Audits · septembre 2026Audit du Creative & Growth OS : 18 septembre 2026

Audit du Creative & Growth OS : 18 septembre 2026

Perimetre : tout ce qui, dans ce depot, produit, range, paie, relit, distribue ou mesure une creative, pour la plateforme elle-meme comme pour un store client. Seize sous-systemes lus en parallele par autant de lecteurs…

Perimetre : tout ce qui, dans ce depot, produit, range, paie, relit, distribue ou mesure une creative, pour la plateforme elle-meme comme pour un store client. Seize sous-systemes lus en parallele par autant de lecteurs independants (le tableau « La carte » ci-dessous les enumere, et c'est lui qui fait foi sur le compte), chaque affirmation MISSING / REDUNDANT / SAFE_TO_REMOVE / MISPLACED qui decide du plan contre-verifiee par un sceptique a trois lentilles (autre nom, implementation partielle, preuve fausse), puis une synthese et une critique de completude. La decision qui en sort est l'ADR 0024 ; ce document est la preuve, l'ADR est la regle.

Ce qui a ete trouve, en une phrase

Le depot ne manque pas d'un Studio : il en a deux qui ne se parlent pas (le Studio vendu, sur l'AI Gateway, avec ledger, QC et lineage ; et la production de la plateforme, sur Remotion et ElevenLabs, sans ligne en base ni cout enregistre), et les sept capacites media du premier vivent hors du registre que l'ADR 0023 a fait adopter par le canvas, le MCP et l'API, donc aucune grammaire autre que le chat ne sait generer.

La methode, et ce qu'elle ne couvre pas

  • Codebase first. Aucune affirmation de ce document ne vient du brief ; chacune cite un fichier. Quand un lecteur a dit MISSING, un sceptique a cherche le concept sous un autre nom, sous forme partielle, et a relu la preuve. Les affirmations qui n'ont pas ete contre-verifiees sont marquees comme telles dans la gap analysis : elles sont des constats d'inventaire, pas des verdicts.
  • Les captures de reference ne sont pas dans le depot. Le brief s'appuie sur plus de vingt captures d'un studio generatif du marche ; trois sont decrites textuellement (Replace, Motion, Cinematic > Scenes). La matrice ecran ci-dessous est un squelette construit sur ces descriptions et sur les primitives existantes. La parite d'interaction attend les captures reelles, versionnees dans le depot (elles sont un prerequis nomme, pas un detail).
  • Les moteurs sont ceux du depot, et la liste est fermee. AI Gateway (Vercel), ElevenLabs, Remotion, Playwright (les captures du produit reel), Postiz, Datafast. Le studio generatif dont viennent les captures est une reference d'ergonomie, jamais un fournisseur : rappele le 2026-09-18, « on reproduit, en aucun cas on va l'utiliser ». Une capacite que nos moteurs ne servent pas est nommee et desactivee, pas sous-traitee.
  • Pas de recommandation sur l'argent. Le plan qui inclut la generation video, qui paie la production de la plateforme, le cout de gros reel d'une image, la licence Remotion : chiffres et options sont dans le registre des decisions, jamais tranches ici.

Les deux Studios, mesures

Le Studio vendu (plane B)La plateforme se produit elle-meme (plane A)
Entreele chat, mediaMode dans le menu « + » du composer (composer-plus-menu.tsx) ; une regex sur l'objectif arme aussi les outils quand le toggle est « off » (studio-capabilities.ts)/admin/creative/generate (role ADMIN) et, depuis growth-web/2758, /ops/content (platform.content.operate)
CapacitesgenerateImage, composeProductImage, generateVector, generateVideo, saveStudioAsset, planCreativeVariants, saveCreativeConcept : construites par tour dans handler-tools-build.ts, assemblees dans handler-tools-assembly.ts, hors TOOL_FAMILIESlaunchTemplateRender (render-dispatch.ts) : dix formes × six toiles × quatre fichiers (templates.json), synthesizeVoiceover (voiceover.ts)
MoteursNano Banana Pro et Veo 3.1 Fast sur l'AI Gateway, nommes une fois dans ai-models.ts ; le vecteur est ecrit par le modele, sans moteur imageRemotion sur GitHub Actions (creative-render.yml), ElevenLabs
Asynchronenon : experimental_generateVideo est synchrone en ai@6, polle 180 s dans un tour de 300 s ; un clip plus long est paye et perdu (ai-platform/0377)workflow_dispatch sans identifiant de run rendu, etat relu sur l'API GitHub, aucune ligne en base
FichiersBlob stores/<storeId>/studio/, ou studio/unassigned sans storeBlob creative/library/<template>/<slug>/, creative/voiceover/<slug>/
EnregistrementStudioAsset (storeID, neuf termes North Star, conceptId, variantOfId + variantAxis, generationCostUsd, QC, dropId), best-effort : la ligne n'existe que si le modele appelle saveStudioAssetaucune : « le chemin EST l'enregistrement » (generated-assets.ts)
ArgentcanAffordStudioMedia avant, trackStudioMediaUsage apres, ligne Credit avec providerCost estime (billing.ts) ; generationCostUsd lu d'une Map en memoire qui ne survit pas a une autre instance Vercel, et jamais remplie pour la videorien : minutes de runner et caracteres ElevenLabs hors ledger (billing/0613)
Verite produitcatalogue, kit de marque, concepts valides du storefacts.md de boostecom-content, garde check-plan.mjs
QC, lineage, apprentissagefile QC, variantOf, CreativeLearningaucun
Porteschat seulement ; MCP boostecom:studio.read et REST /studio/[section] en lecturedeux server actions ; aucune porte MCP ni API

Les trois planes de creative-media-os.md §2 tenaient ces deux pipelines a distance par doctrine (« un render A n'ecrit jamais un StudioAsset »). L'ADR 0024 garde l'intention (ne jamais melanger la production de la plateforme et celle d'un client) et change le mecanisme : le scope, pas le pipeline.

La carte, par sous-systeme

Seize lectures. Les fichiers pivots, et ce que chaque sous-systeme decide :

