-
Notifications
You must be signed in to change notification settings - Fork 0
Supreme Graal
Faire évoluer Platform Factory pour permettre à un plugin de fonctionner dans une ou deux directions :
native environment
↓
plugin
↓
canonical model
et :
canonical model
↓
plugin
↓
native environment
Un plugin peut donc être :
DISCOVERY ONLY
APPLY ONLY
BIDIRECTIONAL
selon les capabilities réellement implémentées et vérifiées.
Le système doit permettre :
Plugin A
↓
discover
↓
canonical model
↓
Platform Factory
↓
capability resolution
↓
Plugin B
↓
apply
et également l’inverse :
Plugin B
↓
discover
↓
canonical model
↓
Platform Factory
↓
capability resolution
↓
Plugin A
↓
apply
Principe fondamental :
PLUGIN → CAPABILITY
NEVER
PLUGIN → PLUGIN
Le plugin traduit son environnement.
Platform Factory comprend, planifie, résout, orchestre, observe et vérifie.
- Un plugin ne doit jamais importer un autre plugin
- Un plugin ne doit jamais invoquer directement un autre plugin
- Un plugin ne doit jamais sélectionner une autre implémentation par son nom
- Un plugin externe ne doit pas importer
internal/... - Les interactions passent par le protocole plugin existant
- Les plugins sont découverts via
internal/plugin.Registry - Le host résout les capabilities
-
TraceIDest propagé E2E -
OperationIDprotège toutes les mutations - Les résultats plugins restent non fiables jusqu’à vérification host
- Le modèle canonique reste indépendant de toute implémentation
- Aucun nouveau système RPC
- Aucun deuxième registry
- Aucun deuxième journal d’idempotence
- Aucun deuxième modèle de pipeline
Invariant :
PLUGIN ≠ ORCHESTRATOR
Ne pas créer une nouvelle abstraction parallèle.
Réutiliser :
api/plugin
sdk/plugin
internal/plugin.Registry
Ajouter uniquement les contrats nécessaires pour représenter les nouvelles capabilities.
Un plugin peut annoncer des opérations conceptuellement réparties en deux directions.
discover
inspect
observe
export
verify
plan
import
apply
update
delete
verify
La présence d’une capability dans une direction ne doit jamais impliquer l’autre.
Exemple :
plugin A
discover ✓
inspect ✓
export ✓
apply -
ou :
plugin B
discover ✓
inspect ✓
apply ✓
delete ✓
verify ✓
Toutes les décisions doivent être prises par capability.
Interdit :
if plugin.Name == "..."Correct :
requires:
runtime.vm.create
ou :
requires:
deployment.apply
Le host résout ensuite :
requirement
↓
Registry
↓
candidate plugins
↓
trust verification
↓
capability verification
↓
selected plugin
Ne pas confondre :
DECLARED
DISCOVERED
NEGOTIATED
VERIFIED
AVAILABLE
Un manifeste peut annoncer une capability.
Cela ne suffit pas à la considérer utilisable.
Flux :
plugin manifest
↓
Registry
↓
plugin handshake
↓
runtime verification
↓
AVAILABLE
Invariant :
DECLARED CAPABILITY
≠
AVAILABLE CAPABILITY
Créer ou compléter les contrats publics nécessaires sous :
api/migration/
Optionnellement :
sdk/migration/
Répartition :
api/migration
→ contrats sérialisables
sdk/migration
→ helpers publics
internal/app/migration
→ orchestration
Ne pas placer un contrat utilisé par un plugin externe dans internal/....
Créer un modèle générique.
type Resource struct {
ID string
Kind string
Source ResourceOrigin
Attributes map[string]string
Requirements []Requirement
}type ResourceOrigin struct {
PluginID string
NativeType string
NativeID string
Location string
}Le modèle doit conserver :
- identité native ;
- origine ;
- caractéristiques ;
- requirements ;
- garanties ;
- état observé.
Il ne doit jamais dépendre d’un target particulier.
Ajouter :
type DependencyEdge struct {
From string
To string
Relation string
Required bool
}Le graphe doit permettre de répondre :
What depends on this resource?
What must move with it?
What may remain external?
What becomes unavailable if this resource disappears?
- IDs uniques
- références valides
- dépendances externes explicites
- ordre déterministe
- relations déterministes
- aucune dépendance silencieusement ignorée
- détection des incohérences
Un plugin capable de discovery doit :
- observer son environnement natif
- découvrir les ressources
- découvrir les relations
- découvrir l’état
- découvrir les requirements
- découvrir les garanties
- signaler les zones non accessibles
- signaler les données non observables
- produire un résultat déterministe
Invariant :
NOT OBSERVED
≠
DOES NOT EXIST
Représenter explicitement :
complete
partial
failed
Exemple :
discovery:
status: partial
unknowns:
- scope: network
reason: permission-denied
- scope: identity
reason: unsupportedUn plugin ne doit jamais transformer un échec d’observation en absence de ressource.
Permettre de sérialiser le modèle canonique en YAML.
Exemple :
apiVersion: platform.factory/v1
kind: ImportedEnvironment
metadata:
name: production
discovery:
status: complete
resources:
- id: app
kind: container-workload
source:
plugin: plugin-a
nativeType: workload
nativeID: app-001
requirements:
- capability: runtime.container
required: true
- capability: network.private
required: true
graph:
edges:
- from: ingress
to: app
relation: routes-to
required: trueLe YAML doit être :
- déterministe
- canonique
- diffable
- versionné
- validable
- sans secrets
- indépendant des plugins target
Pour les gros environnements, permettre :
environment/
├── environment.yaml
├── resources/
│ ├── compute.yaml
│ ├── workloads.yaml
│ ├── networking.yaml
│ ├── storage.yaml
│ ├── identities.yaml
│ └── services.yaml
├── graph.yaml
├── compatibility.yaml
└── migration-plan.yaml
Le manifest principal doit contenir les digests des documents référencés.
- chemins relatifs uniquement
- protection path traversal
- digest de chaque document
- ordre stable
- validation à la lecture
Deux niveaux.
Is the document structurally valid?
Does the represented system make sense?
Vérifier :
- IDs uniques
- références existantes
- graphe cohérent
- capabilities valides
- requirements cohérents
- digests valides
- aucune donnée secrète
- versions supportées
- états cohérents
Les plugins doivent décrire :
WHAT IS REQUIRED
jamais :
WHO MUST IMPLEMENT IT
Exemple :
requirements:
- capability: runtime.vm.create
required: true
- capability: storage.block.import
required: true
- capability: network.configure
required: trueInterdit :
plugin: plugin-bdans un requirement métier.
Chaque ressource doit être classée :
DIRECT
ADAPTABLE
DEGRADED
UNSUPPORTED
Créer :
type Compatibility string
const (
CompatibilityDirect Compatibility = "direct"
CompatibilityAdaptable Compatibility = "adaptable"
CompatibilityDegraded Compatibility = "degraded"
CompatibilityUnsupported Compatibility = "unsupported"
)Aucune ressource ne doit disparaître silencieusement.
Créer :
type CompatibilityGap struct {
ResourceID string
Requirement string
Status Compatibility
Reason string
LostGuarantee string
RequiresApproval bool
}Exemple :
compatibility:
status: degraded
lostGuarantees:
- high-availability
reason: >
Target environment does not expose the required
redundancy capability.
requiresApproval: trueCréer ou compléter :
type MigrationStep struct {
ID string
Requirements []Requirement
SourceResource string
DependsOn []string
OperationID string
}type MigrationPlan struct {
Version string
Resources []Resource
Graph []DependencyEdge
Steps []MigrationStep
Gaps []CompatibilityGap
Unknowns []UnknownObservation
Digest string
}Invariant :
MIGRATION PLAN
MUST NOT CONTAIN
TARGET PLUGIN NAMES
Garantir :
same canonical input
→ same MigrationPlan
- ordre stable
- IDs stables
- sérialisation canonique
- digest du plan
- aucune timestamp non nécessaire
- aucune dépendance à l’ordre de découverte
Créer ou compléter :
internal/app/migration/
Responsabilités :
- charger le modèle canonique
- valider
- construire ou charger le MigrationPlan
- résoudre les capabilities
- sélectionner les plugins compatibles
- vérifier la confiance
- démarrer les plugins
- propager TraceID
- attribuer OperationID
- gérer le DAG
- gérer retries
- observer après mutation
- vérifier la convergence
- produire provenance
Le host est le seul orchestrateur.
Ajouter explicitement dans internal/archtest :
PLUGIN
MUST NOT IMPORT
ANOTHER PLUGIN
et :
EXTERNAL PLUGIN
MUST NOT IMPORT
internal/...
Le host doit être la seule couche connaissant plusieurs plugins.
Un plugin source doit pouvoir fonctionner même sans aucun target plugin installé.
Il doit toujours pouvoir, si ses capabilities le permettent :
discover
inspect
normalize
validate
Tester explicitement ce cas.
Un plugin capable de matérialisation reçoit :
canonical resource
+
requirements
+
OperationID
+
TraceID
Puis :
plan native operation
→ apply
→ observe
→ normalize observed state
→ verify
Ne jamais considérer le retour de l’API native comme preuve suffisante.
Flux obligatoire :
apply
↓
native system accepts request
↓
observe
↓
normalize
↓
compare with desired
↓
verify
Invariant :
REQUEST ACCEPTED
≠
DESIRED STATE VERIFIED
et :
COMMAND SUCCESS
≠
SYSTEM SUCCESS
Lorsque l’état observé diffère de l’état voulu :
desired
↓
observed
↓
difference
↓
action
↓
observe again
Le système doit :
- converger ;
- réduire la différence ;
- ou produire une erreur terminale explicite.
Éviter les retries infinis sans progression.
Un même plugin peut exposer :
discover
inspect
export
et :
import
apply
observe
verify
Le host doit traiter chaque capability indépendamment.
Ne jamais considérer :
plugin supports discover
comme preuve qu’il supporte :
apply
Ajouter :
Native A
↓
Plugin A
↓
Canonical
↓
Plugin B
↓
Native B
↓
Plugin B discover
↓
Canonical
Comparer :
required guarantees before
vs
observed guarantees after
Ne pas exiger une égalité byte-for-byte.
Comparer les propriétés nécessaires.
Tester :
- CPU
- mémoire
- architecture
- firmware
- disks
- stockage
- réseau
- ports
- persistence
- health
- identité
- secrets requirements
- availability
- isolation
- durability
Toute différence non acceptable doit produire un CompatibilityGap.
Pour les plugins manipulant des artefacts :
native artifact
↓
plugin export
↓
portable artifact
↓
host verification
↓
plugin import
Le host doit vérifier :
- digest ;
- taille ;
- format ;
- structure ;
- provenance.
Invariant :
PLUGIN OUTPUT
≠
TRUSTED ARTIFACT
Séparer les scopes.
Discovery Credentials
→ READ ONLY
Export Credentials
→ restricted source mutation
Apply Credentials
→ target mutation
Un plugin bidirectionnel ne doit pas demander par défaut des credentials omnipotents.
Le jeu de permissions doit dépendre de l’opération.
- jamais dans YAML
- jamais dans MigrationPlan
- jamais dans logs
- jamais dans provenance
- jamais dans cache plaintext
- jamais dans diagnostics
- références uniquement lorsque possible
Le target doit résoudre ou injecter les secrets selon les capabilities disponibles.
Propager :
CLI
↓
migration host
↓
source plugin
↓
artifact operations
↓
target plugin
↓
native environment
↓
verification
↓
provenance
Un workflow complet doit être retraçable.
Toute mutation doit utiliser :
TraceID
OperationID
Invariant :
same OperationID
→ no duplicate logical effect
Tester :
- duplicate call
- duplicate concurrent call
- retry
- timeout
- crash
- reconnect
- indeterminate operation
- reconciliation
Réutiliser les journaux existants.
Ne pas créer un troisième mécanisme.
Vérifier la distinction entre :
in-memory journal
et :
persistent operation journal
Ne pas déclarer une opération crash-safe si son état n’est pas persisté.
Un plugin reçoit uniquement :
- filesystem nécessaire ;
- réseau nécessaire ;
- credentials nécessaires ;
- workspace ;
- budgets nécessaires.
Interdit :
- accès hôte arbitraire ;
- credentials d’un autre environnement ;
- runtime socket sans capability explicite ;
- accès direct à un autre plugin.
Si le niveau d’isolation requis n’est pas disponible :
FAIL
sauf policy explicite autorisant une dégradation.
Inclure :
- source plugin ID
- source plugin digest
- target plugin ID
- target plugin digest
- canonical graph digest
- MigrationPlan digest
- source resource IDs
- target resource IDs
- artifact digests
- transformations
- compatibility gaps
- capabilities demandées
- capabilities résolues
- capabilities vérifiées
- TraceID
- OperationIDs
- observations
- verification results
- final state
Invariant :
PROVENANCE
=
WHAT ACTUALLY HAPPENED
Prévoir une UX générique.
pf migrate discover \
--plugin plugin-aPuis :
pf migrate validate environment/Puis :
pf migrate inspect environment/Puis :
pf migrate plan \
--from plugin-a \
--to plugin-bPuis :
pf migrate apply migration-plan.yamlLes noms servent ici à la sélection utilisateur explicite.
La logique métier du plan reste basée sur les capabilities.
Permettre également :
pf migrate plan \
--from plugin-a \
--target autoLe host :
requirements
↓
Registry
↓
compatible plugins
↓
verified capabilities
↓
compatibility score
↓
selected target
La décision doit être explicable.
Les opérations suivantes doivent pouvoir être sans mutation :
discover
inspect
validate
plan
compatibility
Invariant :
PLAN
≠
APPLY
Aucun plan ne doit provoquer de mutation cachée.
Chaque plugin bidirectionnel doit passer une suite commune.
- empty environment
- normal environment
- partial discovery
- permissions denied
- malformed native data
- pagination
- cancellation
- timeout
- create
- update
- duplicate OperationID
- timeout
- partial success
- native rejection
- observe after apply
- verify
Tester :
Plugin A works without Plugin B
Plugin B works without Plugin A
Plugin A never imports Plugin B
Plugin B never imports Plugin A
Cas :
- aucune implémentation
- une implémentation
- plusieurs implémentations
- capability déclarée mais indisponible
- plugin non vérifié
- plateforme incompatible
- permissions insuffisantes
- target degraded
Créer des fixtures génériques :
fixture A
↓
Plugin A normalize
↓
Canonical
↓
Fake Plugin B apply
↓
Fake Plugin B discover
↓
Canonical
Comparer les requirements et garanties.
Toute perte doit être explicitement déclarée.
Injecter :
- source plugin crash
- target plugin crash
- host crash
- network failure
- partial artifact
- partial mutation
- timeout
- disk full
- verification failure
- stale observation
- duplicate operation
Invariant :
FAILURE
MUST NEVER BECOME
FALSE SUCCESS
Priorités :
- canonical model parser
- YAML
- graph
- MigrationPlan
- plugin messages
- compatibility data
- artifact metadata
- provider-native normalization inputs
Toute découverte de crash devient regression test.
Ajouter :
PLUGIN MUST NOT IMPORT ANOTHER PLUGIN
PLUGIN MUST NOT IMPORT internal/...
pour les modules externes.
api/migration MUST NOT IMPORT internal/...
sdk/migration MUST NOT IMPORT internal/...
cmd/platform-factory MUST NOT IMPLEMENT PLUGIN-SPECIFIC DOMAIN LOGIC
L’architecture test doit fail closed.
native
→ plugin
→ canonical
- Resource
- Requirements
- DependencyEdge
- Compatibility
- UnknownObservation
- validation
- serialization
plugin
→ discover
→ normalize
→ canonical graph
- RPC
- capability
- TraceID
- tests
- partial discovery
canonical graph
→ compatibility
→ requirements
→ DAG
- deterministic steps
- OperationIDs
- digest
- no plugin names
- tests
MigrationPlan
→ Registry
→ verified target plugin
- candidate resolution
- capability verification
- compatibility
- explainable selection
canonical
→ plugin
→ native
- apply
- observe
- normalize
- verify
- idempotence
- provenance
Faire fonctionner un plugin dans les deux directions :
Native
↕
Plugin
↕
Canonical
- discover
- inspect
- export
- import
- apply
- observe
- verify
Démontrer :
Plugin A
↓
Canonical
↓
Platform Factory
↓
Plugin B
avec :
- discovery
- graph
- validation
- plan
- capability resolution
- apply
- observe
- verify
- provenance
Démontrer :
Plugin B
↓
Canonical
↓
Platform Factory
↓
Plugin A
sans introduire de code spécifique à la paire A/B.
Ajouter un Plugin C.
Vérifier que :
A ↔ C
B ↔ C
devient possible sans modifier A ou B.
Meine Graal est atteint lorsque l’ajout d’un nouveau plugin compatible ne nécessite aucune modification spécifique aux plugins déjà présents.
Test :
Add Plugin X
sans modifier :
Plugin A
Plugin B
Plugin C
et obtenir automatiquement, lorsque les capabilities le permettent :
X ↔ A
X ↔ B
X ↔ C
La propriété recherchée est :
COST OF ADDING A PLUGIN
≈ O(1)
et non :
COST OF ADDING A PLUGIN
≈ NUMBER OF EXISTING PLUGINS
L’évolution ne nécessite pas une réécriture du projet.
Les fondations existent déjà :
plugin protocol ✓
plugin Registry ✓
capabilities ✓
TraceID ✓
OperationID ✓
provenance ✓
architecture tests ✓
runtime abstractions ✓
0.5 – 1 jour
- canonical migration types
- bidirectional capabilities
- compatibility
- tests architecture
1 – 2 jours
- source plugin
- target resolution
- MigrationPlan
- apply
- observe-after-apply
- verification
1 – 2 jours
- discovery
- normalization
- apply contract
- tests
2 – 4 jours
- discover
- canonicalize
- plan
- resolve
- apply
- observe
- verify
1 – 2 jours
- A → B
- B → A
- fault injection
- provenance
2 – 3 jours
5 – 10 jours
3 – 6 semaines
selon :
- profondeur des APIs natives ;
- stockage ;
- réseau ;
- sécurité ;
- conversion d’artefacts ;
- edge cases ;
- rollback ;
- tests adversariaux.
Le système de plugins bidirectionnels est considéré terminé lorsque :
- un plugin peut découvrir son environnement
- discovery peut être read-only
- un plugin peut produire le modèle canonique
- le modèle canonique est déterministe
- le graphe de dépendances est explicite
- les observations inconnues restent inconnues
- le MigrationPlan est indépendant des plugins
- le host résout les capabilities
- les capabilities sont vérifiées
- un plugin peut matérialiser un modèle canonique
- apply est idempotent
- observe-after-apply est obligatoire
- la convergence est vérifiée
- les pertes de garanties sont explicites
- round-trip validation fonctionne
- TraceID est propagé
- OperationID protège les mutations
- provenance décrit le workflow réel
- aucun plugin n’importe un autre plugin
- aucun nouveau framework parallèle n’a été introduit
- architecture tests passent
-
make verifypasse -
make release-checkpasse
NATIVE ENVIRONMENT
↓
PLUGIN
↓
OBSERVE
↓
CANONICAL MODEL
↓
VALIDATE
↓
PLAN
↓
PLATFORM FACTORY
↓
RESOLVE CAPABILITIES
↓
PLUGIN
↓
APPLY
↓
OBSERVE
↓
VERIFY
↓
PROVENANCE
Et toujours :
PLUGIN → CAPABILITY
jamais :
PLUGIN → PLUGIN
Le plugin connaît son monde.
Platform Factory connaît le modèle, les règles, les capabilities et l’orchestration.
Aucun plugin n’a besoin de connaître l’existence des autres.
© 2026 CYPT71
platform-factory
Core
- Architecture and OCI Layout
- Next-generation Architecture
- Architecture Decision Records
- Security Model
- Threat Model and Residual Risks
- Independent Security Review Process
- CLI Reference
- Project Configuration and Dependency Freezing
- mTLS Configuration
- Meine Graal
CI/CD
Running an image
- Production Adoption Guide
- Dockerfile Consumer
- Local Dev (Podman/macOS)
- MicroVM Support
- MicroVM Administration
- Large-image streaming
Operating