L'emboîtement fractal : appareils × assemblages de sorties
ouvrir la planche en plein écran → · 35 pièces · 13 traverses · 15 marges
Les deux bouts sont bâtis — 7 sorties fermées et gardées au serveur, 6 moteurs et 6 afficheurs au client — mais le MILIEU n'existe que sur UNE page : le seul choisisseur de sortie n'est dans aucun des deux tableaux du chargeur central, l'attestation de l'appareil arrive au noyau APRÈS que la branche de compilation soit déjà choisie, et les deux moitiés du joint appareil→assemblage ne se rencontrent sur AUCUNE page.
Ce que cette collecte N'A PAS pu voir. (1) LE RUNTIME : tout est mesuré sur le commit 8addf1c9481559a8e9dbc97b1fc0bcc85e10a0e1 et sur l'arbre de travail, jamais sur un navigateur ouvert. Je n'ai chargé aucune page, donc je n'ai pas vu un seul `window.ViewModeManager` réel, aucun appel HTTP, aucune projection compilée. « Chargé » signifie ici « présent dans un tableau de scripts ou une balise <script> », pas « exécuté sans erreur ». (2) LA PRODUCTION : je n'ai pas interrogé le VPS DigitalOcean (138.197.132.63) ni la base atom_db. Je ne sais donc pas combien d'appareils sont réellement enregistrés dans le registre, ni si `scope_membership` / `projection_nodes` contiennent une seule ligne, ni quels routeurs le processus prod a réellement montés (`register_router` avale l'ImportError, et les listes `_registered_ok` / `_registered_broken` ne vivent qu'en mémoire du processus). L'importabilité des 5 routeurs est mesurée dans backend/.venv-tests, en local. (3) LE DEUXIÈME ARBRE : mes grep ont bien couvert `backend/app/` ET les ~278 .py hors `app/` (le motif `-- backend` les prend tous les deux), mais je n'ai PAS fouillé `archives/`, `transit/` ni `AT-OM-999-DEPLOY-ZAMA-ALLELUYA/` — un appelant historique y vivrait sans que je le voie, et ce serait un appelant mort de toute façon. (4) LES BALISES DYNAMIQUES : je n'ai cherché les chargements que dans governance-init.js et dans les balises `<script src>` statiques des .html. Un module injecté par un autre chargeur JS (window-manager, module-orchestrator, un import dynamique) m'échapperait : mes comptes « 0 / N pages » sont donc des MINORANTS de chargement, et c'est dans ce sens-là qu'ils peuvent être faux. (5) LE COMPTE DES VALEURS `render_layer` dépend de la forme cherchée : ma règle ne voit que les littéraux `render_layer = \"x\"` / `render_layer: 'x'` ; une valeur construite, lue en base ou passée par variable n'y figure pas. (6) LES SORTIES `2.5d` ET `sonore` : je conclus ABSENT sur l'absence de moteur dans le noyau de projection ; je n'ai pas cherché un organe sonore ailleurs dans le dépôt (bioacoustic, audio_generation existent et n'ont pas été examinés pour cette question).
ne pas dessiner
| device_registry (POST /api/v2/devices/register) alimente | → | device-master.js (_registryState)backend/app/routers/device_registry.py:658 → frontend/js/device-master.js:410-411, enregistrement auto :1549-1552 | |
| device-master.js (getDeviceProfile) alimente | → | ViewModeManager (_getDeviceCapabilities)frontend/js/device-master.js:1570-1590 → frontend/js/view-mode-manager.js:823-862 — mais governance-init.js:95 ne charge device-master que sur institutions.html, et view-mode-manager n'est dans aucun tableau : intersection de pages = 0 | |
| device-master.js (getDeviceProfile) alimente | → | atom-projection-kernel (device_render_ceiling)frontend/js/atom-projection-kernel.js:92-113, appelée à :1326 — APRÈS le choix de branche à :1286-1303 : le plafond annote, il ne décide pas | |
| ViewModeManager.selectMedium appelle | → | atom-projection-studio (_resolveMedium)frontend/js/atom-projection-studio.js:695-718 — appel conditionnel à `global.ViewModeManager`, absent du chargeur central ; le repli déclaré est `defaut_sans_selecteur` → meshmap (:719-722) | |
| select du panneau studio appelle | → | atom-projection-kernel (compile*)frontend/js/atom-projection-studio.js:1275-1280 → :686-693 → :956 → noyau :1286-1303 ; monté seulement là où existe #projection-studio-root : frontend/design-center.html, 1 page sur 215 | |
| nav-state (position dérivée) autorise | → | medium de la requête studiofrontend/js/atom-projection-studio.js:966-971 puis :1570-1572 — quand un focus est dérivé, `request.medium` est FORCÉ à 'meshmap' et le choix explicite de l'opérateur est écrasé ; nav-state-machine.js n'est chargé que dans le tableau FULL (governance-init.js:293), donc pas sur design-center | |
| atom-projection-kernel alimente | → | les six afficheurstopic `projection.compile.completed` publié à frontend/js/atom-projection-kernel.js:1356 ; abonnés : mirror-earth.js:626, projection-2d-window.js:98, projection-text-window.js:163, scene-viewer-3d.js:509, xr-layer.js:1238 — 2 des 6 hors du tableau LIGHT, 1 hors des deux | |
| visual-layer-composer (MEDIUM_PRESET_MAP) appelle | → | renderers de calquesfrontend/js/visual-layer-composer.js:184 via RENDERER_COMMAND_TOPICS:65-67 — 1 fil (geo) pour 5 calques | |
| arbre-spheres (S6_PACKAGING_LAYER / render_plan) alimente | → | ViewModeManager (_wireFruitRenderPlan)frontend/js/arbre-spheres.js:693-711 → frontend/js/view-mode-manager.js:320-330 — consommateur non chargé | |
| nested_window_fractal.RenderLayer autorise | → | trinity_geo_router (garde des 7 sorties)hf-atom-tools/atom_canon/primitives/nested_window_fractal.py:20-29 → backend/app/routers/trinity_geo_router.py:53-58, :123-134 ; import canon re-vérifié OK dans backend/.venv-tests | |
| FractalAddress (plafond 12) contient | → | NestedWindowFractal (depth)hf-atom-tools/atom_canon/primitives/nested_window_fractal.py:44-51 — la profondeur est héritée et bornée, mais la classe qui l'hérite n'a aucun appelant | |
| device_taxonomy (RENDER_OUTPUTS) alimente | → | les services backend1 seul consommateur des SORTIES : backend/app/routers/device_registry.py:36-42 ; les 4 autres importateurs (atom_package_vocab.py:17, continuity_engine.py:41, device_capability_registry.py:43, runtime_adapter_registry.py:47) n'importent que RUNTIME_FAMILY_VALUES | |
| fractale_communautaire (/api/v2/fractale) alimente | → | un clientbackend/app/routers/fractale_communautaire.py:79 monté main.py:2007 ; 0 appelant hors docs/tests/scripts de déploiement |
| 1 | Noyau de projection — SIX moteurs de compilation6 méthodes compile* — règle : `git show HEAD:frontend/js/atom-projection-kernel.js | grep -n '^ compile[A-Za-z0-9]*:'`, 6 lignesfrontend/js/atom-projection-kernel.js:1385 (compileMeshMap), :1449 (compileGeoMirror), :1507 (compileText), :1558 (compileVillage2D), :1586 (compileScene3D), :1638 (compileXR) · confirmé dans le code | |
| 2 | Le noyau est dans LES DEUX tableaux du chargeur central109 pages sur 215 chargent governance-init.js (règle : `git grep -l governance-init.js -- 'frontend/*.html' | wc -l`, fichiers suivis par git)frontend/js/governance-init.js:474 (tableau FULL) et :1164 (tableau LIGHT) · confirmé dans le code | |
| 3 | compileMeshMap — branché, et HORS du vocabulaire fermé du serveur`meshmap` ∉ RENDER_OUTPUTS (7 valeurs : text, 2d, 2.5d, 3d, xr, geo, sonore — re-mesuré par appel)frontend/js/atom-projection-kernel.js:1385 ; demandeurs : frontend/js/environment-projection-door.js:97,226 · frontend/js/hitl-panel.js:627 · frontend/js/atom-projection-studio.js:720 (défaut) ; absence côté serveur : backend/app/core/device_taxonomy.py:62-70 · confirmé dans le code | |
| 4 | compileGeoMirror — BÂTI ET APPELÉ (la fiche le disait dormant : FAUX)3 demandeurs `medium: 'geo'` hors noyau et hors tests (règle : `git grep -n "medium: 'geo'" -- frontend/js`, moins le noyau, moins __tests__)frontend/js/atom-projection-kernel.js:1449 ; demandeurs : frontend/js/mirror-earth.js:547 · frontend/js/projection-spine-bridge.js:355 · frontend/js/temple-flow-bridge.js:436 · confirmé dans le code | |
| 5 | compileScene3D — branché, et atteint par deux portes réelles2 demandeurs `medium: '3d'` hors noyau/tests ; 2 pages où demandeur ET afficheur coexistent (creation.html, meshmap.html)frontend/js/atom-projection-kernel.js:1586 ; demandeurs : frontend/js/env-customizer.js:926 (creation.html) · frontend/js/environment-projection-door.js:339 (creation.html, meshmap.html) ; afficheur frontend/js/scene-viewer-3d.js:509 (chargé governance-init.js:477 et :1167) · confirmé dans le code | |
| 6 | RENDER_OUTPUTS — le vocabulaire FERMÉ du serveur, validé à l'import7 sorties — re-mesuré par appel : `len(RENDER_OUTPUTS) == 7`, ('text','2d','2.5d','3d','xr','geo','sonore')backend/app/core/device_taxonomy.py:62-70 ; garde à l'import :232-238 (RuntimeError si une sortie sort de l'énumération) · confirmé dans le code | |
| 7 | Les 17 types d'appareil et leurs sorties maximales17 types — re-mesuré par appel : `len(DEVICE_TYPE_VALUES) == 17`backend/app/core/device_taxonomy.py:34-57 (DeviceType), :98-140 (DEVICE_TYPE_DEFINITIONS), garde d'unicité :230-231 · confirmé dans le code | |
| 8 | L'honnêteté de la taxonomie — 9 types refusent d'inventer une sortie9 types à sorties vides — re-mesuré par appel : drone, sensor, robot, iot, vehicle, gateway, camera_360, seed_key, energy_node ; chacun porte son `no_runtime_reason`backend/app/core/device_taxonomy.py:96 (_NO_SCREEN), :101-140 · confirmé dans le code | |
| 9 | Le registre d'appareils — importable et enregistré10 routes — mesuré par import réel dans backend/.venv-tests (`import app.routers.device_registry` → len(router.routes)==10)backend/app/routers/device_registry.py:36-42 (seul consommateur backend des sorties), prefix /api/v2/devices :46-48 ; montage backend/app/main.py:2548 · confirmé dans le code | |
| 10 | FractalAddress — la profondeur, bornée et qui refuseplafond 12 ; 2 appelants de production hors tests/docs (règle : `git grep -ln 'fractal_address import'` moins docs/, moins tests/)hf-atom-tools/atom_canon/primitives/fractal_address.py:20 (MAX_FRACTAL_DEPTH = 12), :32 (FractalDepthError), :130-133 (le refus) ; appelants de production : backend/app/services/trinity_geo/locator.py et backend/app/services/bioacoustic/fractalizer.py · confirmé dans le code | |
| 11 | Le répartiteur du noyau — 5 media nommés, le 6e est le DÉFAUT5 `if` nommés (geo, 2d, 3d, xr, text) + 1 `else` → compileMeshMapfrontend/js/atom-projection-kernel.js:1286-1303 · confirmé dans le code`meshmap` n'est jamais nommé : tout medium inconnu (dom, uefn, cymatique, sonore, 2.5d) reçoit une meshmap sans refus ni trace. Le commentaire :1297-1299 le reconnaît et laisse le geste à plus tard. | |
| 12 | compileText — bâti de bout en bout, et STRUCTURELLEMENT INATTEIGNABLE8 des 17 types déclarent `text` ; 0 des 8 déclare `text` SANS `2d` (re-mesuré par appel sur DEVICE_TYPE_DEFINITIONS)frontend/js/atom-projection-kernel.js:1507 ; afficheur frontend/js/projection-text-window.js:163 ; échelle frontend/js/view-mode-manager.js:951-958 ; taxonomie backend/app/core/device_taxonomy.py:98-140 · confirmé dans le codeDeux verrous, et je les ai vérifiés moi-même. (a) `_deviceMediumCeiling` teste `outputs.includes('2d')` AVANT `outputs.includes('text')` (view-mode-manager.js:951 puis :958) : comme AUCUN type canon ne porte `text` sans porter `2d`, la ligne `return 'text'` est morte pour les 17 types. (b) Le select du studio n'offre pas `text` (atom-projection-studio.js:1275-1280 : auto, meshmap, geo, 2d, 3d, xr). Aucun des deux chemins ne peut produire `text`. | |
| 13 | compileVillage2D — bâti, afficheur bâti, UN SEUL demandeur : un select sur une page0 demandeur en code (`medium: '2d'` littéral hors noyau/tests = 0) ; 1 demandeur par geste humain (option du select) sur 1 page sur 215frontend/js/atom-projection-kernel.js:1558 ; afficheur frontend/js/projection-2d-window.js:98 (chargé governance-init.js:475 et :1165) ; demandeur frontend/js/atom-projection-studio.js:1278 → :686-693 · confirmé dans le codeLa fiche disait « zéro demandeur » : c'est trop fort. L'option `2d` EXISTE dans le panneau et traverse `_resolveMedium` (medium_source='panel_explicit'). Mais le panneau ne se monte que là où vit `#projection-studio-root` — `frontend/design-center.html`, SEULE page du dépôt (règle : `git grep -l projection-studio-root -- 'frontend/*.html'` → 1). Aucun code ne demande jamais `2d`. | |
| 14 | compileXR — bâti, afficheur bâti, UN SEUL demandeur : un select sur une page0 demandeur en code ; 1 option de select sur design-center.html — qui est une page LIGHT, donc xr-layer.js n'y est PAS chargéfrontend/js/atom-projection-kernel.js:1638 ; afficheur frontend/js/xr-layer.js:1238 (chargé governance-init.js:913, tableau FULL SEUL) ; demandeur frontend/js/atom-projection-studio.js:1280 · confirmé dans le codePire que « zéro demandeur » : le seul demandeur et le seul afficheur sont sur des pages DISJOINTES. `design-center` n'est pas dans GOVERNANCE_PAGES (governance-init.js:51-65, 27 pages) → tableau LIGHT → `xr-layer.js` absent. Demander `xr` depuis le studio compile une projection que rien n'affiche sur cette page. | |
| 15 | RenderLayer canon — la MÊME énumération, mais importée dans un try/except7 valeurs identiques aux 7 de RENDER_OUTPUTS — re-mesuré par appel dans backend/.venv-tests : l'import canon RÉUSSIT et rend exactement ('text','2d','2.5d','3d','xr','geo','sonore')hf-atom-tools/atom_canon/primitives/nested_window_fractal.py:20-29 ; import backend/app/routers/trinity_geo_router.py:53-58 · confirmé dans le codeLa fiche disait « en autorité canon-aware ». L'import est enveloppé d'un `except Exception` qui retombe sur un CLONE LITTÉRAL des sept valeurs (trinity_geo_router.py:58). Les deux listes sont aujourd'hui égales — mais AUCUN test ne les compare (règle : `git grep -rn RENDER_OUTPUTS -- backend/tests hf-atom-tools` → 2 occurrences, toutes deux internes à device_taxonomy). Trois copies du même vocabulaire peuvent diverger en silence. | |
| 16 | ⚑ LE JOINT appareil → assemblage — les deux moitiés existent, elles ne se rencontrent sur AUCUNE pagedevice-master.js : 1 page (institutions) · view-mode-manager.js : 3 pages (desktop, meshmap, simulation-dashboard) · intersection : 0serveur : backend/app/routers/device_registry.py:658 (rend possible_render_outputs) · client-émetteur : frontend/js/device-master.js:1549-1552 (enregistrement AUTO au chargement), :1570-1590 (getDeviceProfile pose le plafond) · client-consommateur : frontend/js/view-mode-manager.js:823-862, :925-960 · chargement : governance-init.js:95 (device-master.js, SPHERE_MODULE_MAP['institutions'] UNIQUEMENT) · confirmé dans le codeLA CORRECTION LA PLUS LOURDE DE CETTE PASSE. La fiche annonçait « BÂTI DE BOUT EN BOUT ». Mesuré : `device-master.js` n'apparaît qu'UNE fois dans governance-init.js, à la ligne 95, dans l'entrée `'institutions'` de SPHERE_MODULE_MAP — il ne se charge donc que sur institutions.html. `view-mode-manager.js` n'est dans AUCUN des deux tableaux de scripts ; il n'arrive que par balise directe sur desktop.html, meshmap.html, simulation-dashboard.html. AUCUNE page ne porte les deux. Le plafond attesté est produit là où personne ne choisit, et le choisisseur vit là où aucun plafond n'arrive. | |
| 17 | ⚑ L'attestation de l'appareil arrive au noyau APRÈS le choix de la branche1 appelant, à la ligne 1326 — soit 23 lignes APRÈS le `if/else if/else` qui a déjà choisi le moteurfrontend/js/atom-projection-kernel.js:92-113 (_requestWithConfirmedDeviceRenderCeiling), appelée une seule fois à :1326 ; branche de compilation choisie à :1286-1303 · confirmé dans le codeLe noyau SAIT lire le plafond serveur et ne s'en sert pas pour choisir. Son propre commentaire le dit (:101-102) : « Le plafond qualifie seulement la lecture graphique ». C'est le second trou du joint, et il est indépendant du premier : même si device-master et un choisisseur se trouvaient un jour sur la même page, le noyau continuerait d'annoter sans décider. | |
| 18 | ⚑⚑⚑ LE CHOISISSEUR — ViewModeManager, absent des DEUX tableaux du chargeur central0 occurrence de `/js/view-mode-manager.js` dans les tableaux `scripts` ; 3 pages sur 215 le chargent par balise directefrontend/js/view-mode-manager.js:24 (objet), :293-310 (selectMedium), :1147 et :1150 (exposition globale) ; governance-init.js:1389 — 'view-mode-manager' n'y figure QUE dans TIER3_PATTERNS (une liste de CLASSEMENT par étage, pas de chargement : matchesTier :1433-1436 dérive le nom d'un script DÉJÀ présent dans le tableau) · confirmé dans le codeLe piège est le nom dans TIER3_PATTERNS : il donne l'illusion d'un chargement. Il ne fait que dire « si ce script est chargé, défère-le ». Le module qui décide quelle sortie l'appareil reçoit n'est atteint par le chargeur central sur AUCUNE page. ⚑ La fiche disait « 3 des 166 pages » : je ne reproduis pas 166. Mesure : 215 fichiers .html suivis par git sous frontend/, 109 chargent governance-init.js, 27 sont des GOVERNANCE_PAGES (governance-init.js:51-65). | |
| 19 | Le composeur d'assemblage — MEDIUM_PRESET_MAP5 clés (meshmap, geo, 2d, 3d, xr) pour 7 sorties canon — `text`, `2.5d` et `sonore` sont absentsfrontend/js/visual-layer-composer.js:80-86 (la table), :303 (`MEDIUM_PRESET_MAP[normalized] || 'explorer'`) ; chargé governance-init.js:466 et :1156 · confirmé dans le codeUne sortie hors table ne provoque aucun refus : elle reçoit `explorer` (geo + pings). Un appareil texte se verrait donc composer des calques géographiques. Le repli par défaut déguise l'absence en succès. | |
| 20 | RENDERER_COMMAND_TOPICS — 5 calques déclarés, 1 fil vers un renderer5 calques nommés dans PRESETS (geo, pings, semi-xr, xr-full, gaming) · 1 topic de commande (geo)frontend/js/visual-layer-composer.js:65-67 (la table : une seule entrée 'geo'), :69-76 (PRESETS nomment 5 calques), :184 (`RENDERER_COMMAND_TOPICS[layerId]`) · confirmé dans le code4 calques sur 5 s'activent dans l'état du composeur sans qu'aucune commande ne parte vers un renderer. Le commentaire du code l'assume (:63-64 : « Une preference active n'est pas une preuve qu'un renderer existe »). | |
| 21 | S6_PACKAGING_LAYER — l'assemblage par BRANCHE, 14 renderers déclarés14 renderers déclarés ; 14/14 fichiers existent ; 3/14 seulement sont chargés par governance-init.js (atom-encyclopedia-view, env-renderer-village [page 'desktop' seule], scene-viewer-3d)frontend/js/arbre-spheres.js:732-757 (le registre), :693 (sélection du renderer), :1641 et :1775 (exposition) · confirmé dans le code11 des 14 renderers déclarés n'ont AUCUNE entrée dans les tableaux de scripts : battlefield-view, chronoscope-renderer, dreamcatcher-renderer, env-renderer, isometric-renderer, lys-mirror-renderer, narrative-notes, provenance-viewer, sankey-renderer, world-renderer — et `view-mode-manager`, qui y est pourtant déclaré « orchestrator / router S6 ». Le registre nomme son propre routeur, et ce routeur n'est pas chargé. | |
| 22 | La branche xr/3d de la sélection de renderer — inatteignable par le chemin automatique4 marches de repli, dont 1 (`dom`) hors des 7 sorties canon ; `text`, `geo`, `meshmap`, `2.5d`, `sonore` absents de l'échellefrontend/js/view-mode-manager.js:311-317 (fallbackMedium, échelle ['xr','3d','2d','dom']) · confirmé dans le codeLe module qui porte cette sélection n'est de toute façon pas chargé centralement (voir LE CHOISISSEUR). La branche existe ; rien ne l'atteint par un chemin automatique. | |
| 23 | ⚑⚑⚑ NestedWindowFractal — LA primitive d'emboîtement fenêtre-dans-fenêtre, orpheline0 appelant de `add_child` / `children_ids` — règle : `git grep -rn 'NestedWindowFractal\|nested_window_fractal'` sur TOUT le dépôt (donc les DEUX arbres backend : backend/app/ ET les 278 .py hors app/), hors hf-atom-tools/atom_canon/tests → 2 occurrences seulement, et aucune n'est un appel : trinity_geo_router.py:54 importe `RenderLayer` (l'énum, pas la classe) et temple_canonical_extractor.py:807 la cite en commentairehf-atom-tools/atom_canon/primitives/nested_window_fractal.py:32-77 (parent_id, children_ids, add_child, path) · confirmé dans le codeEt le module frontend qui porte presque son nom ne la sauve pas : `frontend/js/fractal-nested-windows.js` (chargé, governance-init.js:485 et :1172) est une charpente FIXE de 3 étages (L1 tronc / L2 feuille / L3 flux) lisant /api/v2/fractal-code — en-tête :3-7. Aucune récursion fenêtre-dans-fenêtre. La seule primitive récursive du dépôt reste sans appelant ; sa propriété `path` (:52-57) ne rend d'ailleurs que 2 maillons. | |
| 24 | render_layer — le champ PAR NŒUD, chaîne libre12 valeurs littérales distinctes en circulation — MA mesure, avec sa règle : `git grep -ohE "render_layer[\"']?\s*[:=]\s*[\"'][A-Za-z0-9_.-]+[\"']" -- backend frontend/js hf-atom-tools agents`, hors __tests__ → geo(18), 3d(7), 2d(7), meshmap(5), data(4), GEO_DUAL_MIRROR(4), root(2), geo_voids(2), geo_filaments(2), mesh_core(1), geo_overlay(1), geo_hubs(1)backend/app/models/world_canon_projection.py:57 — `Mapped[str] = mapped_column(Text, nullable=False, server_default=text("'2d'"))` · confirmé dans le codeLa fiche annonçait 13 : je ne le reproduis pas sous ma règle, j'en compte 12 — et la règle d'extraction change le compte, donc ce nombre doit toujours voyager avec elle. Ce qui compte n'est pas 12 ou 13 : c'est que 8 de ces 12 (meshmap, data, root, mesh_core, geo_voids, geo_filaments, geo_overlay, geo_hubs) sortent des 7 sorties canon, et que la colonne n'a NI enum NI CheckConstraint pour les refuser. | |
| 25 | La garde des 7 sorties — côté API, sur une seule porte6 routes importables (mesuré par import réel dans backend/.venv-tests) ; 1 champ gardé : `LocateRequest.render_layer`backend/app/routers/trinity_geo_router.py:123-134 (_sortie_connue, field_validator, refus nommé) ; montage backend/app/main.py:2303 · confirmé dans le codeLa garde existe, elle refuse honnêtement, et elle ne couvre QUE le corps de POST /api/v2/trinity-geo/locate. Le `render_layer` PAR NŒUD de world_canon_projection.py:57 n'est gardé par rien. La même notion est fermée d'un côté de l'API et libre de l'autre. | |
| 26 | QUATRE vocabulaires de sortie, disjoints4 énumérations ; `2d`/`3d`/`xr` sont les 3 SEULES valeurs communes aux quatre ; `meshmap`, `dom`, `uefn`, `pings`, `gaming` n'existent dans aucune autre(1) backend/app/core/device_taxonomy.py:62-70 — 7 valeurs · (2) frontend/js/atom-projection-kernel.js:1286-1303 — 6 media (meshmap, geo, 2d, 3d, xr, text) · (3) frontend/js/view-mode-manager.js:1033 (_mediumRank) — 6 rangs (dom, text, 2d, 3d, xr, uefn) · (4) frontend/js/visual-layer-composer.js:69-76 — 5 calques (geo, pings, semi-xr, xr-full, gaming) · confirmé dans le codeAucune table de correspondance entre les quatre, et aucun test qui les compare. Chaque traversée du joint est une traduction implicite. | |
| 27 | L'écouteur de changement de medium du studio — jette geo et meshmap en silence5 media acceptés ; `geo` et `meshmap` retombent sur un `return` nu — sans recompilation ni refus publiéfrontend/js/atom-projection-studio.js:1554-1579, le filtre à :1566 — `if (['dom','2d','3d','xr','text'].indexOf(rawMedium) === -1) return;` · confirmé dans le codeLe commentaire :1563-1565 reconnaît le trou pour les autres media (« ce silence-là est un geste séparé »). Et l'écouteur ne vaut que pour une requête dont `medium_source` est `view_mode_selected` ou `viewmode_medium_changed` (:1559-1561) — or le choisisseur qui produit ces sources n'est pas chargé. | |
| 28 | La chaîne de repli du medium — ne se replie pas vers le canon4 marches : xr → 3d → 2d → dom ; `dom` ∉ les 7 sorties canonfrontend/js/view-mode-manager.js:311-317 · confirmé dans le codeLe dernier barreau sort du vocabulaire : un appareil qui se replie jusqu'au bout atterrit sur `dom`, qui n'est pas une sortie canon et n'affiche pas le monde. Le commentaire :975-977 dit que ces quatre marches sont FIGÉES par un test — c'est le cas du « test qui fige une dérive et reste vert ». | |
| 29 | Les six afficheurs — tous bâtis, tous filtrants, mais pas tous chargés6 afficheurs · 3 dans LES DEUX tableaux (2d, text, scene-viewer-3d) · 2 dans le tableau FULL seul (mirror-earth, xr-layer → 27 pages) · 1 dans AUCUN tableau (atom-meshmap, 2 pages par balise : design-center.html, meshmap.html)frontend/js/mirror-earth.js:626-631 (geo, filtre `medium !== 'geo'`) · frontend/js/projection-2d-window.js:98 · frontend/js/projection-text-window.js:163 · frontend/js/scene-viewer-3d.js:509 · frontend/js/xr-layer.js:1238 · frontend/js/atom-meshmap.js (abonné via son propre pont, :670) ; chargement : governance-init.js:475, :476, :477, :913, :196 · confirmé dans le codeLa fiche disait BÂTI. Je dégrade : l'afficheur de la sortie PAR DÉFAUT du noyau — `atom-meshmap.js`, celle que reçoit tout medium inconnu — n'est dans aucun des deux tableaux du chargeur. Sur 107 des 109 pages qui chargent governance-init, le noyau peut compiler une meshmap que rien n'affiche. | |
| 30 | La porte d'environnement — bâtie, commitée, hors du chargeur central0 dans les tableaux de scripts · 2 pages sur 215frontend/js/environment-projection-door.js:97, :216, :226, :329, :339 ; 0 occurrence dans governance-init.js ; 2 pages : frontend/creation.html, frontend/meshmap.html · confirmé dans le codeElle porte les deux seuls appels `medium: 'meshmap'` et `medium: '3d'` faits par du CODE (et non par un select). Hors de ces 2 pages, ces deux portes n'existent pas. | |
| 31 | La porte REST de la fractale communautaire — montée, et personne ne s'y présente6 routes importables (mesuré par import réel dans backend/.venv-tests) · 0 appelant client — règle : `git grep -rn 'api/v2/fractale'` sur TOUT le dépôt, hors docs/, hors tests, hors frontend/content : il ne reste que la déclaration du préfixe, un script de déploiement (deploy/deploy-from-archive.sh:92, qui teste un 404) et des index de cartographiebackend/app/routers/fractale_communautaire.py:79 (prefix /api/v2/fractale), :193, :250, :279, :330, :406, :426 ; montage backend/app/main.py:2007 · confirmé dans le codeLa fiche disait BÂTI. L'organe est là, il est atteignable — mais aucune page ni aucun module ne l'appelle. `GET /api/v2/fractale/grille-27` et `/communaute/{id}/tronc` sont la seule porte REST de l'emboîtement communautaire, et elle n'a pas de client. | |
| 32 | Le plan de rendu des fruits — la jonction branche → sortie1 émetteur, 1 consommateur, 0 page où les deux sont chargés par le chargeur centralémetteur frontend/js/arbre-spheres.js:693-711 (topic `arbre.fruits.render_plan.updated`) ; consommateur frontend/js/view-mode-manager.js:320-330 (_wireFruitRenderPlan) · confirmé dans le codeLe seul consommateur du plan de rendu des fruits vit dans le module non chargé. Le plan est publié dans le vide. | |
| 33 | Le montage des routeurs — une DÉCLARATION, que j'ai dû vérifier autrement5 routeurs re-vérifiés par import réel dans backend/.venv-tests : device_registry 10 routes · device_capability_router 9 · scene_renderer 10 · fractale_communautaire 6 · trinity_geo_router 6 — tous importent sans erreurbackend/app/main.py, fonction register_router : `except ImportError` qui journalise et CONTINUE, sauf si `core=True` ou `REGISTER_ROUTER_STRICT` ; aucun des routeurs de cette planche n'est déclaré `core=True` (main.py:1839, 1871, 2007, 2303, 2548) · confirmé dans le code« Monté dans main.py » ne prouve rien par soi-même : l'ImportError est avalée. J'ai donc mesuré l'importabilité moi-même — dans l'interpréteur LOCAL backend/.venv-tests, PAS dans le conteneur de production. Ce que je n'ai pas vu : l'état réel du processus en prod. | |
| 34 | Moteur de la sortie `2.5d`1 sortie canon déclarée, 0 moteur, 0 afficheurbackend/app/core/device_taxonomy.py:64 (la sortie est déclarée) ; aucune méthode `compile*` correspondante dans frontend/js/atom-projection-kernel.js (6 compile*, aucune 2.5d) · confirmé dans le code | |
| 35 | Moteur de la sortie `sonore`1 sortie canon déclarée (portée par 8 types d'appareil), 0 moteurbackend/app/core/device_taxonomy.py:68 ; hf-atom-tools/atom_canon/primitives/nested_window_fractal.py:28 ; aucun moteur dans le noyau · 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'emboîtement fractal : appareils × assemblages de sorties ». 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.