Asymetrie Fondateur / Marchand dans le Studio
Audit commande, hors rotation hebdomadaire. Semaine du 2026-09-15. Piliers couverts : design-system et ai-platform en premier chef, growth-web et data-platform en consequence.
Audit commande, hors rotation hebdomadaire. Semaine du 2026-09-15. Piliers couverts :
design-systemetai-platformen premier chef,growth-webetdata-platformen consequence.
Périmètre
Commit mesure : 43e2e3ca17d33152dd283502709e805fe0649491 (origin/main).
Tous les chiffres de cette page sont derives d'un worktree detache sur
ce commit, jamais de l'arbre de travail : un autre agent modifie en ce
moment src/features/studio/**, src/components/studio/** et
src/lib/studio/**.
Revu : les deux montages du module Studio
(src/features/studio/creative-os-access.ts,
creative-os.ts), les 28
fichiers de src/components/studio/,
le registre d'outils
(src/features/ai/tools/), le catalogue
du canvas
(workflow-capabilities.ts),
le catalogue MCP
(mcp-scopes.ts), les onze
boards du siege
(src/features/studio/ops-boards/),
et les quatre moteurs nommes.
Non revu, volontairement : la resolution du tenant Fondateur. Elle est tranchee par l'ADR 0026 et son implementation est en vol. Aucun item de cette page ne la refait ; plusieurs s'appuient dessus et le disent.
Non mesurable depuis ce depot, et c'est ecrit plutot que devine : ce que
INTERNAL_ORG_SLUGS vaut en production. La variable est lue cote
serveur (internal-pricing.ts:41),
son defaut est ""
(src/env/server.ts:634), donc un clone ne
peut pas savoir si une organisation de plateforme est designee.
La table d'ecart
Une capacite par ligne, et pour chacune ce que le montage MARCHAND
(storeStudioHost, le mode studio de la scene du store) peut, contre
ce que le montage FONDATEUR (openInternalCreativeOs,
/ops/creative/studio) peut.
| Capacite | Fichier | Montage marchand | Montage Fondateur | Ecart |
|---|---|---|---|---|
| Composer, mode Image | actions.ts:230 | rend vraiment, ligne GenerationRequest, debit ledger | identique | aucun |
| Composer, mode Video | gallery-context.tsx:326 | clip de demo groupe, rien de facture | identique | aucun |
| Composer, mode Nova | idem | clip de demo | identique | aucun |
| Composer, mode Replace | idem | clip de demo | identique | aucun |
| Edition (Upscale, Variation) | actions.ts:258 | image-vers-image reel | identique | aucun |
| Galerie | creative-os.ts galleryItemsFor | listStoreGalleryRows(storeId) | identique | aucun |
| Références | studio-references.ts | scope stores/<id>/ | identique | aucun |
| Production (6 blocs) | buildStudioProduction | blocs filtres par studio.* | identique | aucun |
| Couts affiches | composerCosts | credits (retail) | dollars (internal) si l'org est designee | derive de l'ORG, pas du montage |
| Grille de prix, abonnement, profil | pricing-plans.tsx, subscription-content.tsx, profile-content.tsx | rendus | rendus aussi, checkout a null | aucun, sauf un CTA mort en moins |
| Avatar / identite | studio.tsx:85 | ecran « rien n'est construit » | identique | aucun |
| Academy | academyForOperator | liste vide, ligne absente du rail | corpus content/handbook/ | rail |
| Platform System | platformSystemFor | appele aussi (vide sans mandat) | rempli | rail |
| Brand System | brandSystemFor | 9 entrees | 9 entrees des qu'une marque est choisie | aucun |
| Selecteur de marque | retire. Le siege ouvre la marque designee (founder-tenant.ts) | brands: [], composant rend null | liste des marques atteintes | rail |
| Les 11 boards du siege | ops-boards/index.ts | inatteignables sans mandat | 11 boards en lecture | rail |
| Remotion, ElevenLabs, Postiz, Datafast | cf. §2 | inatteignables | inatteignables aussi depuis le cockpit | aucun |
Ce que la table prouve
Le module fait 5519 lignes sur 28 fichiers
(wc -l src/components/studio/*.ts*). Le nombre de lignes de ce module
qui se comportent differemment selon le montage est quatre, et les
voici toutes :
| Fichier, ligne | Ce qui differe |
|---|---|
studio-sidebar.tsx:106 | host.academy.length decide si la ligne Academy existe |
data.tsx:124 | links.operator decide si la ligne Platform System existe |
system-content.tsx:106 | quelle des deux Systems est rendue |
founder-tenant.ts | le selecteur n'est plus monte. Sans marque designee, le siege ne produit pas |
Les quatre vivent dans le RAIL ou dans ce que le rail ouvre. Aucun
fichier du composer, de la galerie, de la modale de detail, de la
production, du prix, du profil ou de l'abonnement ne lit links.operator,
scope.brands ni academy. Le constat est donc exact
au sens litteral : la seule chose qui differe est la sidebar.
Et l'asymetrie n'est meme pas propre dans ce sens-la :
storeStudioHost appelle platformSystemFor(who.id)
(creative-os-access.ts),
donc un fondateur qui ouvre le cockpit d'une boutique CLIENTE y voit sa
Platform System. C'est exactement la confusion que l'ADR 0026 §Contexte
nomme au point 3 : le siege est devenu un outil pour operer la boutique
d'un utilisateur, et ici il s'invite dans son cockpit.
1. Ce que chaque montage peut, en detail
1.1 Le composer produit une chose sur quatre
generateStudioImage est la seule generation reelle du module. Le
commentaire de
actions.ts:225 le dit
lui-meme : « Video/Nova modes stay on the bundled demo clip ». Le
chemin est ecrit dans
gallery-context.tsx:326 :
un setTimeout, puis DEMO_RESULT.videoSrc =
/gallery/landscape-video-1.mp4, et « Nothing is charged for a demo
clip ».
Trois des quatre onglets du composer sont donc une maquette, des deux cotes. Un fondateur qui ouvre son siege pour produire une video de lancement obtient le meme mp4 groupe qu'un marchand.
Pendant ce temps le registre d'outils porte un vrai generateVideo
(handler-tools-build.ts:1353),
qui ouvre sa ligne de journal et facture. Il n'est atteignable que par
le chat.
1.2 Le cockpit lit onze surfaces et n'en opere aucune
Les onze boards de
ops-boards/ portent chacun un
champ action qui est un href sortant :
/ops/creative/qc, /ops/creative/generate, /ops/creative/library,
/ops/creative/cockpit, /ops/creative/pipeline, /ops/creative/clients,
/ops/creative/concepts, /ops/growth, /ops/content, /ops/bulletin,
/ops/bulletin/health.
Le docblock de
media.ts l'assume mot
pour mot : « Le geste reste sur la page, que l'action nomme ». C'est
une decision explicite et lisible, pas un oubli. Mais additionnee au
reste, elle produit le resultat que le proprietaire decrit : le cockpit
Fondateur est une SALLE DE LECTURE dont toutes les portes sortent, et
tout ce qu'on peut y FAIRE est ce qu'un marchand peut faire.
2. Les quatre moteurs, et ou ils vivent
Derive par grep des importeurs, au commit.
| Moteur | Module | Importeurs hors de lui-meme | Atteignable depuis le cockpit ? | Le composer le connait ? |
|---|---|---|---|---|
| Remotion | services/creative/render-dispatch.ts | 7 : growth/creative-render.ts, ops/content/page.tsx, ops/content/_actions/index.ts, ops/creative/_actions/generate.ts, ops/creative/generate/page.tsx, ops-boards/creative.ts (type + lecture) | non : le board ops-generate le LIT, son action sort vers /ops/creative/generate | non |
| ElevenLabs | services/creative/voiceover.ts | 3 : ops/content/page.tsx, ops/content/_actions/index.ts, ops-boards/media.ts | non : readVoiceoverQuota + voiceoverReadiness sont lus par le board, synthesizeVoiceover n'est appele que par l'action de /ops/content | non |
| Postiz | services/growth/postiz.ts | 10 fichiers, dont 5 sous ops/growth et ops/content | non : isPostizConfigured + listPostizIntegrations dans le board, la publication reste sur la page | non |
| Datafast | lib/datafast-api.ts | lu par ops-boards/media.ts (datafastBlock, partage par les deux boards media) | lecture seule, et c'est correct : Datafast mesure, il ne produit pas | sans objet |
Reponse nette : aucun des trois moteurs de PRODUCTION n'est atteignable
depuis le cockpit, et le composer n'en connait aucun. Le composer
connait une chose, runStudioImageGeneration via
actions.ts:37.
Le catalogue Remotion vaut la peine d'etre chiffre :
templates.json declare
10 templates et 6 formats. Zero sont offerts dans le composer, qui
offre 4 modes dont 1 fonctionne.
Le commentaire de creative-os-access.ts sur le lien growth du rail
Fondateur decrit la situation exactement : « c'est la que les trois
moteurs retenus se rejoignent deja. Un lien, pas
une copie. » Un lien qui sort du cockpit est precisement ce que
design-system/2799 disait vouloir supprimer.
3. Ce que l'ADR 0024 §1 promet, et ce qui en est fait
Fait
La famille studio-media existe dans le registre.
src/features/ai/tools/studio-media-tools.ts:72
declare les sept noms exactement comme l'ADR les nomme :
generateImage, composeProductImage, generateVector,
generateVideo, saveStudioAsset, planCreativeVariants,
saveCreativeConcept. Elle est enregistree dans TOOL_FAMILIES
(index.ts:178), etape
studio, couche connected. AtlasToolContext a gagne son champ
ctx.studio (modes, attachedImages), et
studio-media-parity.test.ts
prouve que la famille et la construction par tour rendent le meme
ensemble.
La construction par tour de chat subsiste :
handler-tools-build.ts fait toujours 2518 lignes et
handler-tools-assembly.ts 347. Le parity test en fait un doublon
GARDE plutot qu'une divergence, ce qui est le bon etat transitoire.
Pas fait
Le canvas n'a gagne aucune generation. Dans
workflow-capabilities.ts,
le compte au commit est 7 capacites available et 10 planned.
ai.generate-image est toujours planned (ligne 44), et il n'existe
aucune capacite ai.generate-video, ai.generate-vector,
studio.save-asset ni render.composition. Les sept noms de
STUDIO_MEDIA_TOOL_NAMES n'apparaissent nulle part dans ce fichier.
Le MCP n'a gagne aucune generation.
mcp-scopes.ts:158 porte
toujours boostecom:studio.read, famille native, avec un seul outil,
getStudioSection, en lecture. Aucun scope d'ecriture media n'existe.
Le cockpit /ops n'a gagne aucune generation par derivation. Il a
gagne onze boards de lecture (design-system/2799) et le composer
image, qui est le meme que celui du marchand.
Verdict de section : la tranche 1 de l'ADR 0024 est livree a moitie.
Le rangement est fait, la derivation qui le justifiait ne l'est pas. La
phrase de l'ADR, « le canvas, le MCP, l'API et le cockpit /ops gagnent
la generation par derivation, sans qu'aucune liste ne soit recopiee »,
est encore fausse pour les quatre.
4. La verite produit du tenant Fondateur
L'ADR 0024 §4 : « sa verite produit est facts.md monte comme source de
connaissance de ce store, avec sa garde ».
Ce n'est pas le cas. Le fichier existe, a un seul endroit :
.claude/skills/boostecom-content/references/facts.md, 141 lignes.
Aucun fichier de src/ ne le LIT. Les cinq mentions de facts.md dans
le code sont des commentaires ou des messages d'erreur :
services/growth/plan-import.ts:20: commentaire ;features/growth/copy-rules.ts:28: commentaire ;features/growth/copy-rules.ts:379: lehintd'une regle de copie, qui demande a un humain qu'un chiffre porte un id defacts.mdsans jamais pouvoir le verifier.
Le seul fichier du skill que le code lit vraiment est
plan-2026-q4.json, et par un test
(plan-import.test.ts:252).
Le mecanisme d'accueil, lui, existe depuis longtemps :
Store.knowledgeSources est une colonne JSON du schema
(prisma/schema.prisma:494), editee par
components/shared/store-switcher/settings.tsx
et consommee par @Atlas. Rien ne l'a jamais remplie pour la marque de la
plateforme, pour la raison que l'ADR 0026 explique : jusqu'a lui, il n'y
avait pas de marque de la plateforme a remplir.
Consequence concrete, et c'est la reponse la plus directe au constat : le Studio Fondateur ne sait rien du produit qu'il est cense vendre. Un marchand ouvre son Studio avec son catalogue, son kit de marque et ses concepts valides. Un fondateur ouvre le sien avec la meme page blanche, et les 141 lignes de faits sourcés restent dans un repertoire que seul un agent Claude Code charge.
5. Ce qui a fait deriver
Chronologie derivee de git log origin/main -- src/components/studio src/features/studio src/app/(dashboard)/ops, la plus ancienne d'abord.
| Commit | Item | Ce qu'il a fait, et pourquoi il a fait deriver |
|---|---|---|
e79f04be | aucun | « replace the cross-org creative QC with the internal Studio ». Le siege cesse d'etre une vue inter-organisations et devient une vue d'UNE organisation. Juste en soi, mais c'est le premier pas ou « operer la plateforme » se met a vouloir dire « operer une organisation ». |
5fda163c | security-identity | /ops et les permissions platform.* naissent. Le siege gagne sa frontiere : c'est le bon mecanisme, et il est toujours la. |
415b1c32 | design-system/2796 | La derive principale. 54 fichiers, 5353 insertions. Le prototype v0 est porte « pixel pour pixel » et monte deux fois. Or ce prototype etait une grammaire de MARCHAND : un solde de credits, une grille de prix a trois plans, une page abonnement, un onglet Upscale. Monter cette grammaire telle quelle dans le siege, c'est avoir decide que le fondateur est un client de son propre produit. L'item le dit lui-meme : « rien ne change en UI/UX ». |
9b9c0c7b | design-system/2797 | Le Studio devient un MODE de la scene et les six surfaces quittent /admin/creative. Excellent pour le marchand. Pour le siege, il ajoute links.operator : neuf liens SORTANTS, qui sont depuis la totalite de ce que le fondateur a en plus dans le module. |
6718bcc8 | design-system/2799 | Platform System et Brand System entrent dans le rail. La regle y est : le cockpit est le generateur tout-en-un. Ce qui a ete livre est un index, pas un generateur : deux sections de cartes-liens. |
b3d22680 | : | Les douze surfaces se lisent dans le cockpit. Onze boards, onze action qui sortent. La lecture est rapatriee, le GESTE reste dehors : c'est le moment ou le cockpit devient definitivement une salle de lecture. |
98ded7ae | design-system/2802 | StudioScope.storeId devient nullable pour que le siege s'ouvre sans marque. L'ADR 0026 §Contexte point 2 a deja juge ce commit : il a supprime l'ecran de selection sans corriger sa source, donc on ne peut plus produire du tout cote /ops sans designer une boutique cliente. |
La cause, en une phrase
Les sept pas sont chacun defendables. Ce qui manque a la chaine, c'est qu'aucun ne s'est jamais demande ce que le fondateur peut FAIRE que le marchand ne peut pas. Le module a ete porte depuis une maquette de produit vendu, monte deux fois, puis on a passe trois items a lui ajouter des menus. La sidebar est le seul endroit ou quelqu'un a repondu a la question, et une sidebar ne produit rien.
L'ADR 0024 §4 avait pourtant la bonne formule : ce que le profil Founder
a en plus est du CONTEXTE, pas du code. Mais un contexte doit ETRE
MONTE quelque part pour exister, et les trois porteurs de ce contexte
sont precisement les trois trous mesures ci-dessus : les mandats
platform.* (montes, ils ne donnent que des liens), la lecture du depot
comme verite produit (§4 : pas montee), les canaux Postiz de la
plateforme (§2 : hors du cockpit).
Constats par severite
P0
Aucun. Rien ici ne perd de donnee, ne fuit un scope ni ne facture a
tort. Le scope croise est tenu :
actions.ts:154 resout les
references dans { scope: { storeId } }, et le prefixe Blob est
stores/<storeId>/studio.
P1
- Trois des quatre modes du composer sont une maquette, des deux
cotes (
gallery-context.tsx:326), alors quegenerateVideoexiste et facture dans le registre. →design-system/2822. - Les trois moteurs de production sont hors du cockpit
(§2). Le fondateur ne peut declencher ni un rendu Remotion, ni une
voix, ni un brouillon Postiz sans quitter le cockpit.
→
ai-platform/2823,ai-platform/2824,design-system/2825. facts.mdn'est monte nulle part (§4). Le Studio du fondateur ne connait pas le produit. →ai-platform/2826.- Le montage MARCHAND resout la Platform System
(
creative-os-access.ts,storeStudioHost). Un fondateur voit son siege dans le cockpit d'un client : c'est l'inversion que l'ADR 0026 ferme, reintroduite par une ligne. →design-system/2820.
P2
La tranche 1 de l'ADR 0024 est a moitie livree (§3) : sept outils ranges, zero surface qui en derive.Mesure perimee le jour meme. Verifie le 2026-09-19 : le canvas DERIVE bien les sept capacites (capability-catalogue.ts←describeAtlasTools), l'API/api/workflow/v2/capabilitiesles sert, le noeudcapabilityles execute etthe-studio-runs-what-it-declares.test.tsverifie leur etat depuis leur RISQUE.ai.generate-imageresteplannedet le doit :aiImagen'a pas d'executeur, le chemin qui genere estcapability. Ne reste que le scope MCP d'ECRITURE, qui n'est pas un trou d'implementation mais la decisionintegrations/0714, et dont le travail est suivi parintegrations/2767. →ai-platform/2821, clos sur ce constat.creative/library/reste un second inventaire.generated-assets.tsliste des fichiers Blob sans ligne en base, pendant que le Studio ecrit desGenerationRequest. L'ADR 0024 §Consequences l'avait declare « chemin de transition » : il ne l'est que si quelque chose le termine. →data-platform/2828.- La voix de la plateforme n'atteint pas le composer.
copy-rules.tsencode les regles de copie, le composer Fondateur n'en applique aucune. →growth-web/2827.
Non-constats
Ce qui ressemble a un defaut et n'en est pas. Un prochain auditeur ne doit pas les rouvrir.
-
Le module partage a 99,9% entre les deux montages n'est PAS le defaut. C'est la decision de l'ADR 0024 (« un seul moteur creatif ») et de l'ADR 0023, et elle est juste. Le defaut n'est pas que le noyau soit commun, c'est que rien n'ait ete ajoute au-dessus cote Fondateur. Refactorer vers deux implementations serait la pire reponse possible a ce rapport.
-
Les onze boards en lecture seule avec un
actionsortant ne sont pas une paresse. Le docblock deops-boards/media.tsargumente correctement : un board repond « est-ce que quelque chose m'attend ici ? », une page porte le geste et sa garde serveur. La regle est bonne ; ce qui manque est qu'aucun geste de PRODUCTION n'ait jamais rejoint le composer, ou il aurait sa place. -
La grille de prix rendue dans le montage Fondateur n'est pas un bug.
checkouty estnull(creative-os-access.ts), avec sa raison ecrite : « a CTA that 404s is worse than none ». La section reste atteignable par le rail, ce qui est discutable en ergonomie, pas en correction. -
INTERNAL_ORG_SLUGSvide n'est pas une regression a signaler ici. C'est le defaut d'origine, et l'ADR 0026 §Decision point 3 tranche deja ce qui doit se passer dans ce cas. Cet audit ne rouvre pas la question. -
handler-tools-build.tsconstruit encore les outils media par tour de chat. C'est un doublon, et il est GARDE :studio-media-parity.test.tscompare les deux portes sur chaque combinaison de modes. Un doublon sous garde derivee est une dette acceptable ; le supprimer est un nettoyage, pas une correction de risque. -
Datafast lu et jamais ecrit depuis le cockpit n'est pas un ecart. Datafast mesure. Un moteur de mesure qu'on pourrait « declencher » depuis un composer serait le defaut.
-
Le mode
avatarqui n'ouvre rien est deja traite, correctement :studio.tsx:85rend un etat vide qui DIT ce qui manque, et l'ADR 0024 §6 a deja nomme l'objet (StudioIdentity) et refuse le mot « avatar » comme identifiant moteur. Aucun item n'est ouvert dessus par cet audit : il est en attente de la tranche qui porte le modele.
Sequence de fermeture de l'ecart
Neuf items, dans l'ordre de lancement. Chacun nomme son bloqueur.
| # | Item | Taille | Bloque par |
|---|---|---|---|
| 1 | design-system/2820 | S | : |
| 2 | ai-platform/2821 | L | clos : la derivation etait deja livree, le reste est integrations/0714 |
| 3 | design-system/2822 | L | livre : un seul executeur video, Nova et Replace desactives |
| 4 | ai-platform/2823 | L | livre : capacite du registre ; le reglage de la ligne est platform-ops/2830 |
| 5 | ai-platform/2824 | M | livre : capacite du registre, voix sous le prefixe de sa boutique |
| 6 | design-system/2825 | L | livre : trois gestes, chacun par sa capacite et sa permission |
| 7 | ai-platform/2826 | M | livre : monte comme source de connaissance du tenant designe |
| 8 | growth-web/2827 | M | livre : cadre derive, et fact.unsourced devient une regle |
| 9 | data-platform/2828 | M | livre : le second inventaire a cesse de grossir ; la vue unique est platform-ops/2830 |
Les items 7 et 8 sont independants des six premiers : ils peuvent partir en parallele, sur un autre pilier, des que l'ADR 0026 a pose la marque de la plateforme.
Correction du 2026-09-19 : un item de type decision EST ouvert et
commande une partie de cette sequence — integrations/0714, « un agent
MCP peut-il declencher une generation payante ». La phrase qui suit etait
fausse a l'ecriture ; elle est conservee pour que la correction se lise.
Aucun item de type La seule question qui en
etait une, « qui paie la production interne », a deja ete tranchee et
livree (decision n'est ouvert.billing/0613, archive) : une organisation designee produit au
cout fournisseur.