Concepts clés
| Concept | En un mot |
|---|---|
| Workbook | Conteneur de travail (≠ fichier). Regroupe tables, sheets, versions et politiques |
| Source | L’original uploadé (immutable). auto (tout automatique) / staged (contrôle explicite : analyze → correction du parse-spec → materialize) |
| Table | Jeu de données typé, avec ID de ligne, versionné. La cible principale des agents. Deux sortes : base (éditable) et derived (sortie d’un transform) |
| Transform | Template SQL (Jinja2) / Python. Lie {{ arg }} aux tables d’entrée via args et produit un artifact de sortie. L’unité de lineage |
| Sheet | Composition d’affichage sans données propres. Les blocks référencent des tables (n:m), et le render les compose en xlsx |
| Chart | Chart créé par l’agent. Porte une config et une recipe (l’outil et les paramètres de sa génération) |
| Version | versions.commit(label) = label immuable sur un snapshot. Le revert restaure les tables dérivées via le mécanisme de snapshot (ré-exécution du DAG) — les éditions de lignes des tables base sont, elles, historisées côté log d’edits |
| Job | Handle d’une opération asynchrone (upload async=true, etc.). jobs.wait() ou le webhook job.completed |
| Workspace | L’objet frontière (membres, facturation, gouvernance). Un développeur gère plusieurs workspaces avec une Account API key |
Édition de lignes et verrouillage optimiste
Section intitulée « Édition de lignes et verrouillage optimiste »Toute écriture exige expected_version (l’etag de la table). En cas de décalage : 409 — le SDK lève une ConflictError. Aucun retry automatique (pour ne jamais écraser en silence une édition concurrente) : le contrat est relire (rows() renvoie edit_version) → réappliquer → réessayer.
page = client.tables.rows(wb, "sales")client.tables.upsert_rows( wb, "sales", rows=[{"__d2b_row_id": 3, "amount": 999}], # row_id present = update, absent = insert expected_version=page["edit_version"],)Idempotence
Section intitulée « Idempotence »Le SDK ajoute automatiquement Idempotency-Key à tout appel de mutation (même clé + même corps = rejeu de la première réponse). Un retry réseau ne cause jamais de double application. Si vous appelez l’API HTTP directement, ajoutez le header vous-même.
Modèle de promotion (le raw ne disparaît pas en silence)
Section intitulée « Modèle de promotion (le raw ne disparaît pas en silence) »L’ingestion auto construit les tables structurées de D2B à partir d’une copie raw fidèle de chaque feuille. Les tables structurées prennent le nom du fichier et les tables raw sont rétrogradées en state=archived (le registre et le lineage restent). tables.lineage() remonte jusqu’aux tables raw, et tables.unarchive() rematérialise la feuille d’origine au besoin. Avec structuring=defer, les tables raw sont posées d’abord et la même promotion a lieu quand la structuration se termine ; si des dérivés ont été construits sur une table raw entre-temps, la promotion est automatiquement abandonnée (l’aval n’est pas cassé).
Fraîcheur (staleness)
Section intitulée « Fraîcheur (staleness) »Les écritures interactives, comme l’édition de lignes, ne recalculent pas immédiatement les tables dérivées en aval : elles les marquent stale. freshness: {stale, stale_since} de GET .../tables/{name} l’indique, et POST /workbooks/{id}/recompute (MCP recompute_stale) recalcule l’ensemble dans l’ordre des dépendances. L’exécution d’un transform, elle, se propage de façon eager (sa sortie est toujours fraîche).
Gouvernance
Section intitulée « Gouvernance »Les politiques mask / deny (tag de colonne × rôle) sont imposées par la couche de données. Les colonnes masquées reviennent en NULL typés, signalées par masked_columns. GET .../tables/{name}/access permet un dry-run préalable. La même politique vaut pour l’export, le profile, MCP et le preview de fichiers bruts — sans voie de contournement (sur un workbook gouverné, le preview / revise des octets bruts est refusé).
JSON Schema de ligne (pour le constrained decoding)
Section intitulée « JSON Schema de ligne (pour le constrained decoding) »Un OpenAPI statique ne peut pas typer le contenu des tables (la forme d’une ligne dépend des données). Chaque table expose donc à l’exécution le « JSON Schema d’une ligne » :
GET /api/v1/workbooks/{wb}/tables/{name}/schema?format=json-schemaCôté MCP : get_schema(..., include_json_schema=true). Le schema renvoyé est généré depuis l’ensemble des colonnes après application des politiques (les colonnes deny n’y apparaissent pas), avec additionalProperties: false, toutes les cellules nullable, et __d2b_row_id en « omis = insert / présent = update ». Un harnais d’agent peut s’en servir pour contraindre la génération du payload d’upsert_rows (constrained decoding).
Historique
Section intitulée « Historique »- snapshot : commit immuable.
POST /snapshots/POST /snapshots/{id}/restore - version : un nom sur un snapshot (
POST /versions,POST /versions/{label}/revert) - op log : toutes les mutations, enregistrées dans l’ordre (
GET /ops). Un op de ligne s’inverse viaPOST /ops/{id}/undo(l’historique est append-only) - branch / merge :
POST /exportavecrecord_branch=truefige les lignes au moment de l’export, puisPOST /tables/{name}/mergeapplique au fichier édité un 3-way merge cellule par cellule sur la clé d’ID de ligne. Les cellules modifiées des deux côtés partent en queue de conflicts