CVN-N014-ED-S01 — Fondation : flip global du backend object-storage XCom · hub Story¶
Hub documentaire de la Story S01 (load-bearing) de l'Epic CVN-N014-ED — poser le standard de transport inter-tâches (object-storage XCom backend, piloté par seuil) et le flipper globalement, sans régresser le parc. État live = OpenProject (wp#242, GH #1105, ADR-76).
En une phrase¶
Activer globalement XComObjectStorageBackend — un flip near-inert aujourd'hui (parc JSON-only sous seuil, vérifié in-pod), outillé et prouvé avant d'être déployé, le numpy (s43) étant déféré à S02.
Les documents (dans l'ordre de lecture)¶
| # | Document | Quoi | Pour qui |
|---|---|---|---|
| 1 | Plan dossier | le quoi & pourquoi — Partie I : problématisation (sans jargon), user stories, hypothèses (EN), état de l'art (EN), Definition of Done ; Partie II : decision record A-recon-fondé + design. plan_review PASSED. |
décideur, quant, relecteur |
| 2 | Architecture | le comment c'est construit — mécanique serialize_value (json.dumps avant seuil), flip config-only Helm, 3 outils read-only in-pod, rollback, conformité ADR. |
ingénieur, archi |
| 3 | ADR-0100 — standard de transport | le standard — 5 invariants : JSON-ou-pass-by-réf, pas de store bespoke, flip proof-gated, rollback revert+re-trigger, seuil ≠ sérialisation. | archi, décideur |
| 4 | Runbook flip / kill-switch | le comment on s'en sert — pre-flight, détection, revert + re-trigger, rehearsal obligatoire avant cut-over. | opérateur |
| 5 | Stratégie de tests | le comment on le valide — pyramide ADR-83, table de cas (audit/verdict/read-only), validation système (dogfood in-pod). | dev, QA |
| 6 | MLOps readiness | ADR-70 — monitoring/SLO XCom, rollback, DRI, risque résiduel. | DRI |
| 7 | Cut-over decision dossier | le paquet de cut-over — calibrage seuil, pre-flight, diff Helm, lifecycle, rehearsal kill-switch, vérif post-flip + le RCA du 1er cut-over raté (voir ci-dessous). | opérateur, archi |
| 8 | PR review — committee pr_review PASSED (session 3a73b7e1, OP Meeting #251) |
dossier archivé sur la Meeting. | relecteur |
Outils livrés (branche feat/CVN-N014-ED-S01-xcom-objectstorage-foundation) :
scripts/xcom_serialization_audit.py— audit statique (AST) du parc XCom. Run réel : 129 sites, 0 numpy_suspect, 116 unknown (@taskdicts).scripts/xcom_roundtrip_probe.py— round-trip dynamique in-pod. Run réel : contrôle-flow GREEN, numpy EXPECTED-FAIL (finding).scripts/xcom_flip_preflight.py— pre-flight durci §G.3 (provider + connexion S3 + config dotted-section prouvée in-pod ; S3 write opt-in).- 19 tests unitaires (
tests/unit/test_xcom_*.py).
État¶
In progress (OpenProject) — implémentation des outils + docs + ADR sur la branche. Le flip prod (values-prod.yaml) est volontairement staged, séparé, sur go opérateur + rehearsal kill-switch (gate runbook).
Findings vérifiés in-pod (scheduler réel) :
- enable_xcom_pickling=False effectif → parc XCom JSON-only énumérable.
- XComObjectStorageBackend ne sérialise pas numpy (json.dumps(XComEncoder) avant le seuil) → l'Epic §2 corrigé ; route X non drop-in (S02 : X′/X″/Y préféré).
- sous seuil = octets identiques à BaseXCom → flip near-inert ; au-dessus = DB garde le chemin → kill-switch = revert + re-trigger.
Incident & RCA — 1er cut-over raté (encodage env-var section pointée) · 2026-06-06¶
Le cut-over prod a eu lieu (PR #1118 mergée, deploy SUCCESS) puis s'est révélé cassé mais latent (DAGs
schedule=None, 0 run en vol → aucune perte). Fix-forward (PRfix/CVN-N014-ED-S01-xcom-env-encoding). Détail complet : cut-over decision dossier §RCA.
- Symptôme : backend actif →
AirflowConfigException: section/key [common.io/xcom_objectstorage_path] not found.serialize_valuelit le seuil avant le test de taille → tout write XCom aurait crashé. - Root cause : section pointée encodée avec un point littéral (
AIRFLOW__COMMON.IO__…). Airflow faitsection.replace('.', '_')→ il ne cherche queAIRFLOW__COMMON_IO__…(underscore). Var présente dans l'env mais invisible àconf.get. - Fix (vérifié in-pod avant re-deploy) : encoder
COMMON_IO(underscore). - Pourquoi les gates ont raté : (1) pre-flight testait la présence de l'env var, pas sa résolution
conf.get; (2) le signal (config get-valueen échec post-deploy) a été rationalisé en « quirk CLI » au lieu d'être traité comme le footgun ; (3) le rehearsal bypassait le mapping (import direct + offload manuel). → Gate durci : post-deploy on appelleconf.get('common.io', …), et un échec = STOP/revert, jamais un quirk. - Blast radius : zéro (aucun run exécuté entre le deploy cassé et le fix).
Gates ADR-81 :
- In specification ✅ (plan dossier) · Specified ✅ (plan_review PASSED 8d7efca0 / Meeting #249, 0 blocker) · In progress ✅ (impl en cours, single-WIP override opérateur 2026-06-05).
- → Developed : reste PR ouverte + checks verts + CodeRabbit + pr_review PASSED + docs live.