Conceptos centrales
Objetos
Sección titulada «Objetos»| Concepto | En una frase |
|---|---|
| Workbook | Contenedor de trabajo (≠ archivo). Agrupa tablas, sheets, versiones y políticas |
| Source | El archivo original subido (immutable). auto (todo automático) / staged (control explícito: analyze → corregir el parse-spec → materialize) |
| Table | Dataset tipado, con ID de fila y versionado. El objeto principal del agente. Hay base (editable) y derived (salida de un transform) |
| Transform | Plantilla SQL (Jinja2) / Python. Liga {{ arg }} a las tablas de entrada vía args y produce un artifact de salida. La unidad del lineage |
| Sheet | Composición de presentación sin datos propios. Sus blocks referencian tablas (n:m) y render las compone en un xlsx |
| Chart | Chart creado por el agente. Tiene config y recipe (la herramienta y los parámetros con que se generó) |
| Version | versions.commit(label) = etiqueta inmutable sobre un snapshot. revert restaura las tablas derivadas con el mecanismo de snapshots (re-ejecución del DAG) — las ediciones de filas de las tablas base se gestionan en el historial del log de edits |
| Job | Handle de una operación asíncrona (p. ej. upload con async=true). jobs.wait() o el webhook job.completed |
| Workspace | Objeto frontera (miembros, facturación, gobernanza). Un desarrollador puede administrar varios workspaces con una Account API key |
Edición de filas y bloqueo optimista
Sección titulada «Edición de filas y bloqueo optimista»Toda escritura exige expected_version (el etag de la tabla). Si no coincide: 409 — el SDK lanza ConflictError. No hay reintento automático (para no sobrescribir en silencio una edición concurrente): el contrato es releer (rows() devuelve edit_version) → reaplicar → reintentar.
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"],)Idempotencia
Sección titulada «Idempotencia»El SDK adjunta automáticamente Idempotency-Key a toda llamada de mutación (la misma clave + el mismo body reproducen la respuesta original). Un reintento de red no aplica la operación dos veces. Si llamas al HTTP directamente, agrega el header por tu cuenta.
Modelo de promoción (el raw no desaparece en silencio)
Sección titulada «Modelo de promoción (el raw no desaparece en silencio)»La ingesta auto construye las tablas estructuradas de D2B a partir de una copia raw fiel de cada hoja. Las tablas estructuradas toman el nombre del archivo y las tablas raw se degradan a state=archived (el registro y el lineage permanecen). Con tables.lineage() puedes remontarte hasta las tablas raw y, si hace falta, rematerializar la hoja original con tables.unarchive(). Con structuring=defer las tablas raw aterrizan primero y la misma promoción ocurre cuando termina la estructuración; si para entonces habías creado derivados sobre una tabla raw, la promoción se pospone automáticamente (no rompe lo que hay aguas abajo).
Frescura (staleness)
Sección titulada «Frescura (staleness)»Las escrituras interactivas, como editar filas, no recalculan de inmediato las tablas derivadas aguas abajo: las marcan como stale. Se detecta en freshness: {stale, stale_since} de GET .../tables/{name}, y POST /workbooks/{id}/recompute (MCP recompute_stale) recalcula todo junto en orden de dependencias. La ejecución de un transform propaga de forma eager (la salida siempre está fresca).
Gobernanza
Sección titulada «Gobernanza»Las políticas por etiqueta de columna × rol (mask / deny) se fuerzan en la capa de datos. Las columnas enmascaradas vuelven como NULL tipado y se anuncian en masked_columns. Puedes hacer un dry-run previo con GET .../tables/{name}/access. La misma política aplica a export, profile, MCP e incluso al preview del archivo crudo: no hay rutas para esquivarla (en un workbook con gobernanza, el preview / revise de bytes crudos se rechaza).
JSON Schema de fila (para constrained decoding)
Sección titulada «JSON Schema de fila (para constrained decoding)»Un OpenAPI estático no puede tipar el contenido de las tablas (la forma de la fila depende de los datos). Por eso puedes obtener en tiempo de ejecución el “JSON Schema de una fila” de cada tabla:
GET /api/v1/workbooks/{wb}/tables/{name}/schema?format=json-schemaEn MCP, get_schema(..., include_json_schema=true). El schema devuelto se genera desde el conjunto de columnas que queda tras aplicar las políticas (las columnas deny no aparecen), con additionalProperties: false, todas las celdas nullable y __d2b_row_id como “omitido = insert / presente = update”. Un harness de agente puede usarlo para restringir la generación del payload de upsert_rows (constrained decoding).
Historial
Sección titulada «Historial»- snapshot: commit inmutable.
POST /snapshots/POST /snapshots/{id}/restore - version: un nombre sobre un snapshot (
POST /versions,POST /versions/{label}/revert) - op log: registra toda mutación en orden (
GET /ops). Un op de filas se revierte conPOST /ops/{id}/undo(el historial es append-only) - branch / merge: con
record_branch=trueenPOST /exportse congelan las filas del momento de exportar, y el archivo editado se reincorpora conPOST /tables/{name}/mergecomo 3-way merge a nivel de celda con el ID de fila como clave. Las celdas cambiadas en ambos lados van a la cola de conflicts