Aller au contenu

Portabilité vers Snowflake

Objectif du labo : transposer chez le client le travail fait au labo sans le réécrire. Ce document liste ce qui reste identique, ce qui change, et ce qui n'est pas encore outillé.

Ce qui reste identique

  • Noms à trois niveaux : analytics.<schema>.<table> au labo (catalogue Trino, catalogue Polaris, attachement DuckDB), ANALYTICS.<SCHEMA>.<TABLE> chez Snowflake. Les schémas portent les mêmes noms : raw, standardized, semantic, intake, forecast, shared_calendar.
  • Identifiants en minuscules, jamais entre guillemets : le même SQL est valide partout (Snowflake met en majuscules les identifiants non quotés). Référence : https://docs.snowflake.com/en/sql-reference/identifiers-syntax (vérifiée le 2026-10-22).
  • Projet dbt unique (dbt/) : mêmes modèles, mêmes tests, mêmes snapshots, même couche MetricFlow ; quoting désactivé ; schémas nommés tels quels (generate_schema_name).
  • Appels AI_* écrits comme dans Snowflake (noms, arguments, littéraux), accès aux champs par GET(x, 'champ') plutôt que x:champ.
  • Colonnes de preuve (_source_file, _row_number pour METADATA$FILENAME, METADATA$FILE_ROW_NUMBER), confidence_class et schéma de la table forecast.
  • Types : decimal(38, s), timestamp, timestamptz, JSON en chaîne (voir les écarts ci-dessous). Une colonne Iceberg timestamptz se lit chez Snowflake en TIMESTAMP_LTZ, pas en TIMESTAMP_TZ (voir les écarts).

Ce qui change chez le client

Élément Au labo Chez le client Où agir
Adapter dbt dbt-duckdb (cible duckdb, défaut) ou dbt-trino dbt-snowflake : cible snowflake de dbt/profiles.example.yml dbt build --target snowflake avec SNOWFLAKE_ACCOUNT, SNOWFLAKE_USER, SNOWFLAKE_PASSWORD, SNOWFLAKE_ROLE, SNOWFLAKE_WAREHOUSE ; groupe de dépendances snowflake (uv sync --group snowflake)
Base des sources raw Variable raw_database vide : base de la cible (target.database, soit analytics), pour les trois adapters Idem Rien : le SQL compilé lit analytics.raw.* partout
Nom de la base analytics Nom de la base Snowflake du client Voir ci-dessous
Fonctions AI_* en SQL Macros DuckDB de cortex_lab (plugin dbt-duckdb) Fonctions natives Cortex Rien : le SQL est le même ; la macro dbt get dispatche vers GET natif
Fonctions Cortex en Python cortex_lab.cortex, cortex_lab.snowpark snowflake.cortex, snowflake.snowpark.functions CORTEX_BACKEND=snowflake et import par cortex_lab.compat
Modèle d'AI_COMPLETE Alias LiteLLM cortex-complete Nom d'un modèle hébergé par Snowflake CORTEX_COMPLETE_MODEL (lu par ingest/mapping.py) ; dans le SQL, l'argument model
Stages et chargement landing/ sur MinIO, ingest.raw_loader Stage Snowflake, COPY INTO ou Snowpipe Non outillé dans le dépôt (voir plus bas)
Prévision Conteneur forecast lancé par Docker Compose Même image dans Snowpark Container Services, ou modèle custom du Model Registry Voir prevision.md
Lineage Marquez Lineage de Snowsight (page lue le 2026-10-23 : mouvements de données par COPY INTO, CREATE TABLE AS SELECT, INSERT ... SELECT, MERGE, UPDATE et dépendances de vues, Enterprise Edition requise ; le lineage des tables du client reste à constater chez lui) Aucun code à changer côté dbt ; l'émetteur ingest/lineage.py et la CLI ingest.raw_loader sont propres au labo

Renommer la base

Au labo, le nom de la base est porté par plusieurs fichiers. Pour aligner le labo sur le nom réel du client :

  • LAB_DATABASE dans .env (catalogue Polaris créé par polaris-init, attachement DuckDB, profils dbt trino et snowflake) ;
  • le nom du fichier infra/trino/catalog/analytics.properties et sa propriété iceberg.rest-catalog.warehouse=analytics ;
  • les règles infra/trino/rules.json, qui nomment le catalogue analytics en dur ;
  • le catalogue Polaris existant n'est pas renommé par le job : un nouveau catalogue est créé sous le nouveau nom (les tables de l'ancien restent dans l'ancien, à migrer ; la documentation de Polaris sur l'enregistrement de tables dans un autre catalogue n'a pas été lue : point V24, toujours à vérifier).

