Architecture Decision Records — Index¶
Per-file ADRs migrated from the monolithic documentation/ADR.md
during Phase 0 of issue #593 on 2026-04-23.
Backfilled ADRs (2026-04-24) — ADR-46, 47, 48 were referenced in the codebase (TUNING_PROTOCOL, FILTER_FUNNEL, TRAINING_PIPELINE, ML Platform design) since Sprint 10–11 but had never been authored as standalone ADRs. Reconstructed from those references + the code they describe. The header comment in each of those files flags them as backfilled.
Reserved / unassigned numbers: 0049, 0050, 0051, 0053, 0072, 0073, 0074, 0075, 0078. Available for future ADRs — do NOT re-number existing ADRs to fill gaps (invariants elsewhere in the repo cite them by number). 0078 is reserved for the IDP framework choice (stub referenced in CVN-N012-EA-S01 plan dossier ; formal ADR lands in CVN-N012-EA-S04).
New ADRs: use documentation/templates/TEMPLATE_adr.md and the next available number (current max: 0089 → next 0090).
Index¶
| # | Title | File |
|---|---|---|
| 0001 | ZenML OSS, pas Pro | 0001-zenml-oss-pas-pro.md |
| 0002 | Séparation Discovery / Promotion | 0002-separation-discovery-promotion.md |
| 0003 | Build ≠ Deploy | 0003-build-deploy.md |
| 0004 | Cache Policy explicite par step | 0004-cache-policy-explicite-par-step.md |
| 0005 | NannyML CBPE est un signal secondaire | 0005-nannyml-cbpe-est-un-signal-secondaire.md |
| 0006 | Validation OHLCV obligatoire | 0006-validation-ohlcv-obligatoire.md |
| 0007 | Idempotence des mutations | 0007-idempotence-des-mutations.md |
| 0008 | Logging exhaustif des signaux | 0008-logging-exhaustif-des-signaux.md |
| 0009 | Drift monitoring | 0009-drift-monitoring.md |
| 0010 | Configuration PTE versionnée | 0010-configuration-pte-versionnee.md |
| 0011 | Airflow = UI opérateur, ZenML = backend pipeline | 0011-airflow-ui-operateur-zenml-backend-pipeline.md |
| 0012 | ZenML Airflow Orchestrator natif | 0012-zenml-airflow-orchestrator-natif.md |
| 0013 | DAGs publiés via Git | 0013-dags-publies-via-git.md |
| 0014 | Le testing DOIT estimer la généralisation, pas la performance locale récente | 0014-le-testing-doit-estimer-la-generalisation-pas-la-performance.md |
| 0015 | Les seuils de décision DOIVENT être calibrés out-of-sample | 0015-les-seuils-de-decision-doivent-etre-calibres-out-of-sample.md |
| 0016 | Screening et testing DOIVENT partager la même sémantique de labels | 0016-screening-et-testing-doivent-partager-la-meme-semantique-de-.md |
| 0017 | Les optimisations de vitesse NE DOIVENT PAS altérer la sémantique statistique | 0017-les-optimisations-de-vitesse-ne-doivent-pas-alterer-la-seman.md |
| 0018 | Les DAGs générés sont manual-only (pas de schedule) | 0018-les-dags-generes-sont-manual-only-pas-de-schedule.md |
| 0019 | Le launcher est l'autorité unique d'exécution | 0019-le-launcher-est-l-autorite-unique-d-execution.md |
| 0020 | Pas de cleanup post-création de DagRuns | 0020-pas-de-cleanup-post-creation-de-dagruns.md |
| 0021 | La sémantique du DAG DOIT correspondre à l'intention d'exécution | 0021-la-semantique-du-dag-doit-correspondre-a-l-intention-d-execu.md |
| 0022 | Les DAGs générés sont créés paused par défaut | 0022-les-dags-generes-sont-crees-paused-par-defaut.md |
| 0023 | Feature retrieval must be version-pinned (fail-fast) | 0023-feature-retrieval-must-be-version-pinned-fail-fast.md |
| 0024 | Le feature set fait partie du contrat modèle | 0024-le-feature-set-fait-partie-du-contrat-modele.md |
| 0025 | Pas de fallback silencieux dans les pipelines ML | 0025-pas-de-fallback-silencieux-dans-les-pipelines-ml.md |
| 0026 | Grafana comme point d'entrée unique | 0026-grafana-comme-point-d-entree-unique.md |
| 0027 | Comparaison intra-crypto uniquement | 0027-comparaison-intra-crypto-uniquement.md |
| 0028 | Classification binaire (BUY/HOLD) assumée | 0028-classification-binaire-buy-hold-assumee.md |
| 0029 | Baseline naïve obligatoire pour interpréter le ML | 0029-baseline-naive-obligatoire-pour-interpreter-le-ml.md |
| 0030 | Logs structurés comme interface stable (CORRELATION DATA) | 0030-logs-structures-comme-interface-stable-correlation-data.md |
| 0031 | Logging unifié via Python logging, interdiction de print() dans les pipelines | 0031-logging-unifie-via-python-logging-interdiction-de-print-dans.md |
| 0032 | Les événements métier utilisent le format structuré event=name key=value | 0032-les-evenements-metier-utilisent-le-format-structure-event-na.md |
| 0033 | Catalogue fermé des événements de pipeline | 0033-catalogue-ferme-des-evenements-de-pipeline.md |
| 0034 | Séparation lisibilité humaine et parsabilité machine | 0034-separation-lisibilite-humaine-et-parsabilite-machine.md |
| 0035 | Pas de passage en DEBUG sans résumé INFO | 0035-pas-de-passage-en-debug-sans-resume-info.md |
| 0036 | Filtrage centralisé des loggers tiers non actionnables | 0036-filtrage-centralise-des-loggers-tiers-non-actionnables.md |
| 0037 | Budget qualité des logs mesurable | 0037-budget-qualite-des-logs-mesurable.md |
| 0038 | Champs canoniques, golden fields, séparation status/code | 0038-champs-canoniques-golden-fields-separation-status-code.md |
| 0039 | Runtime standalone, API façade | 0039-runtime-standalone-api-facade.md |
| 0040 | Paper et live partagent le même kernel | 0040-paper-et-live-partagent-le-meme-kernel.md |
| 0041 | Sessions event-sourced et recouvrables | 0041-sessions-event-sourced-et-recouvrables.md |
| 0042 | Promotion atomique par crypto | 0042-promotion-atomique-par-crypto.md |
| 0043 | Centralisation de l'observabilité dans le FilterChainExecutor | 0043-centralisation-de-l-observabilite-dans-le-filterchainexecuto.md |
| 0044 | Contrat de données strict pour l'événement signal_funnel | 0044-contrat-de-donnees-strict-pour-l-evenement-signal-funnel.md |
| 0045 | Gate Checks basés sur la densité de signal (Anti-Starvation) | 0045-gate-checks-bases-sur-la-densite-de-signal-anti-starvation.md |
| 0046 | Class balancing obligatoire en training binaire (backfilled 2026-04-24) | 0046-class-balancing-obligatoire.md |
| 0047 | Meta-label model trained on a separate fold (backfilled 2026-04-24) | 0047-meta-label-trained-on-separate-fold.md |
| 0048 | Cost and Kelly are execution-layer, not signal filters (backfilled 2026-04-24) | 0048-cost-and-kelly-at-execution-layer.md |
| 0052 | Auditabilité des sessions du comité d'experts | 0052-auditabilite-des-sessions-du-comite-d-experts.md |
| 0054 | Replace Static CUSUM Filter with Adaptive Event Engine | 0054-replace-static-cusum-filter-with-adaptive-event-engine.md |
| 0055 | Format de présentation des verdicts du comité d'experts | 0055-format-de-presentation-des-verdicts-du-comite-d-experts.md |
| 0056 | Every Pipeline Change Must Be FTF-Testable (A/B Testable by Design) | 0056-every-pipeline-change-must-be-ftf-testable-a-b-testable-by-d.md |
| 0057 | ADRs Must Be Written in English | 0057-adrs-must-be-written-in-english.md |
| 0058 | Every FTF Factor Must Have a Guardrail | 0058-every-ftf-factor-must-have-a-guardrail.md |
| 0059 | All Pipeline Parameters Must Be Stored in PostgreSQL and Editable via Console | 0059-all-pipeline-parameters-must-be-stored-in-postgresql-and-edi.md |
| 0060 | Hot-Path Sequential Pipeline (CandlePipeline Pattern) | 0060-hot-path-sequential-pipeline-candlepipeline-pattern.md |
| 0061 | Batch Dataflow DAG Pattern (Hamilton for Feature Computation) | 0061-batch-dataflow-dag-pattern-hamilton-for-feature-computation.md |
| 0062 | Unified Observability via OpenTelemetry | 0062-unified-observability-via-opentelemetry.md |
| 0063 | FTF Mission Mode is Binary BUY/NOT_BUY; 3-class is Legacy | 0063-ftf-mission-mode-is-binary-buy-not-buy-3-class-is-legacy.md |
| 0064 | FTF Preflight is a First-Class Phase (No External Data-Prep Scripts) | 0064-ftf-preflight-is-a-first-class-phase.md |
| 0065 | Airflow DAG Params Are Run-Level Context Only; Config Lives in ftf_config | 0065-airflow-dag-params-run-level-only.md |
| 0066 | UI Stack: Figma + MkDocs + Structurizr + Mermaid + Storybook + Next.js | 0066-ui-stack.md |
| 0067 | Pluggable Feature-Selection Framework (variance / covariance / FI / SHAP × {global, perfold}) | 0067-pluggable-feature-selection-framework.md |
| 0068 | Expert Committee is the default channel for plan and PR reviews | 0068-expert-committee-as-default-review-channel.md |
| 0069 | OpenProject is the project orchestrator (versions = sprints, Story-pull / version-close discipline) | 0069-openproject-as-project-orchestrator.md |
| 0070 | MLOps readiness plan template is mandatory before any ML production merge | 0070-mlops-readiness-template-mandatory.md |
| 0071 | Trading kill-switch invariants (single PG source, operator-only disengage, fail-safe on connectivity loss) | 0071-trading-kill-switch-invariants.md |
| 0076 | OpenProject is the single source of truth for project memory (extends ADR-69) | 0076-openproject-single-source-of-truth.md |
| 0077 | MkDocs + Structurizr is the single source of truth for project documentation | 0077-mkdocs-structurizr-single-source-of-truth-docs.md |
| 0079 | FTF sweep — results analysis, dossier, and Story closure (8-step workflow + verdict decision tree) | 0079-ftf-sweep-results-analysis-and-story-closure.md |
| 0080 | FTF post-run extraction, dossier, and Story-update mechanics (operator-triggered, single-PR closure, PG = PDF source-of-truth) | 0080-ftf-post-run-extraction-dossier-story-update.md |
| 0081 | Eight-state Story workflow with rituals at every gate (amends ADR-69 state model) | 0081-eight-state-story-workflow-with-rituals.md |
| 0082 | Every committee session MUST be logged as an OpenProject Meeting (amends ADR-68 traceability) | 0082-committee-session-logged-as-op-meeting.md |
| 0083 | Test taxonomy (12 types) + tiered gate hierarchy + canonical performance budgets (companion : documentation/strategy/CVN-N015-test-strategy.md) |
0083-test-taxonomy-and-gate-hierarchy.md |
| 0089 | Training harness as plugin registry (Hamilton) — XGB / LGB / CB unified ; new model = drop a DAG file ; stacking = composition ; opt-in θ-sweep ; CVN_USE_HARNESS flag for gradual cutover | 0089-training-harness-as-plugin-registry.md |
| 0090 | All training hyperparameters live in PG ftf_config (Console-only) — CVN_HPO_<MODEL>_<TF>_<PARAM> naming, canonical resolver fail-fast on missing key, fallback path emits WARN event=hpo_fallback_applied, CI grep gate G5, sharpens ADR-59 |
0090-training-hyperparameters-in-pg-console-only.md |
| 0091 | Console/ftf_config keys a DAG resolves MUST be guaranteed-seeded by an automated, idempotent, insert-missing-only, fail-loud deploy mechanism (Helm post-upgrade hook) — never a manual operator chore ; ADR-90 resolver fail-fast = last-line guard only ; sharpens ADR-59 / ADR-90 | 0091-console-keys-guaranteed-seeded-by-deploy.md |
| 0092 | DAG versioning + operator-visible build provenance (doc_md banner + DAG-list tag + first-task event=dag_loaded ; stamp file written at sync time ; CI guardrail G6) |
0092-dag-versioning-and-build-provenance.md |
| 0095 | Diagnostic Stories follow the canonical 5-artifact template (hub · plan · architecture · runbook · test strategy) + pre-registered methodological invariants (pre-registration, envelope bootstrap, multiple-testing, significance-keyed decision, first-class inconclusive, no-crash, full-run input gate) ; reference = CVN-N001-EI-S05 ; operator-mandated | 0095-diagnostic-story-canonical-template.md |
| 0096 | Every CPU-bound compute pod MUST cap ALL its parallelism (threads + processes) to its cgroup allocation — env-level OMP/OPENBLAS/MKL/NUMEXPR_NUM_THREADS + LOKY_MAX_CPU_COUNT + OMP_WAIT_POLICY=passive at the shared pod entrypoint (unconditional), Downward-API cgroup read, fail-loud startup assertion (incl. undeclared limit), n_jobs≠-1 joint constraint — prevents the OpenMP/BLAS/loky-in-cgroup busy-wait livelock (s42 RCA) ; proposed |
0096-compute-pods-cap-thread-pools-to-cgroup.md |
| 0097 | Every experiment report MUST follow the canonical template (TEMPLATE_experiment_report.md) — front-matter → pre-registration-before-results (§3) → methods → results (effect sizes + CIs) → first-class Threats-to-Validity (§8) → Reproducibility (run ids + commit + calendar windows not indices) → Glossary/References ; reports under documentation/reports/, on the Reports nav ; active |
0097-experiment-reports-follow-canonical-template.md |
| 0098 | A diagnostic/experiment MUST map the deployment regime it informs — metric (measure the deployment objective, or prove the proxy transfers) AND regime (search vs fixed-HP, calibrated vs raw, joint vs marginal) — verified by a framing §0bis read of live config at the PLAN stage, before building/running ; generalises ADR-0093 §0bis up one level ; lesson-of-record S04/s42 (AUC-on-fixed-HP didn't map prod's f1_buy search) ; active |
0098-diagnostic-framing-must-map-deployment-regime.md |
| 0099 | Staged-proof architecture — existence-vs-selection boundary + inter-stage validity chains : a stage proves existence of its property (legit proxy) but MUST NOT select a config that needs the downstream objective (deferred to composition) ; each seam validates the local proxy as a faithful contributor to the economic goal (assumed transfer = defect) ; magnitude-aware sub-objectives (expectancy, not win-rate/F1) ; objective is top-level. ADR-0098 = the diagnostic-seam instance. Durable lesson of the S04 thread ; active |
0099-staged-proof-existence-vs-selection-and-seam-validity.md |
| 0100 | Inter-task data transport standard — object-storage XCom backend, threshold-driven, no bespoke per-task storage. Verified (common-io 1.4.2) : the backend transports XComEncoder-JSON, not arbitrary objects (numpy fails at any size, before the threshold) ; below-threshold = byte-identical to BaseXCom (near-inert flip) ; above-threshold DB holds the path string → rollback = revert + re-trigger. Flip is proof-gated (hardened pre-flight proves provider + S3 conn + effective dotted-section config in-pod ; static+dynamic serialization audit) ; numpy/pandas → registered serializer or pass-by-reference (S02, default Y). CVN-N014-ED-S01 ; proposed |
0100-xcom-objectstorage-transport-standard.md |
| 0101 | Universal Story/Epic documentation standard — the documentary structure (hub · plan [problématisation→DoD→Consolidation] · architecture · runbook · test strategy + epic doc & nav) applies to every substantial work item (objective, non-circular "substantial" trigger) ; artifacts adapted-not-empty (N/A+rationale) per an applicability matrix ; DoD = operational readiness (MLOps where ML/data, process-equivalent otherwise) ; dual enforcement CI + story-advance, advisory→blocking with a waiver contract. Generalizes the doc shape beyond diagnostics ; ADR-0095 keeps the diagnostic method add-ons. CVN-N014-EC-S17 ; proposed |
0101-universal-story-epic-documentation-standard.md |
| 0102 | Tradability decision protocol (durable rules) — pre-registered, falsifiable, budget-bounded protocol producing a defensible verdict (PROMOTE / KILL tuple→family→thesis / single INFEASIBLE) and making downstream optimisation before upstream proof structurally impossible. 9 invariants: named program thesis (instance-free ADR) · switch boundary = separate Epic · strict gate chain Phase 2→6 · verdict taxonomy (no PARK ; INFEASIBLE→substrate/S03-relock/stop only) · anti-snooping (action-policy not a free retry, structural=new tuple, final-holdout one-touch+violation, siloed-exploration source, cost-retune=post-hoc) · budgets decremented · blocking registries (killed-tuple material-equivalence) · E_econ_min≠E_pred_min · joint sign-off + blocking risk-owner veto, no trading authority. Values live in the charter (S02 fills, S03 locks). CVN-N001-EK-S01 ; accepted |
0102-tradability-decision-protocol.md |