Sous-systemeOu il vitCe qu'il decideCe qu'il ignore
Chat, surface de commandefeatures/ai/chat/runtime/, orchestrator/runtime/handler*.tsquand une capacite media s'arme (resolveStudioCapabilities : le toggle est un indice, une regex sur l'objectif suffit), quel modele, quel niveau d'autonomiequ'un autre appelant puisse generer
Canvas, surface graphefeatures/ai/workflow/v2/, api/workflow/v2/quelles capacites du registre un store peut executer (capability-catalogue.ts, derive), l'etat available / plannedla generation : ai.generate-image est planned, l'executeur n'a pas de branche
Generation mediaorchestrator/runtime/handler-tools-build.ts (2301 lignes), handler-tools-assembly.tsles sept capacites creatives, leurs limites zod, leur prompt compose, leur coutle registre : aucune n'est dans TOOL_FAMILIES
Registre de capacitesfeatures/ai/tools/index.ts, stages.ts, CLAUDE.mdla liste unique que le canvas, le MCP et l'API derivent (ADR 0023), l'etape de chaque famille, le risque de chaque outilla generation, et la garde surfaces-import-their-capabilities que l'ADR 0023 annonce est absente du disque
Assets et lineageprisma (StudioAsset, CreativeConcept, StudioDrop, CreativeLearning), features/studio/boards.tsconcept → asset → variante → drop → apprentissage, la QC, le cout par assetla generation qui l'a produit : ni prompt, ni references, ni parametres, ni run
Bibliothequesservices/creative/generated-assets.ts (Blob nu), admin/creative/library, StudioAssetGridtrois inventaires disjoints, aucun modele communla suppression : studioAsset.delete n'a aucun appelant, un store supprime laisse ses blobs
Remotion, plane Acreative/ (dix primitives, trois compositions, pipeline), services/creative/render-dispatch.ts, creative-render.ymlle rendu deterministe du produit, dix formes × six toiles × quatre fichiersson propre suivi : workflow_dispatch ne rend aucun identifiant de run, rien n'est persiste
Voixservices/creative/voiceover.ts, creative/pipeline/tts.mjsla synthese, le quota, les trois refus avant depensequ'une voix appartienne a quelqu'un : ELEVENLABS_VOICE_ID est une valeur d'environnement pour toute la plateforme
Identite visuellenulle partrientout : aucun modele, aucun type, aucun outil, aucun ecran
Tenancylib/security/ (permissions, platform-permissions, access-grants, tenant-auth, collab-access), features/studio/internal-scope.tsqui est admin plateforme, quelles platform.* un mandat porte, quelle organisation la plateforme opere, que le mandataire n'entre pas cote userun contexte unique : quatre resolveurs d'entitlement, aucun StudioRuntimeContext
Jobsservices/jobs/ (QStash, DLQ, verifier, quota), services/cron/l'asynchrone de la plateforme, les retries, la file mortela generation : aucune ligne ne suit un rendu, et la video est pollee dans le tour
Argentorchestrator/runtime/billing.ts, config/model-pricing.ts, Creditle pre-check de solde, la ligne d'usage, le cout provider estimela production de la plateforme (hors ledger), et le cout d'une video sur l'asset (Map en memoire, jamais remplie pour la video)
Distributionservices/growth/postiz.ts, features/growth/postiz-draft.ts, ContentRender, ContentReviewle brouillon par canal, l'approbation humaine, la preuve de publicationqu'un store ait ses propres canaux : Postiz est une seule cle, celle de la plateforme
Mesureservices/growth/attribution.ts, lib/datafast-api.ts, AttributionEvent, CreativeLearningl'attribution observee, l'apprentissage par concept et par variantele maillon generation → post → canal
Connaissancefeatures/ai/skills/, knowledge-tools, memory/, prompts/kernel.ts, .claude/skills/les trois niveaux de contexte du chat (modele, ecosysteme, utilisateur)le niveau 1 seul du noeud aiText du canvas (ai-platform/2777)
Surfacesconfig/admin-routes.ts (categorie creative, 6 outils), features/studio/ops-routes.ts, ~/studio/*, [storeSlug]/studioqui ouvre quoi, avec quelle permissionqu'une seule des trois fabriques soit atteignable par un non-admin

La frontiere Founder / Store, couche par couche

La plateforme n'est nommee par aucun identifiant, et ce n'est pas un oubli : PLATFORM_ORG_ID et Organization.kind ont ete rejetes trois fois (acces-delegue-et-frontiere-studio.md, ADR 0013, ADR 0024). Le profil existe comme un contexte derive a trois couches :

CoucheCe qui porte la frontiereOu
identiteUser.role === "ADMIN", relu en base, jamais depuis la sessionlib/security/platform-admin.ts
mandatcinq platform.* sur un AccessGrant de portee platform, resolues par un membre synthetique delegate a plancher videlib/security/platform-permissions.ts
organisationl'organisation interne = adhesion de l'admin union les organisations atteintes par un mandat portant la permission nommeefeatures/studio/internal-scope.ts

Cote store, le scope tient a chaque couche, et par des mecanismes differents (c'est la solidite et le cout) : le where Prisma d'appartenance (garde par tenant-pages-scope-by-membership.test.ts), la porte cross-tenant du chat (handler-gates.ts : storeAccess.orgId !== activeOrgId → 403), AtlasToolContext, les chargeurs Studio qui prennent storeId dans le where, le prefixe Blob stores/<storeId>/studio, le bearer MCP lie a un seul storeId, le namespace vectoriel par store, et la frontiere /collab (le mandataire n'entre pas cote user, garde par collab-never-reaches-the-user-side.test.ts).

Trois trous, mesures, et ce sont eux que l'ADR 0024 ferme :

  1. studio-references.ts autorise par hote, pas par scope : .public.blob.vercel-storage.com en entier, donc l'URL publique d'un asset d'un autre store passe l'allowlist. Aucun test ne prouve que generateImage du store A ne peut pas referencer le store B.
  2. Le prefixe studio/unassigned : un rendu sans store est facture a l'organisation, ecrit publiquement, liste nulle part, supprimable par personne. Trois sites d'ecriture, zero lecteur.
  3. La production de la plateforme est hors tenant : pas de StudioAsset, pas de ligne Credit, pas de QC. loadQcBoard() sans orgId reste d'ailleurs une signature qui embrasse la plateforme entiere, meme si plus aucun appelant de production ne l'utilise ainsi.

Deux gardes citees par le code n'existent pas sur le disque : delegate-has-no-floor.test.ts (referencee par deux docblocks de lib/security/) et surfaces-import-their-capabilities.test.ts (annoncee par l'ADR 0023, par features/ai/tools/CLAUDE.md et par ai-platform/2764). Une regle citee et absente est plus couteuse qu'une regle jamais ecrite : elle se lit comme tenue.

Les capacites, et ou elles manquent

L'ADR 0023 a fait du registre src/features/ai/tools/ la liste unique : 26 familles, une etape par famille, un risque par outil, trois lecteurs (createAtlasTools, describeAtlasTools, probeToolContext) et un catalogue servi par store a GET /api/workflow/v2/capabilities.

Les sept capacites creatives n'y sont pas :

CapaciteConstruite dansAtteignable depuis
generateImagehandler-tools-build.ts:778le chat seul
composeProductImage:802 (composite serveur, la seule qui produise une preuve de fidelite)le chat seul
generateVector:859 (le modele ecrit le SVG, aucun moteur image)le chat seul
generateVideo:1336 (Veo 3.1 Fast, synchrone, 180 s)le chat seul
saveStudioAsset:1439le chat seul
planCreativeVariants:1925le chat seul
saveCreativeConcept:2089le chat seul

Et le rendu Remotion (launchTemplateRender) n'est atteignable que par deux server actions, l'une requireAdmin, l'autre platform.content.operate. La matrice cible, capacite produit contre implementations :

Capacite produitAujourd'huiA ajouterJamais
image depuis texte / referencesNano Banana Pro (Gateway)——
produit exact dans une scenecomposeProductImage (composite serveur)—un modele generatif seul : la fidelite est le produit
clip court depuis une imageVeo 3.1 Fast (Gateway), synchroneasynchrone (job)—
demonstration du produitRemotion, deterministe (ADR 0017)Remotion comme capacite du registreun provider generatif : l'ADR 0017 a mesure pourquoi
mouvement d'un personnageriena evaluer sur Veo (le Gateway sert deja l'image d'ouverture) ; sinon planned, nomme et desactiveun fournisseur generatif ajoute pour l'obtenir
remplacement d'un personnage dans une videorienidemidem
scenes cinematiques enchaineesrienun enchainement de clips composes par Remotion est le chemin le plus proche de nos moteursidem
voix off aligneeElevenLabs, hors ledger, une seule voixvoix par identite, cout compte—
vecteur editablele modele ecrit le SVG—un raster qui ressemble a du vectoriel

L'identite visuelle : le mot est deja pris

Dans ce depot, avatar designe l'avatar marketing, la cible d'une creative : CreativeConcept.marketingAvatar (« "women 25-34" is not an avatar »), StudioAsset.persona, l'axe de variante persona, le plancher AVATAR_FLOOR = 2 du Go/No-Go, les « Avatar Cards » du skill creative-ads. Et AgentPersona plus identity-registry.avatar designent les agents IA. Trois occupants pour un mot.

Le personnage reutilisable du brief (le fondateur, un porte-parole, un personnage de marque, avec ses references, ses versions, ses attributs et sa voix) n'existe nulle part : aucun modele, aucun type, aucun outil, aucun ecran. Ce qui en tient lieu :

  • une reference de generation est une position d'attachement ou une URL sur allowlist, jamais un identifiant ; aucune grammaire @ n'existe cote Studio (resolveMention, parseMentions : zero occurrence) ;
  • le kit de marque (StoreContext.modules.brandKit) porte nom, ton, audience, palette, typo, logo, et aucun personnage ;
  • la voix est une seule valeur d'environnement, ELEVENLABS_VOICE_ID, pour toute la plateforme ; la doc promet « voix A ≠ voix C » que rien n'implemente ;
  • StudioAssetKind.LIPSYNC n'a aucun producteur ;
  • le consentement de clonage vocal existe, mais dans un script CLI hors application (creative/pipeline/tts.mjs), sur un fichier du depot.

D'ou StudioIdentity (ADR 0024 §6) : un objet distinct, scope comme un asset, reference par son identifiant, resolu par le meme resolveur, avec son consentement. Deux questions restent ouvertes, de gouvernance : le scope (store, comme StudioAsset, ou organisation, pour qu'une agence reutilise un porte-parole sur plusieurs marques) et le droit a l'image d'une personne reelle cote client.

Les surfaces : quinze pages, sur quatre racines gardees differemment

Ce n'est pas une constellation de pages inutiles : les chargeurs sont deja partages (features/studio/boards.ts, board.ts, cockpit.ts servent les pages d'organisation, les pages /admin, la QC de /ops, la file personnelle ~/me, les outils du chat et la route REST). Le noyau commun que la cible demande existe donc deja pour les boards. Ce qui se duplique est ailleurs :

Duplication mesureePreuveSortie
Deux formulaires pour la meme fabrique Remotionadmin/creative/generate/_components/generator.tsx (313 lignes) et ops/content/_components/creative-workshop.tsx (420 lignes) : les deux importent les memes dix symboles du meme template-catalog.ts : ce qui est duplique n'est donc pas le catalogue, deja unique, mais le formulaire autour (etat local, rendu des champs, validation d'affichage, bouton)un composant unique dans features/creative/, parametre par l'action ; les deux portes restent differentes
Quatre boards internes en double/admin/creative/{cockpit,pipeline,clients,concepts} sont les memes pages que ~/studio/*, avec canManage / canValidate forces a true au lieu d'etre derivesfusionner vers ~/studio/*, ou assumer /admin/creative comme « fabrique plateforme » (generate + library) et rien d'autre
Deux lecteurs de l'etat d'un rendu, par deux modules homonymeslistRenderRuns de services/creative/render-dispatch.ts (lu par admin/creative/generate) et listRenderRuns de services/growth/creative-render.ts (lu par ops/growth) : deux fonctions du meme nom, dans deux modules paralleles, pour un fait qui vit sur l'API GitHub. ToolStateStrip n'en est pas un : il affiche de la configuration et un lien sortantune table de jobs, et les deux lisent la meme ligne
Deux surfaces Postizops/content (file de relecture, ContentReview) et ops/growth (rendus, media desk, ContentRender) ecrivent chez Postiz avec deux modelesune file de distribution partagee ; ops/growth garde l'amont (unite → rendu)
Trois galeriesGeneratedGrid (Blob nu), StudioAssetGrid (Prisma), StudioMediaCard (resultat d'outil)une carte d'asset, une galerie, sur la forme StudioAsset
Deux sources de tokens de marquecreative/src/tokens.ts ecrit ses couleurs, rayons, polices et courbes en dur (45 lignes, derivees de rien) ; src/styles/tokens.css porte les memes valeurs sous forme deriveecreative/src/tokens.ts derive du design system, en tranche 4 : c'est le moment ou la production de la plateforme rentre dans le produit

Quelle racine devient le Studio de la plateforme ? La question est tranchee par une contrainte que le depot porte deja : /admin est garde au bord sur User.role === "ADMIN" (src/proxy.ts), donc une page qui doit s'ouvrir a quelqu'un qu'on recrute ne peut pas y vivre. C'est exactement pourquoi la QC creative a demenage vers /ops (security-identity/0605). La fabrique suit le meme chemin : la porte de production de la plateforme est /ops, avec une permission platform.* ; /admin/creative garde ce qui est du ressort du proprietaire seul. Ce qui est deja vrai a moitie (la QC est sous /ops, la fabrique sous les deux) devient une regle.

Les moteurs, et pourquoi la liste est fermee

Six moteurs, et aucun autre : AI Gateway de Vercel (Nano Banana Pro pour l'image, Veo 3.1 Fast pour la video, un seul catalogue dans config/ai-models.ts), ElevenLabs (voix), Remotion (composition deterministe, ADR 0017), Playwright (creative/pipeline/capture.mjs, sur une allowlist : c'est la marche « produit reel » de la hierarchie de l'ADR 0017, celle qui passe avant toute imitation), Postiz (distribution), Datafast (mesure).

Les captures qui ont servi de reference viennent d'un studio generatif du marche. Elles sont une reference d'ergonomie : la forme des controles, la facon de poser un slot, la maniere de dire une limite. Pas un fournisseur. Tranche le 2026-09-18, et c'est coherent avec l'ADR 0017 qui avait deja refuse un moteur generatif pour montrer le produit.

Ce que cela change pour l'architecture, et c'est le point utile : l'abstraction provider ne sert pas a ajouter des fournisseurs. Elle sert a ce qu'une capacite produit (« anime ce personnage ») soit nommee une fois, et que l'UI, le canvas, le MCP et l'API ne sachent pas si elle est servie par une option de Veo, par une composition Remotion, ou par rien. Les trois capacites decrites par les captures et que nos moteurs ne servent pas aujourd'hui (mouvement d'un personnage, remplacement d'un personnage dans une video source, enchainement de scenes) sont donc planned : visibles, desactivees, avec leur raison. C'est exactement ce que the-studio-runs-what-it-declares impose deja au canvas, et ce que le depot refuse de faire autrement (un controle qui semble agir sans agir).

Les ecarts

Les inventaires de session ne sont pas versionnes, donc leurs totaux ne sont derives de rien et ne sont pas repris ici : ce qui tient dans ce document est une preuve fichier:ligne par ligne, verifiable au clone. Le tableau garde les entrees qui decident du plan. La colonne « confirme par » compte les lecteurs independants qui sont arrives a la meme conclusion depuis un angle different, ce qui vaut mieux qu'un vote unanime d'un seul.

EcartStatutPreuveConfirme parCe qu'il faut
Les sept capacites media sont hors du registreMISPLACEDhandler-tools-build.ts:778, 802, 859, 1336, 1439, 1925, 2089 ; absentes de TOOL_FAMILIES (tools/index.ts:119-231) ; le catalogue du canvas derive de describeAtlasTools et ne les voit paschat, generation, MCP, surfaces (4)une famille studio-media, et le contexte qui leur manque (attachements, facturation) sur AtlasToolContext
Aucune ligne ne suit une generationMISSINGgenerateVideo polle 180 s dans un tour de 300 s ; dispatch() GitHub rend 204 sans identifiant de run ; aucun modele Prisma de jobgeneration, jobs, Remotion, MCP (4)GenerationRequest + les jobs QStash existants
Aucune abstraction providerMISSINGimport { experimental_generateVideo, generateImage, generateText } from "ai" appele avec un id code ; render.mjs shelle npx remotion ; voiceover.ts fetch ElevenLabs en directgeneration, Remotion, MCP (3)capacite produit → routeur → adaptateur ; ai-models.ts reste le seul catalogue
La plateforme n'est pas un tenant de son StudioNEEDS_REFACTORlaunchTemplateRender et listGeneratedAssets n'ont aucune notion de tenant ; Blob creative/library/ sans ligne ; deux definitions de « Founder » cohabitent (l'org de l'admin pour les boards, aucun tenant pour Remotion)tenancy, surfaces, assets, Remotion (4)le point 4 de l'ADR 0024
Les references sont autorisees par hote, pas par scopeNEEDS_REFACTORstudio-references.ts:57 ouvre .public.blob.vercel-storage.com en entier ; aucun storeId dans resolveReferencesgeneration, tenancy (2)resoudre par identifiant d'asset dans le scope, et un test croise
studio/unassigned : rendu paye, sans proprietaireNEEDS_REFACTORtrois sites d'ecriture (handler-tools-build.ts:620, 733, 899), zero lecteur, aucune purgegeneration, tenancy, assets (3)refuser la generation sans store
Le cout d'un asset se perdEXISTS_PARTIALLYrecentImageCost est une Map de 32 entrees en memoire, donc perdue sur une autre instance ; jamais remplie pour la video, donc generationCostUsd est toujours nul pour un clipgeneration, assets, credits (3)lire le cout depuis la ligne Credit, pas depuis la memoire du processus
La production de la plateforme est hors ledgerMISSINGminutes de runner et caracteres ElevenLabs n'apparaissent nulle part ; trackStudioMediaUsage rend null sans orgIdcredits, surfaces, Remotion (3)billing/0613, decision de gouvernance
Aucune identite visuelle reutilisableMISSINGaucun modele, aucun type, aucun outil, aucun ecran ; « avatar » designe deja trois autres chosesavatar (exhaustif)StudioIdentity (ADR 0024 §6)
Une seule voix pour toute la plateformeMISSINGELEVENLABS_VOICE_ID, une valeur d'environnement lue par voiceover.ts et tts.mjs ; la doc promet « voix A ≠ voix C »voix, avatar (2)une voix par identite, et son cout
Aucune suppression propageeMISSINGstudioAsset.delete n'a aucun appelant ; supprimer un store laisse stores/<id>/studio/ publicassetsune action, une purge, un cron
Aucune regeneration partielle, aucun verrou de generationMISSINGzero occurrence de regenerat* dans features/studio, services/creative et orchestrator/runtime (les 94 occurrences de src/ sont la regeneration d'un message de chat et celle d'un jeton de listing, sans rapport avec un rendu) ; le seul locked est un verrou d'AFFICHAGE d'un noeud de canvas, ignore par l'executeurassets, chat, Remotion (3)depend de GenerationRequest : sans parametres persistes, on ne peut meme pas rejouer
Aucun versioning de recetteMISSINGtemplates.json n'a ni version ni hash ; les presets sont des constantes ; Workflow.version est un compteur sans contenuRemotion, assets, chat (3)versionner ce qui produit, pas ce qui affiche
Trois galeries, deux formulaires, trois lecteurs d'etat de runREDUNDANTGeneratedGrid / StudioAssetGrid / StudioMediaCard ; generator.tsx 313 lignes contre creative-workshop.tsx 420 ; RecentRuns / ToolStateStrip / tuile RemotionUI, surfaces (2)une carte, une galerie, un formulaire, une table de jobs
Aucun test de regression visuelleMISSINGni playwright.config.*, ni .storybook, ni toHaveScreenshot nulle part dans le depot (Playwright y est, mais pour le scan et les captures creatives, pas pour tester une interface)UIprerequis a la parite d'interaction, avec les captures
Deux gardes citees sont absentes du disqueMISSINGsurfaces-import-their-capabilities.test.ts (ADR 0023, tools/CLAUDE.md, ai-platform/2764) et delegate-has-no-floor.test.ts (deux docblocks de lib/security/)chat, tenancy (2)les livrer, ou retirer la citation
La distribution est mono-tenantMISSINGPOSTIZ_API_KEY est une valeur d'environnement unique (src/env/server.ts) : une seule cle, celle de la plateforme. Un store n'a aucun canal a lui, et rien n'empeche structurellement un rendu de store d'atterrir sur les comptes de la plateforme, sinon le fait que le chemin n'existe pas encoredistribution, surfaces (2)la clé devient la connexion d'un tenant, en tranche 4, avant que la tranche 8 ne fasse partir quoi que ce soit d'un store
La QA deterministe n'existe pasMISSINGrien ne compare le fichier produit a ce qui a ete demande : ni dimensions, ni duree, ni fps, ni zone de securite. Les specs existent pourtant (creative/src/tokens.ts declare width, height, fps, safeZone par toile) et ne sont jamais confrontees a la sortieRemotion, assets (2)derivable des la tranche 2 : la ligne porte les parametres demandes ET l'artefact produit, donc la comparaison devient une garde
La QA semantique n'existe pasMISSINGzero occurrence de « semantique » dans les chemins de generation : rien ne verifie que l'image montre le bon produit, le bon prix, la bonne marque. La seule preuve de fidelite est composeProductImage, et elle n'est pas persisteeassets, generation (2)tranche 5 ou 6, en partant de la preuve de fidelite qui existe deja
La generation n'est gardee que par le soldeEXISTS_PARTIALLYcanAffordStudioMedia (billing.ts) est le seul controle avant une generation, appele en trois points ; les quatre resolveurs d'entitlement (plan, credits, drapeaux, permissions) ne la couvrent pastenancy, credits (2)une capacite declare son entitlement en meme temps que son risque, tranche 1
Le noeud aiText du canvas n'a qu'un niveau de contextePLANNEDgenerateText({ model, prompt, system }) sans kernel, sans regles, sans memoire ; l'ADR 0023 le nomme dejachat, connaissance (2)ai-platform/2777

Les entrees non reprises ici (menage local, prose perimee, doublons de lecteurs) restent dans les inventaires de la session ; elles ne changent pas le plan.

Ce qui se renomme, se fusionne ou disparait

GestePourquoiRisque, et ce qui le tient
Les sept outils media vers features/ai/tools/studio-media.tsc'est la cause structurelle de l'absence de paritele chat doit continuer a fournir attachements et facturation : studio-write-parity.test.ts est le modele du test a ecrire
studio/unassigned disparaitun rendu paye sans proprietairerefuser tot ; le chat dit deja « pas de store, pas de video » pour la video, on etend a l'image
recentImageCost disparaitune Map en memoire sur du serverlesslire Credit ; le cout devient exact au lieu d'etre absent une fois sur deux
Un composant de fabrique unique dans features/creative/deux formulaires pour un catalogueles portes restent differentes (requireAdmin contre platform.content.operate)
StudioAssetKind.LIPSYNC retireaucun producteur, aucune routel'enum est en base : retrait au schema seulement quand plus rien ne le lit
commerce-os-registry.ts et commerce-system-registry.ts retiresplus aucun importateur depuis la moitie cliente de 2764ai-platform/2773 les cite comme « source de ce qu'une porte doit exiger » : il doit deriver de resolveToolRisk a la place
GET /api/workflow/v2/platform, POST /context, GET /templates retiresaucun appelant ; publient des registres a la mainc'est l'oracle que l'ADR 0023 refuse
creative/src/briefs/load-u18.ts retireaucun appelant—
L'import de Root.tsx vers .claude/skills/ coupeune dependance Remotion vers un dossier de skill d'agentdeplacer le brief dans creative/
services/growth/creative-render.ts retiretroisieme chemin de rendu, vocabulaire proprequand le plan Q4 passe par templates.json
ledger.json du pipeline CLI retirejamais rempli en production, double l'AdminAuditLog—

Ce qu'on clone, composer par composer

La consigne est explicite : on reproduit ce que ces studios font tous, on n'utilise aucun d'eux. Ce qui se clone est la forme des controles, la facon de poser un slot, la maniere de dire une limite, l'endroit ou vit le cout. Ce qui reste le notre est le moteur, le nom de la capacite et la porte.

La regle qui gouverne toute cette section, prise telle quelle du brief : l'interface est definie par la capacite, jamais par un formulaire universel. Pas d'invite quand la capacite n'en accepte pas ; pas de duree manuelle quand la sortie suit sa source ; pas de selecteur de format quand la sortie suit sa source. Un controle qui ne pilote rien est la faute que ce depot corrige deja ailleurs (la toolbar de la preview rendait ses commandes dans les quatre modes et trois d'entre eux n'agissaient sur rien).

Sept composers, et ce que nos moteurs en servent reellement :

Composer de referenceSes controlesNotre cheminVerdict
Imageonglets de mode, references image optionnelles, invite, selecteur de modele (nom, objet, cout, selection), format, enregistrer, Generer + coutNano Banana Pro sur le Gateway ; les references (jusqu'a six) et les six formats sont deja des schemas zod ; le cout par image est deja tarife et affiche dans le menu « + »clonable tout de suite : tout existe cote serveur, rien cote ecran
Video (qualite)image d'ouverture, « decrivez le mouvement », qualite, duree, enregistrer, Generer + coutVeo 3.1 Fast ; l'image d'ouverture est deja referenceImage / referenceUrl ; la duree est deja 4, 6 ou 8 ; le cout est deja par secondeclonable tout de suite
Video cinematique + Scenesimage d'ouverture, image de fin (mono-scene), invite, duree, audio, bascule Scenes, puis de deux a cinq plans avec invite et duree propres, somme validee, audio imposel'image de fin a un chemin : frameImages accepte first_frame et last_frame, et src/test/ai-sdk-video-frames.test.ts l'assere au compilateur ; l'outil ne l'expose simplement pas. Le multi-plan est N clips Veo assembles par Remotion, chacun avec son invite et sa duree : c'est deterministe, c'est notre moteur, et c'est la piece la plus interessante du lotclonable, et c'est celle qui vaut le plus
Multi-entrees (type Seedance)debut, fin, images, videos, audio, invite, modele, resolution, format, duree, audio, cout ; les limites affichees dans le slotinputReferences est typee pour des entrees image et video ; l'audio est genere par Veo lui-meme ; la resolution n'est deliberement jamais passee (borne economique documentee dans model-pricing.ts)partiel : les slots et l'affichage des limites se clonent ; l'audio en ENTREE et la resolution demandent une decision
Reference par mention (type Nova)videos, images, debut, fin, invite avec « tapez @ pour referencer un element sauvegarde », resolution, vitesse, format, dureela grammaire @ est la piece la plus utile a cloner, et elle est entierement notre : elle depend des elements sauvegardes (ci-dessous), pas d'un fournisseur. La vitesse est un retiming, que Remotion fait de maniere deterministeclonable : mentions plus retiming Remotion
Remplacement de personnagevideo source, une a quatre photos de personnage, aucune invite, resolution, vitesse, temps estimeaucun de nos six moteurs ne sert le remplacement d'un personnage dans une video sourceplanned : nomme, visible, desactive, avec sa raison
Transfert de mouvementimage de personnage, video de mouvement de trois a trente secondes, modele, orientation (« suivre le cadrage de la video » ou « conserver le cadrage de l'image »)aucun moteurplanned, meme traitement. A noter pour le jour ou : l'orientation se presente en mots, jamais en enum technique, et cette exigence-la est deja un principe du depot

Deux consequences qu'on ne veut pas manquer :

  1. Cinq composers sur sept sont servables par nos moteurs, et deux d'entre eux ne demandent que d'exposer ce que le code type deja (l'image de fin) ou de composer ce que Remotion sait faire (le multi-plan, le retiming). Le clone n'est donc pas un exercice d'imitation : c'est surtout du cablage.
  2. Les deux qui restent sont declares, pas caches. Une capacite planned qui dit pourquoi vaut mieux qu'une absence : c'est la difference entre « le produit ne sait pas encore » et « le produit ne sait pas ».

Les elements sauvegardes, et la grammaire @

C'est le systeme que les trois composers a mentions supposent, et il n'existe pas : aucune grammaire de mention cote Studio, aucune table d'element sauvegarde. Les types que le brief enumere, confrontes a ce que le depot porte deja :

Type d'elementCe qui existe dejaCe qu'il faut
produit, image de produitle catalogue Shopify, autorise comme referenceun identifiant, pas une URL
logo, actif de marqueStoreContext.modules.brandKit (logoUrl, faviconUrl)l'exposer comme element referencable
capture, etat d'interfacecreative/captures/ via Playwright, sur allowlistremonter dans la bibliotheque
actif genereStudioAssetdeja la, il lui manque d'etre adressable par mention
image de debut, image de fin, reference de style, reference de mouvementdes roles, pas des objets : un meme actif joue l'un ou l'autre selon le slotle role appartient au slot, l'objet a la bibliotheque
personne, porte-parole, fondateurrienStudioIdentity (tranche 6)
voix, musique, audioELEVENLABS_VOICE_ID, une valeur globaleune voix par identite, et un actif audio

La regle qui en sort : un element sauvegarde est un actif de la bibliotheque plus un role donne par le slot. Pas une seconde taxonomie. C'est ce qui evite d'avoir a inventer un objet « StartFrame » distinct d'une image.

La definition d'une capacite

Le brief propose une forme, et le depot en porte deja les trois quarts, eparpilles. Ce que la famille studio-media (tranche 1) doit rassembler, avec pour chaque champ ce qui le tient aujourd'hui :

ChampOu il vit dejaCe qui manque
identifiant, nom affiche, descriptionle nom de l'outil, sa description zodrien
modalite, tacheimplicite dans le nomexplicite, pour que l'UI groupe
moteur, capacite du moteurconfig/ai-models.tsle lien capacite → moteur
slots d'entreeles schemas zod (referenceImages, referenceUrl…)le vocabulaire de slot, aujourd'hui inexistant
controlesles schemas zod (aspectRatio, durationSeconds, placement, scenePreset)leur forme d'affichage
contraintesMAX_REFERENCE_IMAGES, VIDEO_DURATIONS, MAX_VIDEO_STYLE_REFERENCES, MAX_REFERENCE_BYTESqu'elles soient lisibles par l'UI plutot que seulement appliquees
cout estimemodel-pricing.ts, canAffordStudioMediarien
latence estimeerienutile pour le composer de remplacement, qui l'affiche
disponibiliteworkflow-capabilities.ts (available, planned) et capability-catalogue (needs-connection)l'etendre a la generation
droits, portee d'executiontool-permission-matrix.ts, platform.*, studio.*rien
validation, adaptateurzod ; l'appel direct au SDKl'adaptateur (tranche 5)

L'interface du Studio se derive de ces definitions. C'est exactement ce que le canvas fait deja pour les 87 autres capacites : son formulaire de noeud est genere depuis l'inputSchema. La generation rejoint ce mecanisme au lieu d'en inventer un.

Les slots, comme primitive

Huit slots nommes par le brief, zero composant dans le depot. Chacun doit connaitre ses types acceptes, son nombre maximum, sa taille, sa duree maximum, sa portee (le scope, c'est la tranche 3), son etat de televersement, son apercu, son retrait, son remplacement, et le selecteur d'actif deja sauvegarde.

C'est la primitive qui manque le plus, parce que les sept composers ne different presque que par elle : image d'ouverture, image de fin, references image, references video, references audio, personnage, video source, video de mouvement.

Le vocabulaire de mouvement

Le brief enumere dix-sept primitives de motion design (mise au point, deplacement de curseur, clic, revelation, decalage, modale, panneau, surlignage, bulle, frappe de texte, revelation de graphique, compteur, element partage, transition de scene, sous-titre, cadre de navigateur, cadre d'appareil). Le depot en porte dix, et aucune de ces dix-sept par son nom : SafeZone, HookText, KineticText, ProductWindow, BrandBackground, Glow, Notification, Chart, CTA, ChapterCard.

Le recouvrement est reel mais partiel : KineticText couvre la frappe de texte, Chart la revelation de graphique, ProductWindow s'approche du cadre de navigateur. Manquent surtout celles qui montrent un PRODUIT en action : mise au point, curseur, clic, element partage entre deux plans. C'est ce qui separe une video « jolie » d'une demonstration, et c'est exactement la marche que l'ADR 0017 place en haut de sa hierarchie.

La matrice ecrans : un squelette, et ce qui lui manque

Les captures de reference ne sont pas dans le depot. Cette matrice est construite sur les composers decrits textuellement par le proprietaire et sur les primitives qui existent. Elle dit ce qu'il faudra verifier, pas ce qui est decide. Les versionner (sous docs/references/creative-composers/) est un prerequis nomme de la parite d'interaction, pas une formalite.

Etat des primitives, mesure :

Primitive cibleCe qui existeVerdict
StudioShellrien ; voisin : ~/studio/layout.tsx + studio-nav.tsxmanquant
StudioToolbarPromptInputToolbar (chat), PanelToolbar (role="toolbar")a composer
StudioComposerle composer du chat, deja eclate en cinq fichiers composer-*.tsx (environ 1 955 lignes) sur la primitive prompt-input.tsx, monte par ai-chat.tsx (2 116 lignes)a composer, pas a casser : les morceaux existent
CapabilityTabsMediaToggleRow + SegmentedControl, quatre etats, tarif en HoverCardpartiel, et l'etat vit en localStorage
InputSlot (start, end, refs image, refs video, audio, personnage, video source, video de mouvement)aucun composant ; cote serveur seulement, en positions et URLsmanquant, c'est la piece centrale
ParameterChip / ParameterPopoverChip, StatusBadge, ui/popover, HoverCarda composer
GenerateButtonPromptInputSubmit, ComposerRightActions (dont blockedByCredits)a generaliser
GenerationStatustoolPart.state, MessageToolRun, Spinner ; ToolProgress reserve aux scanspartiel, et sans etat reel a afficher tant qu'aucune ligne ne suit un rendu
AssetCard / StudioGalleryStudioMediaCard, GeneratedGrid, StudioAssetGrid : troisa unifier
AssetPickerrien : aucun selecteur d'asset existant a reutilisermanquant
RunCardMessageToolRun, les elements Tool* d'ai-elementsa composer
InspectorDrawerui/sheet, StoreSettingsSheet comme modeledisponible

Les etats a couvrir, pour chaque composer : survol, selection, desactive, televersement en cours, au-dela de la limite, solde insuffisant, en generation, echoue, termine. Aucun n'est teste visuellement aujourd'hui.

Les trois composers decrits, et ce que la codebase peut en tenir :

ComposerControles decritsCe qui existe dejaCe qui manque
Replace (video source + une a quatre references personnage, sans invite)deux slots, resolution, vitesse, temps estimerienles deux slots, la capacite, un provider, l'estimation
Motion (image personnage + video de mouvement de trois a trente secondes, orientation)deux slots, modele, selecteur d'orientation avec sa description en clairrienidem, plus le vocabulaire d'orientation en mots, pas en enum
Cinematic > Scenesde deux a cinq scenes, invite et duree par scene, somme egale a la duree globale, audio impose, pas d'image de finrienun vrai mini-compositeur de plans, pas un interrupteur

La regle qui en sort : l'UI est derivee de la capacite, jamais un formulaire universel. Un controle que la capacite n'accepte pas ne s'affiche pas ; une limite s'affiche dans le slot (« jusqu'a 4 », « 30 s max ») ; et rien n'affiche un pourcentage que personne ne connait.

Les tranches

Chaque tranche est verticale (elle produit un resultat observable), elle reutilise le maximum, et elle nomme sa garde. L'ordre est celui des dependances, pas celui de l'envie.

Tranche 1 : la generation entre dans le registre

Resultat observable : depuis le chat, rien ne change ; depuis le canvas, un noeud « Generer une image » s'execute reellement ; depuis le catalogue servi par store, generateImage apparait avec son etat.

Pilierai-platform
Fichiersfeatures/ai/tools/studio-media.ts (nouveau, recoit les fabriques derriere une interface d'adaptateur unique), tools/index.ts (une famille), tools/types.ts (AtlasToolContext gagne attachements et facturation), orchestrator/runtime/handler-tools-assembly.ts (devient un appelant), workflow/v2/lib/workflow-capabilities.ts
Reutilisetout : les fabriques ne sont pas reecrites, elles demenagent ; wrapToolsWithAutonomy, resolveToolRisk, capability-catalogue fonctionnent par derivation
L'abstraction provider commence icic'est la tranche qui la livre, et rien d'autre ne la livrerait : les sept fabriques passent derriere UNE interface (une capacite produit, un adaptateur), et renderComposition (tranche 4) puis la voix (tranche 6) deviennent le deuxieme et le troisieme adaptateur de la meme interface. Sans cela, l'ADR 0024 point 3 resterait une phrase
Entitlementune capacite studio-media declare son droit de plan en meme temps que son risque : aujourd'hui la generation n'est gardee que par le solde, jamais par un entitlement
Gardessurfaces-import-their-capabilities.test.ts (celle que l'ADR 0023 annonce et qui n'existe pas), the-studio-runs-what-it-declares etendu, un test de parite chat contre canvas sur le modele de studio-write-parity, et check-model-catalogue.mjs etendu aux adaptateurs
TailleL

Tranche 2 : une generation est une ligne, et un job

Resultat observable : un clip de huit secondes qui met quatre minutes arrive ; l'operateur voit « en cours » puis le fichier ; rien n'est facture si rien n'est livre.

Piliersdata-platform (le modele), ai-platform (les appelants)
Fichiersprisma/schema.prisma (GenerationRequest, additive, aucune colonne requise sans defaut sur un modele existant), services/jobs/types.ts + un handler, handler-tools-build.ts (ecrit la ligne avant l'appel), billing.ts (le cout se lit sur la ligne, recentImageCost disparait)
ReutiliseQStash, la DLQ, le verifier, deduplicationId pour l'idempotence
Ce que la tranche doit refermer en passantle plafond de depense. Sortir la generation du tour invalide le seul plafond dynamique existant (le hard cap mi-stream, lie au tour) : le solde doit etre reverifie au depilement, pas seulement a l'enfilement, sinon N requetes en file depassent le solde ensemble. La QA deterministe devient derivable ici : la ligne porte les parametres demandes ET l'artefact produit, donc comparer dimensions, duree, fps et zone de securite est une garde et non un voeu. La suppression propagee aussi : c'est le premier endroit ou le chemin Blob d'un artefact est connu en base, donc la purge se derive au lieu d'etre un balayage de prefixe
Gardespas d'appel provider sans ligne prealable ; pas de ligne Credit de canal studio sans requete ; N requetes en file ne peuvent pas depasser le solde ; le fichier produit correspond aux parametres demandes ; le plafond not-null-column-adds monte de ses colonnes neuves, chacune nommee
TailleL

Tranche 3 : le scope, ferme

Resultat observable : le store A ne peut plus referencer un asset du store B ; un rendu sans store est refuse avant la depense.

Piliersai-platform, security-identity
Fichiersstudio-references.ts (resolution par identifiant dans le scope), handler-tools-build.ts (studio/unassigned retire)
Gardestests de scope croise, dans src/test/ : store A contre store B sur la reference, la sauvegarde et la lecture ; un mandat de store n'ouvre aucune capacite du profil plateforme
TailleM

Tranche 4 : la plateforme devient un tenant de son Studio

Resultat observable : un rendu Remotion de la plateforme apparait dans une bibliotheque avec son cout, son statut de relecture et son concept, comme celui d'un client.

Piliersgrowth-web (creative/, la doctrine), app-shell (les surfaces), billing (le compte)
Fichiersservices/creative/render-dispatch.ts (devient une capacite renderComposition), generated-assets.ts (transition), creative-media-os.md §2 (la doctrine passe de trois planes a un moteur et des scopes), le composant de fabrique unique
Bloque parbilling/0613 : comment distinguer la production interne du revenu consomme est une decision de gouvernance
Gardesaucun if (isPlatformAdmin) dans une capacite studio-media ; le store de la plateforme se resout par internal-scope.ts, jamais par une constante
TailleL

Tranche 5 : les capacites que nos moteurs ne servent pas, nommees

Resultat observable : « anime ce personnage avec ce mouvement » repond « pas encore, voici pourquoi » au lieu de ne rien dire ; et ce que Veo ou Remotion savent reellement faire est branche.

Pilierai-platform
Prerequisles tranches 1 et 2
Travailevaluer ce que Veo sert au-dela de l'image d'ouverture (references de style, image de fin : le SDK les type, le tool ne les expose pas) ; evaluer un enchainement de clips composes par Remotion ; declarer planned ce qui reste, avec sa raison
Fichierstools/studio-media.ts, workflow-capabilities.ts, ai-models.ts
Gardesune capacite planned ne s'execute pas et le dit ; un champ invalide est refuse avant tout appel ; la description derive du catalogue
Ce que la tranche ne fait pasajouter un fournisseur. La liste est fermee, et l'ouvrir est une decision de gouvernance, pas une tranche
TailleM

Tranche 6 : l'identite visuelle

Resultat observable : « genere avec @<identite> » produit le meme personnage deux fois ; sa voix le suit.

Piliersdata-platform, ai-platform
FichiersStudioIdentity et ses references, studio-references.ts (resolution par identifiant), voiceover.ts (une voix par identite)
Bloque parle scope (store ou organisation) et le consentement : deux decisions de gouvernance
TailleL

Tranche 7 : la surface

Resultat observable : les composers decrits existent, un seul formulaire, une seule galerie, une carte d'asset.

Piliersdesign-system, app-shell
Prerequisles captures versionnees ; les tranches 1 et 2 (sans etat reel, GenerationStatus n'a rien a montrer)
Fichiersfeatures/creative/ (composer, slots, galerie), les trois galeries fusionnees
Gardesregression visuelle (a installer), etats couverts
TailleL

Tranche 9 : rejouer, verrouiller, versionner

Resultat observable : « refais exactement ca pour la feature B » fonctionne ; « ne change plus cette image » tient ; une recette qui bouge ne reecrit pas le passe.

Six exigences du brief tiennent ensemble parce qu'elles ont toutes le meme prerequis, et c'est pour cela qu'elles sont une tranche et non six : sans les parametres d'une generation en base (tranche 2), on ne peut ni rejouer, ni verrouiller ce qui a produit, ni dire avec quelle version d'une recette un artefact a ete fait.

Piliersdata-platform, ai-platform
Prerequistranche 2, strictement
Couvreregeneration partielle (rejouer une branche sans rejouer le reste), verrous (un actif approuve ne se fait pas ecraser par une resauvegarde sur la meme URL), versioning des recettes (templates.json et les presets n'ont ni version ni empreinte), presets (aujourd'hui des constantes de code, non editables, non scopees), comparaison de variantes (le lien existe en base, aucune vue ne le montre), historique et rejeu
TailleL

Tranche 8 : la boucle

Resultat observable : une hypothese produit des creatives, elles partent par canal, ce qui revient se rattache a l'hypothese.

Piliersgrowth-web, intelligence
Prerequisles tranches 2 et 4 (sans ligne de generation, le maillon manque)
TailleL

Le master prompt, section par section : ou chaque exigence vit

Le brief compte 105 sections. Un audit qui n'en couvre que les plus visibles laisse croire que le reste est prevu. Ce tableau dit, groupe par groupe, ou l'exigence est portee (une section de ce document, un point de l'ADR 0024, un item), et ce qui n'est porte nulle part encore, avec l'endroit ou ca ira. Une lecture prealable vaut pour tout le tableau : la reference d'ergonomie du brief (le studio generatif tiers) est une reference, jamais un moteur. Ses sections 26 et 93 (lire sa documentation, en deriver une matrice provider) sont remplacees par la meme matrice derivee de NOS six moteurs, sur consigne du 2026-09-18 : ses modeles sont ceux que l'AI Gateway sert deja.

SectionsExigenceOu elle vitEtat
0-2codebase first, cartographie EXISTS / PARTIAL / MISSINGce document entier, 16 sous-systemes, chaque ligne avec preuvecouvert
3-4, 92matrice ecrans, parite fonctionnelle, statut par capture« La matrice ecrans » ; design-system/2785squelette : les captures ne sont pas dans le depot, la matrice se remplit quand elles y sont
5-8un noyau, deux profils, Founder = jamais un super storeADR 0024 points 4 et 5 ; « La frontiere Founder / Store » ; growth-web/2783, ai-platform/2782couvert
9-11un moteur d'identite, deux surfaces, identite reutilisableADR 0024 point 6 ; « L'identite visuelle » ; data-platform/2784, decisions 2789 et 2790couvert, bloque par deux decisions
12elements sauvegardes, grammaire @« Les elements sauvegardes » ; tranche 6couvert dans le plan, rien de livre
13-14, 71le chat est le cockpit, manuel et agent sur le meme pipelineADR 0024 point 1 ; ai-platform/2780couvert : c'est LA tranche 1
15-22les sept composers a cloner« Ce qu'on clone, composer par composer » ; 2785couvert, avec un verdict par composer
23-24CapabilityDefinition, slots comme primitives« La definition d'une capacite », « Les slots » ; 2780 porte la definition, 2785 les slotscouvert
25, 28, 49UI → registre → service → routeur → adaptateur ; capacite produit ≠ capacite providerADR 0024 point 3 ; tranche 1 (« L'abstraction provider commence ici »)couvert, sur une liste de moteurs fermee
26-27, 93doc provider, ne pas inventer une API, matrice providerremplacees : matrice de NOS moteurs, « Les moteurs » ; check-model-catalogue.mjs etendu aux adaptateurscouvert, autrement que le brief le demandait
29-30generation asynchrone persistee, pas de faux pourcentageADR 0024 point 2 ; data-platform/2781 ; contrainte « un etat reel, ou rien » dans 2785couvert
31concurrence : limites provider, quotas par tenant, file intelligente2781, contrainte « plafond de concurrence par organisation »partiel : QStash porte retries, delai et deduplication (services/jobs/client.ts), aucune notion de concurrence par organisation ni de limite provider. 2781 l'exige, rien ne le dessine encore
32-33ledger de cout (brut / interne / credits / prix public), garde-fous de budget« Argent » dans la carte ; Credit.metadata.providerCost existe ; 2781 (solde reverifie au depilement) ; decisions 2786, 2788couvert pour le ledger, partiel pour les plafonds par run et par campagne : un plafond par cycle est dans 2788, un plafond par run n'est ecrit nulle part
34bibliotheque d'assets integree« Trois galeries » dans les surfaces ; 2785 (une galerie sur StudioAsset)couvert
35-36lignee, graphe d'artefacts, regeneration partiellele lien parent existe en base (StudioAsset.variantOfId) (« le lien existe en base, aucune vue ne le montre ») ; graphe multi-niveaux et regeneration par branche dans app-shell/2792couvert dans le plan ; le graphe est la tranche 9
37-39verrous, versioning des recettes, rejeu et duplicationapp-shell/2792couvert dans le plan
40etat de session structure (scope, objectif, assets, verrous, capacite active)Conversation.metadata est un Json? non type, rien n'y range un etat Studiopas encore : la tranche 2 pose la ligne de generation, l'etat de session qui la reference se dessine avec 2785
41carte de run (plan, etapes, cout, annuler, relancer)agent-plan-card.tsx (parse une liste en prose), task.tsx, tool.tsx, queue.tsx existent dans patterns/ai-elements/chat/partiel : les briques existent, aucune ne lit une ligne de generation ; la carte de run du brief est leur composition sur GenerationRequest, tranche 7
42langage naturel vers capacites@Atlas + le routeur de skills (features/ai/skills/router.ts)couvert des que la famille est dans le registre (tranche 1) : le routage existe, la cible manque
43-44verite produit plateforme, verite produit storeADR 0024 point 4 (facts.md = connaissance du tenant plateforme) ; le Store lit le catalogue par les outils existantscouvert
45-47Remotion moteur deterministe, produit reel d'abord, vocabulaire de mouvementADR 0017 ; « Le vocabulaire de mouvement » ; tranche 4 ; decision 2787couvert
48ElevenLabs comme timing maitrevoiceover.ts, creative/pipeline/tts.mjs ; la voix comme horloge des captions est dans la carte, pas dans une tranchepartiel : la synthese existe, le pipeline script → timestamps → captions → coupes n'est dessine nulle part. Il revient a la tranche 4 quand Remotion est une capacite
50, 54-56boucle strategie → hypothese → recette → generation → QA → distribution → mesure → apprentissage ; spec et recettestranche 8 ; GrowthUnit, ContentRender, planCreativeVariants (les huit termes North Star) existentcouvert dans le plan, la tranche 8 n'a pas d'item de travail avant 2781 et 2783
51-53registre de connaissance (source, auteur, confiance, licence, version), skills curateesfeatures/ai/skills/ existe (registre, routeur, acces) ; aucun champ de source, de licence ni de confiancepas encore, et hors des neuf tranches : c'est un item a ouvrir apres la tranche 8, quand la boucle produit de quoi apprendre. Le dire vaut mieux que l'oublier
57-58canaux par profil, Postiz, adaptation par canal« la distribution est mono-tenant » (ligne d'ecart) ; ADR 0024 sur la regle 2 ; tranche 8partiel : un store n'a pas de canal, et c'est nomme
59-62tracking, attribution (mesuree / derivee / estimee), apprentissage isole par storeAttributionEvent (observe seulement), cron outcome-attribution (mesure l'impact des AgentAction, pas d'une creative), GrowthUnitpartiel : l'attribution d'une creative a un resultat n'existe que par les huit termes que saveStudioAsset accepte ; l'isolation d'apprentissage par store est un principe de l'ADR, pas un mecanisme. Tranche 8
63-65QA deterministe, visuelle, semantique ; regression visuelle ; etats exactslignes d'ecart QA ; 2781 (QA deterministe derivable de la ligne) ; platform-ops/2793 ; 2785 (les etats)couvert dans le plan, la QA semantique n'a pas d'item : elle est une capacite de plus dans le registre, apres la tranche 1
66-68acces Founder cote serveur, entitlements store, public-ready sans constanteADR 0024 points 4 et 5 (internal-scope.ts, jamais un id) ; tranche 1 (entitlement) ; decision 2788couvert
69retention et suppression propageedata-platform/2791couvert dans le plan
70piste d'audit des operations sensiblesAdminAuditLog sur les verdicts QC (features/studio/actions.ts), AuditLog sur l'autorisation (guard.ts) ; rien sur une generation couteuse, une publication ou une suppressionpartiel : la tranche 2 ecrit une ligne par etat de generation, c'est la piste ; publication et suppression suivent avec 2791 et la tranche 8
72-75comparer, presets, historique, recherche2792 (comparer, presets, historique) ; la recherche globale a un registre de providers (lib/search/) sans provider Studiopartiel : un provider de recherche sur StudioAsset et GenerationRequest est une ligne dans 2785, ajoutee ci-dessous
76-79secrets serveur seulement, observabilite structuree, idempotence, une seule fileserverEnv, le logger structure, deduplicationId, QStash seul broker ; 2781 (« ne pas creer un second broker »)couvert
80-82primitives partagees, pas une constellation de pages, un centre de commande sobre« Les surfaces » (quinze pages, quatre racines) ; 2785 ; /ops/content existe deja comme cockpitcouvert
83-86ne pas sur-agentiser, le code pour les regles, controle humain, pas de regeneration gaspilleeADR 0023 (un orchestrateur + outils) ; 2792 (verrous, rejeu) ; 2781 (rien n'est refait parce que le chat a recharge)couvert
87-88renommer sans casser, migrations non destructives« Ce qui se renomme, se fusionne ou disparait » ; le schema guard additif, not-null-column-addscouvert
89tranches verticales, la premiere reutilise le plus« Les tranches », neuf, la premiere sans bloqueurcouvert
90-91, 96-97quatre surfaces validees separement, tests croises, relecture apres chaque changementADR 0024 point 5 ; chaque item porte ses tests croises en DoDcouvert dans le plan
94-95l'existant plus avance prime, l'invisible comptece tableau est la reponse a 95 ; 94 est la regle de chaque verdict de composercouvert
98la documentation attenduece document (inventaire, ecarts, carte, frontiere, capacites, identite) + ADR 0024 ; le reste nait avec sa tranchepartiel : PROVIDER_CONTRACTS, ARTIFACT_GRAPH, KNOWLEDGE_ENGINE n'existent pas encore, chacun a une tranche
99, 104-105ne pas s'arreter au plan, demarrer par la plus petite tranchela tranche 1 est ouverte et sans bloqueur : c'est le prochain geste apres le mergecouvert

Ce que ce tableau laisse honnetement dehors : le registre de connaissance (51-53), la QA semantique (63) et le pipeline voix-comme- horloge (48). Aucun des trois n'est oublie, aucun n'a d'item, et les trois dependent d'une tranche qui n'est pas livree.

Risques

  • La tranche 1 touche le chemin le plus chaud du produit. Deplacer sept outils, c'est risquer de casser le chat. Ce qui l'attenue : les fabriques ne sont pas reecrites, et le test de parite est ecrit avant le deplacement, pas apres.
  • AtlasToolContext est un type partage par 26 familles. Lui ajouter deux champs oblige chaque construction de contexte a repondre. C'est voulu (le depot le dit deja pour isPlatformAdmin), mais c'est une PR large.
  • La tranche 4 rend visible une depense qui ne l'etait pas. Le cockpit d'economie affichera une marge differente le jour ou la production interne y entre. C'est une correction, pas une regression, et il faut le dire avant.
  • Un provider de plus est une surface d'attaque et une facture. Cle serveur seulement, scope non accordable par defaut, plafond ecrit.
  • Le squelette d'UI sans les captures est une invitation a deviner. Il est marque comme tel a trois endroits pour que personne ne le lise comme une specification.

Ce qui attend une decision de gouvernance

Aucune de ces questions n'est tranchable par un agent : chacune engage un prix, un contrat, une depense ou un risque juridique. Une question sans item type: "decision" n'atteint jamais le registre, donc le proprietaire ne la voit pas : les cinq qui n'en avaient pas en ont un, et la section 8 de docs/ops/operator-decisions.md les porte avec leur recommandation.

QuestionItemCe qui est deja mesureBloque
Comment distinguer au ledger la production interne du revenu consomme ?billing/0613billing/0613 : trackStudioMediaUsage rend null sans orgId, donc gratuit et invisible ; l'equipe se debite elle-meme depuis son organisationtranche 4
Le cout de gros reel d'une image, et ouvre-t-on le controle de resolution ?billing/2786l'ecart est epingle : markup: 1.5 avec perImage 0.21 impliquerait 0.14, la constante dit 0.039 ; studio-media-units-have-a-cost.test.ts le nomme sans le trancherla verite du cockpit de marge
Le mouvement et le remplacement d'un personnage restent-ils planned, ou vaut-il la peine d'ouvrir la liste fermee des moteurs pour les obtenir ?aucun : la liste des moteurs est fermee par l'ADR 0024, la rouvrir se demande en une ligneaucun de nos six moteurs ne les sert ; la reference d'ergonomie qui les montre n'est pas un fournisseur que nous utiliseronstranche 5
Une identite est-elle scopee au store ou a l'organisation ?data-platform/2789StudioAsset n'a que storeID ; une agence qui reutilise un porte-parole sur plusieurs marques n'a aucun mecanismetranche 6
Le droit a l'image et a la voix d'une personne reelle cote clientsecurity-identity/2790le seul controle existant est assertVoiceConsent, dans un script CLI hors applicationtranche 6
Quel plan inclut la generation video ?billing/2788canAffordStudioMedia est la seule porte : seul le solde decide, et un clip de 8 s vaut $1.20 contre $1 de bonus quotidien Protranche 1, la couche d'entitlement n'a pas de contenu
La licence Remotionbilling/2787ADR 0017 la nomme (« Automators si automation et organisation de trois personnes ou plus »)tranche 4, des qu'on recrute

Ce que le backlog en fait

Huit items de travail, un par tranche executable plus les deux que la tranche 2 tire derriere elle, cinq items type: "decision" pour les questions qui n'appartiennent a aucun agent, et six items existants dont la relation a la cible est desormais explicite plutot que devinee.

Les items ouverts par cet audit

ItemTrancheBloque par
ai-platform/27801, la generation entre dans le registrerien
data-platform/27812, une generation est une ligne et un job2780
ai-platform/27823, le scope fermerien (meilleur apres 2780)
growth-web/27834, la plateforme devient un tenantbilling/0613, decision
data-platform/27846, l'identite visuelle2780, plus deux decisions
design-system/27857, la surface2780, 2781, et les captures
data-platform/27912, sa moitie retention et suppression propagee2781
app-shell/27929, rejouer, verrouiller, versionner2781
platform-ops/27937, l'outillage de regression visuelle (hors du pilier de la surface)rien
integrations/2794hors tranche : Higgsfield est un secours, jamais un moteur, et le depot doit le presenter ainsirien (consigne)

La tranche 5 (nommer ce que nos moteurs ne servent pas) et la tranche 8 (la boucle) n'ont pas d'item de travail : la premiere est une evaluation qui tient dans 2780 une fois la famille en place, la seconde attend 2781 et 2783 pour avoir un maillon a rattacher.

Les items existants, replaces

ItemEtatRelation a la cible
ai-platform/0377 (un rendu de plus de 180 s n'a aucun chemin)blocked par platform-ops/0329La moitie « rien ne suit un rendu » passe dans 2781, qui ne depend d'aucune version du SDK. Ce qui reste dans 0377 est la moitie SDK : l'asynchrone natif de experimental_generateVideo arrive en ai@7.
ai-platform/2764 (le Studio ignore les 87 capacites)claimed, moitie serveur livreeProlonge par 2780 : 2764 a branche le canvas sur le registre, 2780 met la generation DANS le registre. La garde que 2764 annonce, surfaces-import-their-capabilities, est livree par 2780 puisqu'elle n'existe pas.
ai-platform/2773 (porte d'approbation des ecritures du canvas)ready, bloque par 2764Prerequis pour qu'une capacite d'ecriture passe available sur le canvas. A corriger : il cite commerce-os-registry comme « source de ce qu'une porte doit exiger », or ce fichier n'a plus aucun importateur. Il doit deriver de resolveToolRisk.
ai-platform/2777 (le noeud aiText appelle le modele nu)ready, P1Independant et toujours vrai : tant que le noeud de raisonnement du canvas n'a qu'un niveau de contexte, « meme pipeline » est faux pour lui.
ai-platform/0347 (voix, vecteur, reranker)readyRecoupe 2784 sur la voix : 0347 demande de cabler ce qui manque, 2784 demande a qui la voix appartient. 0347 reste, et attend 2784 pour la partie identite.
app-shell/0154 (la bibliotheque d'un store n'a pas de porte)readyDevient une consequence de 2785 : une galerie unique sur StudioAsset est ce que 0154 demandait.
billing/0613 (qui paie la production Studio interne)ready, type decisionBloque 2783. Rendre la depense visible est du travail ; decider comment elle se distingue du revenu consomme appartient au proprietaire.
integrations/2767 (livrer une creative depuis le MCP)ready, bloque par 2765A reecrire apres 2780. Il n'ouvrait que le chemin Remotion de la plateforme, et demandait « suivre un rendu » sans substrat. Une fois la famille dans le registre et GenerationRequest en base, il devient une porte de scope, pas une implementation.
growth-web/2682 (campagne multi-format)readyReste, et porte l'AMONT de la tranche 8 (unite, recette, multi-format) quand 2781 et 2783 sont la. Il ne porte pas la moitie distribution : son perimetre ne mentionne ni canal par store ni compte Postiz de tenant, et c'est la limite nommee dans la ligne d'ecart « la distribution est mono-tenant ».