Aller au contenu

La surface de query (OSL-SQL)

POST /osl/query est l’unique endpoint de consommation. L’analytique structurée, les métriques, le retrieval vectoriel gouverné et la traversée de graphe s’y expriment tous — vous n’apprenez pas cinq surfaces pour lire un domaine.

POST /osl/query
Authorization: Bearer <jwt> # attested delegation chain, see Authentication
Content-Type: application/json

Le body est l’une de trois formes mutuellement exclusives (les mélanger donne 400 E0513) ; toutes trois passent par le même seam gouverné et partagent un seul request_id :

Body Ce que c’est
{ "osql": "…" } OSL-SQL — le dialecte de SQL sémantique (la surface canonique)
{ "sql": "…" } Un SELECT brut en lecture seule sur l’allowlist du tenant (le slice SQL)
{ "metrics": […], "group_by": […], … } Query de métriques façon MetricFlow

osql est un dialecte de SQL sémantique. Il ne nomme que des objets sémantiques — osl.entities.<model> et des colonnes déclarées, ou les fonctions de table RETRIEVE(...) / TRAVERSE(...). Il ne nomme jamais une table physique ni une colonne brute.

Le moteur parse osql (via sqlglot, dialecte trino) et l’abaisse en un IR d’opérateurs fermé — l’échelle déterministe sur laquelle le modèle de gouvernance applique l’enforcement. L’abaissement est total et default-deny : toute construction qui ne s’abaisse pas en un nœud IR connu est refusée.

lower() classe chaque query dans exactement une forme et valide sa grammaire :

SELECT segment, COUNT(*) AS n
FROM osl.entities.Customer
WHERE country IN ('ES','FR','DE')
GROUP BY segment
ORDER BY n DESC
LIMIT 100

S’abaisse en to_trino() → le seam SQL gouverné. Les joins entre entités structurées ne sont autorisés que comme equijoin sur clé scellée (voir plus bas).

Le seul nœud inter-relationnel est un equijoin dont le ON est une égalité scalaire sur une clé d’entité scellée (les entity_key_columns du modèle, ou un champ scalar_indexed d’une facette) sur les deux jambes. Tout autre JOIN … ON400 E0514.

Il n’existe aucune syntaxe qui passe un second argument relationnel à un opérateur de similarité ou de LLM — un join sémantique relation×relation au query time (le non-objectif R3) est une propriété structurelle de la grammaire, pas une blocklist à maintenir.

X JOIN RETRIEVE(...) ON X.k = R.k n’est pas un join relationnel de deux tables physiques. Il s’exécute ainsi :

  1. RETRIEVE (gouverné) → des passages, chacun portant sa clé dénormalisée.
  2. Gate en clair → les valeurs de clé, ou refus (403 E0515).
  3. Préfiltre structurel : … WHERE k IN (<keys>)to_trino → SQL gouverné (la liste IN est construite avec la conversion de littéraux de sqlglot — sûre vis-à-vis des injections).
  4. Hash join in-cell sur la clé scellée, projetant les colonnes de chaque jambe.

Dans la forme RETRIEVE, <op>(col) dans le SELECT est un opérateur de projection (RFC 0004). Ce sont des maps unaires — jamais un join.

Classe Opérateurs S’exécute Si absent
Encoder (déterministe) SIMILARITY, CLASSIFY, TAG, RANK, DEDUP, OUTLIER, CLUSTER Sur les embeddings déjà présents dans le chunk
Decoder (inférence) requiert un LLM EXTRACT, SUMMARIZE, SCORE, GENERATE, COMPLETE Un backend LLM 503 E0521

{ "sql": "<SELECT>" } est un SELECT en lecture seule validé contre l’allowlist du tenant avec le point d’application des politiques appliqué (filtres de lignes + projection depuis le snapshot composé). { "metrics": …, "group_by": … } suit la sémantique MetricFlow. Les deux partagent le même seam gouverné qu’osql.

Code Signification
200 Succès
400 Malformé / hors grammaire (E0511), objet non déclaré (E0512), le body mélange des formes (E0513), JOIN non sur clé scellée (E0514), sql vide (E0246)
403 Deny du PDP (E2101/E2102), clé cross-modal non en clair (E0515), objet hors de l’allowlist (E0512)
422 Valide mais non résoluble — p. ex. MetricFlow pas encore implémenté (E1001)
503 Snapshot du PDP manquant (E2001, fail-closed), op decoder sans backend LLM (E0521)
502 Échec d’exécution de Trino (E0510)

Voir Erreurs et codes de statut pour l’envelope complet.