Côté client, seul LAB_DATABASE (lu par le profil snowflake) compte.

Bascule CORTEX_BACKEND

CORTEX_BACKEND=snowflake python mon_script.py

cortex_lab.compat importe alors snowflake.cortex et snowflake.snowpark.functions au lieu des façades du labo. Ces paquets doivent être installés chez le client (ils ne sont pas des dépendances du labo). Le code client importe toujours depuis cortex_lab.compat.

Écarts à garder en tête

Écart Conséquence chez le client
Casse : identifiants stockés en majuscules chez Snowflake Le SQL non quoté fonctionne ; les noms renvoyés par les métadonnées sont en majuscules
Timestamps en nanosecondes chez Snowflake, microsecondes au labo Comparaisons d'horodatages au-delà de la microseconde différentes. Précision relue le 2026-10-23 (https://docs.snowflake.com/en/user-guide/tables-iceberg-data-types) : sur des tables Iceberg v2 du client, la précision est aussi la microseconde (timestamp vers TIMESTAMP_NTZ(6)), l'écart ne vaut que pour les tables Snowflake natives ; timestamp_ns n'existe qu'en Iceberg v3
timestamptz Iceberg lu en TIMESTAMP_LTZ chez Snowflake La convention du labo timestamp et timestamptz pour TIMESTAMP_NTZ et TIMESTAMP_TZ vaut pour les types natifs ; sur une table Iceberg, Snowflake lit timestamptz en TIMESTAMP_LTZ(6) (même instant, interprété dans le fuseau de la session, pas de fuseau conservé par valeur). Les décimaux decimal(P, S) deviennent NUMBER(P, S), string devient VARCHAR(134217728), list, struct et map deviennent des ARRAY, OBJECT et MAP structurés ; VECTOR n'est pas mentionné par la page (les embeddings du labo sont des listes de flottants) ; VARIANT n'existe qu'en Iceberg v3
GET renvoie VARIANT chez Snowflake, VARCHAR au labo Liste testée des casts portables ci-dessous (B6). Côté Snowflake, le comportement des casts d'un VARIANT reste à constater chez le client
JSON en chaîne au labo Chez Snowflake, une colonne VARIANT se lit sans parse explicite, et GET sur une colonne VARCHAR contenant du JSON peut demander PARSE_JSON (page de GET lue le 2026-10-23 : retour VARIANT pour une entrée semi-structurée, aucune règle de cast sur la page). Le code qui parse une chaîne JSON doit rester valide ; le comportement chez le client reste à constater
AI_COMPLETE forme chaîne seulement au labo Les formes image et objet prompt ne sont pas testées au labo (pages lues le 2026-10-23)
Fonctions AI_* de l'avenant du 2026-10-23 Textes seulement, fenêtre de contexte du modèle local, types de retour des macros, AI_REDACT sans valeur de sécurité : voir cortex-lab.md et contracts.md
snowflake.cortex.sentiment renvoie un float Même forme des deux côtés ; ne pas la confondre avec l'objet d'AI_SENTIMENT
Semantic views MetricFlow seul au labo (décision S6 du 2026-10-25) ; la CREATE SEMANTIC VIEW n'est pas générée ni versionnée. Table de traduction de dbt/models/semantic/semantic_models.yml, voir la sous-section « Traduction de MetricFlow en semantic view » ci-dessous (page https://docs.snowflake.com/en/sql-reference/sql/create-semantic-view, lue le 2026-10-24)
Clone Branches et tags par table au labo ; CREATE [OR REPLACE] {DATABASE \| SCHEMA \| TABLE} ... CLONE <source> [{AT \| BEFORE} (...)] chez Snowflake (https://docs.snowflake.com/en/sql-reference/sql/create-clone, lue le 2026-10-23). Un clone est accessible en écriture et indépendant ; le clone d'une table Iceberg n'existe que si elle est gérée par Snowflake (pas avec un catalogue externe) ; l'historique de chargement n'est pas copié (des fichiers déjà chargés peuvent l'être de nouveau dans le clone)
Time Travel d'une table remplacée Chez Snowflake, CREATE OR REPLACE TABLE supprime puis recrée, l'ancienne table restant récupérable en Time Travel (https://docs.snowflake.com/en/sql-reference/sql/create-table et https://docs.snowflake.com/en/user-guide/data-time-travel, lues le 2026-10-23) ; une table recréée sous le même nom ne restaure pas l'ancienne, et UNDROP échoue si le nom existe. Au labo, la table Iceberg remplacée par dbt-duckdb est supprimée de Polaris et n'est pas récupérable (pas d'UNDROP), et ses fichiers restent dans MinIO (test B7)
Rétention expire_snapshots au labo ; DATA_RETENTION_TIME_IN_DAYS chez Snowflake (https://docs.snowflake.com/en/user-guide/data-time-travel)
CREATE AI FUNCTION absente du labo Écart connu, sans équivalent au labo (page https://docs.snowflake.com/en/sql-reference/sql/create-ai-function, lue le 2026-10-24). La commande est marquée « Preview Feature, Open » et « Available to all accounts ». Elle crée une fonction scalaire dont le corps est une seule expression SQL qui appelle AI_COMPLETE au moins une fois, et peut aussi appeler AI_CLASSIFY, AI_FILTER ou une autre fonction AI définie par l'utilisateur ; AI_AGG est refusée (non scalaire), un corps multi-instructions aussi, RETURNS TABLE(...) n'est pas admis. Seconde forme : FROM EXPERIMENT <experiment> RUN <run> (promotion d'un essai d'optimisation, sans équivalent au labo). Droits : CREATE FUNCTION sur le schéma (pas de privilège dédié), rôle de base SNOWFLAKE.CORTEX_USER à l'appel. La fonction apparaît dans SHOW USER FUNCTIONS et se supprime par DROP FUNCTION. La page rappelle qu'AI_COMPLETE renvoie un VARIANT à caster vers le type déclaré (même écart que pour GET, ci-dessous). Au labo, aucune instruction CREATE AI FUNCTION n'est reconnue par DuckDB : un code client qui en dépend ne s'exécute pas au labo

Surcharges de macros propres au labo

dbt/macros/drop_relation.sql et dbt/macros/intermediate_relation.sql sont préfixées duckdb__ : elles contournent des limites de DuckDB et de Polaris (suppression sans CASCADE, nom intermédiaire unique) et ne s'appliquent ni à dbt-trino ni à dbt-snowflake. Rien à retirer chez le client. Chez Snowflake, une matérialisation table est un CREATE OR REPLACE TABLE ; au labo la table Iceberg est recréée à chaque exécution et son historique de snapshots Iceberg repart de zéro, comme une table recréée chez Snowflake dont l'ancienne version n'est plus la table courante (voir la ligne « Time Travel d'une table remplacée » ci-dessus).

dbt/macros/trino_list_relations.sql est préfixée trino__ : la macro de l'adapter lit system.metadata.materialized_views, catalogue que les règles de Trino refusent à lab_tech. Même requête sans cette jointure (le labo n'a aucune vue matérialisée). Rien à retirer chez le client.

Voie Horizon IRC : moteurs externes sur les tables Iceberg du client

Si le client garde des tables Iceberg gérées par Snowflake et veut les lire ou les écrire depuis Trino, DuckDB ou PyIceberg, il passe par le catalogue REST Iceberg de Horizon, compatible avec l'API de Polaris. Cette voie est documentée ici seulement : le dépôt ne contient aucune configuration qui la cible.

Sources lues le 2026-10-24 : https://docs.snowflake.com/en/user-guide/tables-iceberg-access-using-external-query-engine-snowflake-horizon (page non datée ; la légende du schéma dit lecture et écriture « Generally Available ») et https://docs.snowflake.com/en/release-notes/2026/other/2026-05-26-tables-iceberg-query-using-external-query-engine-snowflake-horizon-writes-ga (écriture GA le 2026-05-26 ; lecture GA le 2026-02-06 d'après la veille, veille-snowflake-2026-10.md).

Élément Ce que dit la page
Point d'accès https://<organisation>-<compte>.snowflakecomputing.com/polaris/api/catalog
Nom du catalogue (warehouse) Le nom de la base Snowflake, pas celui d'un warehouse. Une base créée sans guillemets doit être donnée en majuscules, même si elle a été créée en minuscules. La même règle s'applique aux namespaces et aux tables dans l'exemple de lecture des métadonnées
Namespaces Correspondent aux schémas de la base (règle implicite des exemples : use namespace <schéma>, chemin /<base>/namespaces/<namespace>/tables/<table>)
Authentification OAuth externe ; paire de clés (JWT signé échangé contre un jeton d'accès) ; jeton d'accès programmatique (PAT) ; fédération d'identité de charge de travail (OIDC)
Credentials En-tête X-Iceberg-Access-Delegation: vended-credentials, requis pour le vending
Moteurs cités comme pris en charge Apache Doris, Apache Flink, Apache Spark, Dremio, DuckDB, PyIceberg, StarRocks, Trino
Versions de table Lecture et écriture des tables Iceberg v2 et v3
Écritures non prises en charge depuis un moteur externe CREATE TABLE AS SELECT (CTAS) ; equality deletes ; création de tags et de branches ; rollback vers un snapshot antérieur ; montée de version v2 vers v3 ; CREATE TABLE avec un emplacement de base explicite ; écriture dans les tables dynamiques ; écriture dans les tables Iceberg partagées ; enregistrement de tables ; écriture dans une table convertie avec vended credentials ; écriture dans une table convertie de gérée en externe vers gérée par Snowflake
Stockage Amazon S3, Google Cloud ou Azure dans les régions commerciales ; le stockage compatible S3 hors AWS n'est pas encore pris en charge
Droits (lecture) SELECT sur la table, USAGE (ou autre privilège) sur la base et le schéma ; le rôle propriétaire de la table doit garder USAGE sur le volume externe, sinon les opérations à vended credentials échouent
Droits (écriture DML) SELECT, UPDATE, TRUNCATE, INSERT, DELETE sur la table, plus USAGE sur la base et le schéma ; CREATE ICEBERG TABLE sur le schéma et USAGE sur le volume externe pour créer une table ; CREATE SCHEMA sur la base pour créer un namespace ; OWNERSHIP pour renommer une table ou changer ses colonnes
Facturation 0,5 crédit par million d'appels d'API (Cloud Services), début annoncé au second semestre 2026, « subject to change » ; frais de sortie inter-régions le cas échéant
Tables gérées en externe Accessibles par le même point d'accès quand elles sont dans une base liée à un catalogue (page séparée)

Conséquences pour la transposition (déductions de cette documentation, à vérifier chez le client) :

  • Casse du catalogue : le labo nomme le catalogue analytics en minuscules (iceberg.rest-catalog.warehouse=analytics dans infra/trino/catalog/analytics.properties, warehouse égal à LAB_DATABASE dans lab/iceberg.py et dans l'attachement DuckDB). Vers Horizon, la valeur attendue est ANALYTICS (lu). Les namespaces du labo (raw, standardized...) devraient de même être donnés en majuscules (inféré de l'exemple de la page). La règle « identifiants en minuscules, jamais quotés » reste valable pour le SQL exécuté dans Snowflake ; elle ne suffit pas pour les noms passés à un client REST.
  • CTAS : la matérialisation table de dbt-duckdb et celle de dbt-trino créent la table par CREATE TABLE ... AS SELECT (voir l'avenant du 2026-10-23 de PLAN.md). Exécutées via Horizon, elles relèveraient de l'écriture non prise en charge (inféré). Chez le client, dbt s'exécute avec dbt-snowflake, dans Snowflake, et n'est pas concerné.
  • Tags et branches : lab/maintenance.py (équivalent du clone par branches et tags) ne s'applique pas via Horizon (lu : création de tags et de branches non prise en charge).
  • Écrivains PyIceberg : le chargeur raw et l'écrivain de forecast créent la table sans emplacement explicite puis ajoutent des lignes ; ces opérations n'apparaissent pas dans la liste des écritures refusées (inféré, à vérifier). lab/iceberg.py désactive aujourd'hui le vending (en-tête vide) et passe des clés MinIO statiques : vers Horizon, il faudrait l'en-tête vended-credentials et une authentification Snowflake (PAT, paire de clés, OAuth externe ou fédération d'identité).
  • Stockage du labo : MinIO est un stockage compatible S3 hors AWS, non pris en charge par Horizon (lu). Le labo ne peut donc pas servir de stockage à des tables gérées par Snowflake, et la voie Horizon ne peut pas être testée au labo.

Toute configuration Trino, DuckDB ou PyIceberg qui ciblerait Horizon change le périmètre et passe par un avenant à PLAN.md.

Traduction de MetricFlow en semantic view

Décision S6 du 2026-10-25 : la couche sémantique du labo reste MetricFlow seul (dbt/models/semantic/semantic_models.yml). Aucun générateur, aucune semantic view versionnée et aucun paquet dbt_semantic_view ne sont ajoutés. Si le client utilise des semantic views, Cortex Analyst ou Cortex Agents, la semantic view s'écrit à la main à partir de la table ci-dessous (clauses de https://docs.snowflake.com/en/sql-reference/sql/create-semantic-view, lue le 2026-10-24 ; BCR-2287 du bundle 2026_07 lu le même jour). Le labo ne peut ni créer ni interroger une semantic view : cette traduction n'a jamais été exécutée.

MetricFlow (labo) Semantic view Remarque
Modèle sémantique hotel_daily sur fct_hotel_daily Table logique hotel_daily AS analytics.semantic.fct_hotel_daily PRIMARY KEY (hotel_id, business_date) L'entité primaire hotel_day n'a pas d'expression : la clé se déclare en colonnes
Modèle sémantique hotel sur dim_hotel Table logique hotel AS analytics.semantic.dim_hotel PRIMARY KEY (hotel_id)
Entité étrangère hotel (hotel_id) RELATIONSHIPS (hotel_daily (hotel_id) REFERENCES hotel) La cible doit être en PRIMARY KEY ou UNIQUE
Dimension temporelle business_date, granularité day, agg_time_dimension DIMENSIONS (hotel_daily.business_date AS business_date) La page ne décrit ni dimension temporelle ni granularité : les granularités de MetricFlow (metric_time__month...) deviennent des dimensions explicites (DATE_TRUNC), à écrire une par une
Dimensions city, hotel_name DIMENSIONS (hotel.city AS city, hotel.hotel_name AS hotel_name)
Mesures rooms_available, rooms_sold, room_revenue (sum) et métriques simples *_total METRICS (hotel_daily.rooms_sold_total AS SUM(rooms_sold), ...) BCR-2287 : interroger des FACTS avec des DIMENSIONS n'est plus pris en charge (activé par défaut) ; exposer des métriques plutôt que des faits
Métriques ratio occupancy_rate, adr, revpar hotel_daily.occupancy_rate AS SUM(rooms_sold) / SUM(rooms_available) (même table) Division par zéro à traiter dans l'expression (DIV0 chez Snowflake, à vérifier) ; les métriques dérivées entre tables utilisent USING, en préversion

Points non vérifiés (classe c) : les tables Iceberg comme tables logiques (la page ne les admet ni ne les exclut) ; la procédure SYSTEM$CREATE_SEMANTIC_VIEW_FROM_YAML (spécification YAML propre à Snowflake, page non lue) ; l'existence d'un outil de conversion de MetricFlow (aucun trouvé le 2026-10-24, absence non confirmée). Le paquet dbt Snowflake-Labs/dbt_semantic_view (version 1.0.3 citée par la page dbt, Snowflake seul, corps écrit à la main) deviendrait utile dès que le client confirme l'usage de semantic views ; il ajouterait un code tiers, un accès réseau pour dbt deps et deux définitions des mêmes KPI à garder cohérentes.

Ce qui n'est pas outillé dans le dépôt

  • Cible dbt-snowflake : vérifiée hors connexion le 2026-10-23, avec un compte factice du domaine réservé .invalid et des variables d'environnement SNOWFLAKE_* factices (le test coupe aussi le réseau par des proxys fermés). dbt parse --target snowflake aboutit sans connexion et écrit le manifeste (B1, tests/ingest/test_dbt_snowflake_offline.py). dbt compile --target snowflake --no-introspect --no-populate-cache aboutit aussi sans connexion (B2) : le SQL compilé lit analytics.raw.pms_daily et ne cite aucun identifiant ; la macro get se rend en get(payload, 'k') natif (aucun modèle du projet n'appelle get aujourd'hui, le critère s'est donc vérifié sur un appel en ligne). La validité du SQL compilé pour Snowflake, la compilation avec introspection et l'exécution restent à constater chez le client. Le groupe snowflake (dbt-snowflake==1.12.4) est installé par défaut en développement.
  • Chargement chez le client : ingest/ écrit dans Iceberg via Polaris et lit MinIO. L'équivalent chez Snowflake (stage, COPY INTO, Snowpipe, tables intake) n'a pas d'implémentation dans le dépôt.
  • Prévision dans SPCS : la lecture de standardized (DuckDB sur Polaris) et l'écriture (PyIceberg via Polaris) sont propres au labo ; la spécification de service SPCS n'est pas dans le dépôt (voir prevision.md).
  • Données partagées : shared_calendar simule un partage ; chez le client, la source réelle (partage, Marketplace) est à brancher.
  • Accès par Horizon IRC : aucune configuration de moteur ne cible le catalogue REST de Horizon (voir la section dédiée ci-dessus).

Casts portables de GET (B6)

La macro get renvoie un VARCHAR (chaîne JSON sans guillemets, autres valeurs en texte JSON, NULL pour un null JSON ou une clé absente). Testé au labo dans tests/cortex_lab/test_get_casts.py (DuckDB 2.0.0), sur des valeurs JSON chaîne, nombre, entier, booléen, date, null et clé absente :

Cast de GET(x, 'f') Portable au labo Échoue au labo
varchar toujours (la chaîne, ou le texte JSON de la valeur) jamais
integer, bigint nombre ou chaîne numérique (une fraction est arrondie : 12.5 donne 13) ; bigint pour les grands entiers booléen, texte non numérique, date, entier trop grand pour integer
double, decimal(38, s) nombre ou chaîne numérique booléen, texte non numérique, date
boolean booléen JSON nombre, texte, chaîne numérique
date chaîne ISO AAAA-MM-JJ tout le reste
tous les types NULL pour un null JSON et pour une clé absente

Règle : caster vers le type qui correspond à la valeur JSON ; un cast qui change de nature (booléen vers nombre, texte vers nombre) échoue au labo et n'est pas portable. Le rendu de la macro dbt get par adapter est testé : get(payload, 'k') pour duckdb et snowflake, json_extract_scalar(payload, '$.k') pour trino.

Résultats de la vérification du 2026-10-23

Point Résultat
B1 dbt parse sur snowflake Aboutit hors connexion, manifeste écrit
B2 dbt compile --no-introspect sur snowflake Aboutit sans connexion ; SQL lisant analytics.raw.pms_daily, sans identifiant cité
B3 dbt build sur trino Premier build : passe (après la macro trino__list_relations_without_caching) ; mf query --metrics occupancy_rate aboutit si target: du profil vaut trino (la CLI mf n'a pas d'option --target). Second build : échouait le 2026-10-23 (Trino envoie le DROP TABLE avec purge, Polaris le refusait) ; passe depuis le 2026-10-24 grâce à la propriété de catalogue polaris.config.drop-with-purge.enabled fixée par infra/polaris/init_catalog.py : les tables et seeds sont remplacés, les versions SCD2 fermées
B4 dbt-ol build Aboutit ; jobs et datasets visibles dans Marquez ; espace de noms des datasets duckdb://:memory:, différent de iceberg://analytics du chargeur (écart documenté, pas de changement du code d'émission)
B5 Time Travel FOR TIMESTAMP AS OF inclut le snapshot validé à l'instant exact ; le snapshot parent donne BEFORE(STATEMENT) ; current_timestamp - INTERVAL 'n' SECOND donne AT(OFFSET) (voir socle.md)
B6 casts de GET Liste ci-dessus
B7 fichiers orphelins Les fichiers d'une table remplacée et d'une table supprimée restent dans MinIO (voir exploitation.md)
B11 fenêtre de contexte 32 768 jetons (chat), 2 048 jetons (embeddings) ; Ollama coupe en silence, le labo refuse avant l'appel
B12 embeddings cortex-embed renvoie 1 024 flottants avec la clé du labo
B13 syntaxe DuckDB 2.0.0 Aucun nom ne masque une fonction existante ; => et := sont acceptés pour les paramètres nommés d'une macro
B14 agrégat list(col) dans une macro vers une UDF Arrow à argument VARCHAR[] fonctionne avec GROUP BY, sur une constante et sur une table vide

À vérifier chez le client (classe c)

Ces points exigent le compte Snowflake du client ; ils ne sont pas implémentés au labo.

  • Statut des bundles BCR-2184 et BCR-2358 dans le compte (le titre actuel de BCR-2358 est « Enabled by default »), et valeur de AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR (paramètre absent de la liste de paramètres de session lue).
  • Modèles Cortex disponibles dans la région du client, et inférence inter-régions.
  • Comparaisons et casts de GET sur VARIANT et sur une colonne VARCHAR contenant du JSON (PARSE_JSON éventuellement nécessaire).
  • Compilation avec introspection et exécution de dbt-snowflake, validité du SQL compilé.
  • Lineage Snowsight sur les tables du client (Enterprise Edition).
  • Type des tables Iceberg du client (gérées par Snowflake ou catalogue externe), qui conditionne le clone.
  • Time Travel et UNDROP selon la rétention du compte.
  • Comptes de jetons et réponses réelles des fonctions Cortex ; fenêtres de contexte par modèle ; dimension de multilingual-e5-large et de snowflake-arctic-embed-l-v2.0-8k ; prise en charge de VECTOR dans les tables Iceberg.
  • HistorySource et écrivain Snowflake de la prévision (voir prevision.md).

Points ajoutés après la veille du 2026-10-24 (veille-snowflake-2026-10.md, action P6). Chaque source a été relue le 2026-10-24.

  • Rôles de modèle (BCR-2378) : le contrôle d'accès par rôles de modèle devient le seul mécanisme d'accès aux modèles ; CORTEX_MODELS_ALLOWLIST n'est plus consulté et les modèles d'embedding sont désormais couverts (AI_EMBED, AI_MULTI_EMBED, AI_SIMILARITY, EMBED_TEXT_768, EMBED_TEXT_1024). Bundle 2026_07, « Enabled by default », activation générale annoncée en janvier 2027. À constater : valeur de CORTEX_MODELS_ALLOWLIST (SHOW PARAMETERS LIKE 'CORTEX_MODELS_ALLOWLIST' IN ACCOUNT), présence de l'octroi CORTEX-MODEL-ROLE-ALL à PUBLIC, rôles de modèle accordés aux rôles qui exécutent dbt et la prévision ; tester avec un rôle autre qu'ACCOUNTADMIN, qui a toujours accès à tous les modèles. Source : https://docs.snowflake.com/en/release-notes/bcr-bundles/2026_07/bcr-2378.
  • Inférence inter-régions (BCR-2376) : quand le bundle 2026_06 (« Generally enabled ») s'applique, Snowflake fixe par défaut CORTEX_ENABLED_CROSS_REGION à une valeur limitée au fournisseur et à la géographie du compte (par exemple AWS_EU) ; les comptes qui ont déjà une valeur explicite (y compris DISABLED) et les comptes des secteurs finance, santé, administration, FedRAMP et VPS ne sont pas concernés. À constater : valeur effective du paramètre dans le compte du client, et modèles disponibles dans cette géographie. Source : https://docs.snowflake.com/en/release-notes/bcr-bundles/2026_06/bcr-2376.
  • Compte « inactif » au sens de BCR-2432 : dans le bundle 2026_08 (« Disabled by default »), les fonctions historiques SNOWFLAKE.CORTEX (COMPLETE, TRY_COMPLETE, CLASSIFY_TEXT, TRANSLATE, SENTIMENT, ENTITY_SENTIMENT, PARSE_DOCUMENT, COUNT_TOKENS, SUMMARIZE, EXTRACT_ANSWER, EMBED_TEXT_768, EMBED_TEXT_1024) échouent dans un compte qui n'en a appelé aucune du 9 juillet au 6 octobre 2026 ; un usage postérieur à la publication du bundle ne change pas ce classement. Le module Python snowflake.cortex est concerné, sauf à partir de snowflake-ml-python 2.4.0 qui appelle les fonctions AI_*. À constater : classement du compte du client, et version de snowflake-ml-python installée chez lui. La page ne dit pas comment vérifier l'usage du compte. Source : https://docs.snowflake.com/en/release-notes/bcr-bundles/2026_08/bcr-2432.
  • Privilèges USE AI FUNCTIONS et USE AI FUNCTION <nom> : le privilège de compte USE AI FUNCTIONS est accordé à PUBLIC par défaut (note du 2026-02-20) ; le privilège par fonction USE AI FUNCTION <nom> est GA depuis le 2026-05-13, et un rôle qui détient l'un ou l'autre peut appeler la fonction. À constater : retrait éventuel de USE AI FUNCTIONS à PUBLIC et privilèges par fonction accordés aux rôles qui exécutent dbt, ingest et la prévision (le labo n'a aucun contrôle d'accès par fonction). Sources : https://docs.snowflake.com/en/release-notes/2026/other/2026-02-20-use-ai-functions-privilege, https://docs.snowflake.com/en/release-notes/2026/other/2026-05-13-use-ai-function-per-function-privileges.
  • Modèles legacy : SHOW CORTEX BASE MODELS affiche pour chaque modèle lifecycle_status, legacy_date et eol_date (syntaxe complète non lue). À constater : statut du modèle retenu pour CORTEX_COMPLETE_MODEL et pour les appels AI_COMPLETE du client ; un modèle passé en legacy n'est plus appelable par un compte qui ne l'utilisait pas avant la date (vague du 2026-08-12, d'après la veille). Source : https://docs.snowflake.com/en/user-guide/snowflake-cortex/aisql-regional-availability.
  • Droits après CREATE OR REPLACE (BCR-2433) : dans le bundle 2026_08 (« Disabled by default »), CREATE OR REPLACE recopie les droits de l'objet remplacé, sauf OWNERSHIP, comme si COPY GRANTS était précisé ; concerne tables, vues, vues matérialisées, streams, semantic views, fonctions, procédures et Cortex Agents ; la clause IGNORE GRANTS rétablit l'ancien comportement. Les matérialisations table de dbt-snowflake sont des CREATE OR REPLACE (inféré) : à constater, état du bundle dans le compte et droits observés sur une table recréée par dbt. Source : https://docs.snowflake.com/en/release-notes/bcr-bundles/2026_08/bcr-2433.
  • Version Iceberg des tables du client : Snowflake crée les tables Iceberg en v2 par défaut ; ICEBERG_VERSION_DEFAULT (compte, base, schéma) ou ICEBERG_VERSION = 3 à la création donnent du v3 ; la montée en v3 est définitive ; dbt Projects on Snowflake n'est pas pris en charge sur les tables v3. À constater : version des tables du client et valeur de ICEBERG_VERSION_DEFAULT. Le labo reste en v2. Source : https://docs.snowflake.com/en/user-guide/tables-iceberg-v3-specification-support.

Références

  • Tables Iceberg dans Snowflake : https://docs.snowflake.com/en/user-guide/tables-iceberg (vérifiée le 2026-10-22).
  • Snowpipe : https://docs.snowflake.com/en/user-guide/data-load-snowpipe-intro (vérifiée le 2026-10-22).
  • Snowpark Container Services : https://docs.snowflake.com/en/developer-guide/snowpark-container-services/overview (vérifiée le 2026-10-22).
  • Modèle custom du Model Registry : https://docs.snowflake.com/en/developer-guide/snowflake-ml/model-registry/bring-your-own-model-types (vérifiée le 2026-10-22).
  • Module snowflake.cortex : https://docs.snowflake.com/en/developer-guide/snowpark-ml/reference/latest/cortex (liste et paramètres lus le 2026-10-23, la page répond ; types de retour lus dans le code de snowflake-ml-python 2.6.0).
  • Types Iceberg côté Snowflake : https://docs.snowflake.com/en/user-guide/tables-iceberg-data-types (lue le 2026-10-23).
  • GET : https://docs.snowflake.com/en/sql-reference/functions/get (relue le 2026-10-23).
  • CREATE ... CLONE : https://docs.snowflake.com/en/sql-reference/sql/create-clone (lue le 2026-10-23).
  • Accès des moteurs externes par Horizon IRC : https://docs.snowflake.com/en/user-guide/tables-iceberg-access-using-external-query-engine-snowflake-horizon (lue le 2026-10-24).
  • CREATE AI FUNCTION : https://docs.snowflake.com/en/sql-reference/sql/create-ai-function (lue le 2026-10-24).
  • Iceberg v3 chez Snowflake : https://docs.snowflake.com/en/user-guide/tables-iceberg-v3-specification-support (lue le 2026-10-24).