Pular para o conteúdo

Conceitos centrais

ConceitoEm uma frase
WorkbookContêiner de trabalho (≠ arquivo). Agrupa tabelas, sheets, versões e políticas
SourceO arquivo original enviado (immutable). auto (totalmente automático) / staged (controle explícito: analyze → ajuste do parse-spec → materialize)
TableDataset tipado, com row ID e versionado. O objeto principal do agente. Há tabelas base (editáveis) e derived (saída de transforms)
TransformTemplate SQL (Jinja2) / Python. Vincula {{ arg }} às tabelas de entrada via args e produz o artifact de saída. A unidade de lineage
SheetComposition de exibição que não guarda dados. Os blocks referenciam tabelas (n:m) e o render compõe tudo em xlsx
ChartChart criado pelo agente. Guarda config e recipe (a tool e os parâmetros usados na geração)
Versionversions.commit(label) = label imutável apontando para um snapshot. O revert restaura as tabelas derivadas pelo mecanismo de snapshot (re-execução do DAG) — edições de linha em tabelas base são gerenciadas pelo histórico do log de edits
JobHandle de operações assíncronas (upload com async=true etc.). jobs.wait() ou o webhook job.completed
WorkspaceObjeto de fronteira (membros, cobrança, governança). Desenvolvedores podem administrar vários workspaces com uma Account API key

Toda escrita exige expected_version (o etag da tabela). Se estiver defasado, a resposta é 409 — o SDK lança ConflictError. Não há retry automático (para nunca sobrescrever em silêncio uma edição concorrente): o contrato é reler (rows() retorna edit_version) → reaplicar → tentar de novo.

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"],
)

O SDK anexa automaticamente um Idempotency-Key a toda chamada de mutação (mesma chave + mesmo body reproduzem a resposta original). Retries de rede não causam aplicação dupla. Se você chama o HTTP diretamente, adicione o header por conta própria.

Modelo de promoção (o raw nunca some em silêncio)

Seção intitulada “Modelo de promoção (o raw nunca some em silêncio)”

A ingestão auto constrói as tabelas estruturadas do D2B a partir de uma cópia raw fiel de cada planilha. As tabelas estruturadas assumem o nome do arquivo e as tabelas raw são rebaixadas para state=archived (o registro e o lineage permanecem). Com tables.lineage() você volta até as tabelas raw e, se precisar, rematerializa a planilha original com tables.unarchive(). Com structuring=defer as tabelas raw aterrissam primeiro e a mesma promoção acontece quando a estruturação termina; se até lá algo derivado tiver sido criado sobre uma tabela raw, a promoção é adiada automaticamente (nada quebra downstream).

Escritas interativas, como edições de linha, não recalculam imediatamente as tabelas derivadas downstream — elas as marcam como stale. Você vê isso em freshness: {stale, stale_since} no GET .../tables/{name}, e recalcula tudo em ordem de dependência com POST /workbooks/{id}/recompute (MCP recompute_stale). A execução de transforms propaga de forma eager (a saída está sempre fresca).

Políticas por tag de coluna × role (mask / deny) são aplicadas na camada de dados. Colunas mascaradas retornam como NULL tipado, sinalizadas em masked_columns. Dá para fazer um dry-run antecipado com GET .../tables/{name}/access. A mesma política vale para export, profile, MCP e até o preview do arquivo bruto — não há caminho de contorno (em um workbook com governança, preview / revise dos bytes brutos são recusados).

Um OpenAPI estático não consegue tipar o conteúdo das tabelas (a forma da linha depende dos dados). Por isso, o “JSON Schema de uma linha” de cada tabela pode ser obtido em tempo de execução:

GET /api/v1/workbooks/{wb}/tables/{name}/schema?format=json-schema

No MCP, get_schema(..., include_json_schema=true). O schema retornado é gerado a partir do conjunto de colunas já com as políticas aplicadas (colunas deny não aparecem), com additionalProperties: false, todas as células nullable e __d2b_row_id significando “omitido = insert / presente = update”. Um harness de agente pode usá-lo para restringir a geração do payload de upsert_rows (constrained decoding).

  • snapshot: commit imutável. POST /snapshots / POST /snapshots/{id}/restore
  • version: um nome para um snapshot (POST /versions, POST /versions/{label}/revert)
  • op log: registra todas as mutações em ordem (GET /ops). Ops de linha são aplicadas em reverso com POST /ops/{id}/undo (o histórico é append-only)
  • branch / merge: POST /export com record_branch=true congela as linhas no momento do export; o arquivo editado volta por POST /tables/{name}/merge, um 3-way merge célula a célula chaveado por row ID. Células alteradas dos dois lados vão para a fila de conflicts