TASK-1614 — Catalogue plugin « 3 assistants IA » + disponibilité Organization - #615
Merged
cslucki merged 3 commits intoSep 21, 2026
Conversation
…zation (TASK-1614)
SLICE A de la Product Spec V0 « ChatLoop — 3 assistants IA », validee
repo-grounded par OPUS et passee a VALIDATED sur cette branche.
Ce que cette TASK rend possible, et rien de plus :
« ce plugin existe au catalogue plateforme, et il est autorise ou
non pour telle Organization. »
Le CATALOGUE est un fichier (config/loop_plugins.php), pas une table :
un deuxieme plugin doit rester une entree de configuration, comme un
cinquieme type de Boucle l'est dans config/loop_types.php.
La DISPONIBILITE est une table (organization_loop_plugins), parce que
c'est une decision, qu'elle change sans deploiement et qu'elle est
toujours celle d'UNE Organization. organization_id y est NOT NULL :
loop_type_settings l'accepte nullable parce qu'un reglage de type existe
a deux portees et que null y veut dire « la Plateforme » ; ici un null
voudrait dire « disponible partout », soit le contraire de ce qu'une
capacite experimentale doit faire quand personne n'a rien decide.
Ferme par defaut. Eteindre n'efface pas la ligne : available=false
conserve qui a coupe et quand.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqwjarKwhSbpzdPxLAmNh3
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqwjarKwhSbpzdPxLAmNh3
…tre du cycle de vie (TASK-1614) CI rouge, shard Feature 3/6 : UserDataLifecycleRegistryTest::test_every_user_foreign_key_is_declared_in_lifecycle_registry -> 'Every FK to users.id must be classified in UserDataLifecycleRegistry.' La migration ajoute une cle etrangere vers users.id (updated_by, qui porte l'auteur de la decision de disponibilite). Le depot tient un registre DECLARATIF de toutes ces cles : une cle non classee est une donnee utilisateur dont personne n'a dit ce qu'elle devient a la suppression du compte. La garde a fait exactement son travail. Politique DETACH, org_scope direct, sur le modele de custom_loop_types.created_by et ai_credit_setting_changes.changed_by : savoir si un plugin est autorise dans une Organization est une decision d'administration, pas une donnee personnelle. Elle doit survivre a son auteur, qui est simplement detache — la cle est deja nullOnDelete. Mesure : 30 verts en PostgreSQL (UserDataLifecycle + TASK1614). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqwjarKwhSbpzdPxLAmNh3
cslucki
force-pushed
the
TASK-1614-catalogue-plugin-3-assistants-ia-disponibilite-organization
branch
from
September 21, 2026 12:06
9cef034 to
87996e5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SLICE A — Catalogue plugin + disponibilité Organization
Premier lot de la Product Spec V0 « ChatLoop — 3 assistants IA ».
Cette PR rend possible une seule phrase, et rien de plus :
Aucun assistant, aucun prompt, aucune capability, aucun appel provider, aucune
activation dans une Boucle.
Architecture
Le catalogue est un fichier, pas une table. Patron déjà établi par
config/loop_types.php+LoopTypeRegistry: un deuxième plugin doit resterune entrée de configuration. Une table de catalogue aurait demandé une
migration, un CRUD et un écran d'édition pour décrire ce que seul un
déploiement peut de toute façon livrer.
La disponibilité est une table, parce que c'est une décision, qu'elle
change sans déploiement, et qu'elle est toujours celle d'une Organization.
Deux décisions qui méritent d'être lues
organization_idNOT NULL.loop_type_settingsl'accepte nullable parcequ'un réglage de type existe à deux portées et que
nully veut dire « laPlateforme ». Ici il n'y a qu'une portée. Un
nullvoudrait dire « disponiblepartout » — exactement le contraire de ce qu'une capacité expérimentale doit
faire quand personne n'a rien décidé. Fermé par défaut.
Pas de trait
HasOrganizationIdsur le modèle. Ce trait remplitorganization_iddepuiscurrent_organizationquand il est absent. C'estjuste pour une écriture faite dans un tenant ; c'est faux ici : le SuperAdmin
écrit pour l'Organization qu'il désigne, et elle n'a aucune raison d'être
celle de sa propre session. Hérité en silence, ce serait la faute inter-tenant
exacte que cette PR doit rendre impossible.
Éteindre n'efface pas la ligne.
available = falseconserveupdated_byet
updated_at— donc qui a coupé et quand. C'est l'écart assumé avecloop_type_settings, qui revient au défaut en supprimant : pour une capacitéexpérimentale qu'on doit pouvoir retirer vite, c'est précisément la trace
qu'on veut garder.
Tests — 21 verts, garde tenant mesurée
tests/Feature/TASK1614LoopPluginCatalogueTest.php— 21 passed (52 assertions).Les 5 tests tenant sont assertés dans les deux sens (A→B et B→A) : un seul
sens laisserait passer une lecture qui ignore purement et simplement
l'
organization_id.Sabotage joué — retirer
->where('organization_id', …)deisAvailable():La garde est donc mesurée, pas affirmée. Arbre restauré,
git diffvide.Voisins — 205 verts, grepés sur le contrat touché (
admin.loop-types,admin.loop-permissions,layouts.admin,Route::getRoutes()) : T1079 ×2,T1116, T1117, T1118, T1119, T1489, T1392, T07411, T1289,
tests/Unit/Architecture.Recette navigateur —
https://test.laravel/admin/loop-pluginsmulti_ai_assistants, badge EXPERIMENTAL, 9 Organizations, 0 sur 9, toutes « Non autorisé »available=falseet sa traceNon vérifié
Responsive. La fenêtre a été redimensionnée en 390×844 mais le viewport
rendu est resté à 1920×812 : le rendu mobile n'a pas été constaté. Le
balisage reprend le patron des écrans admin voisins, mais c'est une
ressemblance de code, pas une mesure.
Hors scope préservé
loop_ai_assistants, Aperio/Traverse/Limen, prompts,loop_multi_ai,AiEconomicGuard,config/ai_pricing.php, OpenRouter, Evidence Build,AiTurnLock, follow-ups, UX ChatLoop, permissions owner/animateur — aucuntouché. Les hard gates du §9 de la Product Spec portent sur l'activation en
production : ils restent dus aux SLICES C et D.
Aucune logique
Community. Aucune migration Community → Organization.VERSION 1.614.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JqwjarKwhSbpzdPxLAmNh3