Storage e artefatos
Mapa de fontes de verdade
| Dado | Fonte de verdade | Quem grava |
|---|---|---|
| snapshots canônicos | filesystem ou S3 de ingestão | job materialize_snapshot |
| séries projetadas para treino | filesystem ou S3 de ingestão | job project_training_series |
| metadados de snapshots e modelos | ClickHouse | API e jobs |
| artefatos treinados | filesystem ou S3 de artefatos | job train_model_candidates |
| runs de treino | MLflow | tracker adapter |
O projeto separa claramente metadado de payload pesado. ClickHouse guarda estado operacional; arquivos e objetos guardam datasets e binários.
Regra arquitetural:
- o control plane persiste estado durável em ClickHouse;
- o data plane persiste snapshots e artefatos em filesystem/S3;
- o control plane referencia metadados do data plane, mas não persiste frames no banco.
Isso deixa claro onde futuras extensões entram:
- feature catalog, snapshot metadata enriquecida e orchestration metadata continuam no control plane;
- materialização, leitura e projeção de features continuam no data plane.
SeriesKeycontinua sendo a identidade compartilhada entre as duas camadas.
Para a lista atual de tabelas ClickHouse e seus contratos de coluna, veja Database tables.
Input path vs snapshot canônico
O input_path recebido pelo comando de treino não vira fonte de treino direta.
Fluxo:
- a API valida e persiste o
input_pathjunto comsource_format(csvouparquet); - o snapshot fica em
processing; - o materializer resolve o arquivo informado sem inferir formato por sufixo;
- o validator central do data plane aplica normalização canônica, tenant scope e regras por série;
- só então o job de materialização grava o snapshot canônico.
Essa separação evita que treino leia fontes sem validação ou dependa de heurística de extensão para decidir como ler o input.
Layout do snapshot canônico
Depois da materialização, o storage canônico recebe:
demand-snapshots/org=<organization_id>/snapshot=<snapshot_id>/data.parquetdemand-snapshots/org=<organization_id>/snapshot=<snapshot_id>/manifest.jsondata.parquet contém a tabela canônica de demanda. manifest.json descreve:
snapshot_idorganization_idrow_countseries_count- lista de
data_file_uris projected_series_data_uri, quando a projeção já rodouprojected_series_index_uri, quando a projeção já rodou
O catalog canônico lê e valida esse manifest antes do treino:
- reaplica o contrato canônico do frame;
row_counteseries_countprecisam bater com o frame canônico carregado.
Depois disso, o restante do fluxo opera sobre DemandSnapshotManifest: o control
enxerga o snapshot já resolvido. A etapa de projeção lê data_file_uris, grava
artefatos derivados por série e atualiza o mesmo manifest com
projected_series_data_uri e projected_series_index_uri.
Isso mantém o contrato do snapshot pequeno e suficiente para detectar deriva óbvia entre manifest e frame carregado, sem transformar o hot path de treino em um pass extra sobre arquivos grandes.
Layout das séries projetadas
project_training_series grava uma visão derivada do snapshot canônico:
demand-snapshots/org=<organization_id>/snapshot=<snapshot_id>/projected/recipe=<recipe_key>/data/demand-snapshots/org=<organization_id>/snapshot=<snapshot_id>/projected/recipe=<recipe_key>/series-index/O dataset projetado é particionado por series_id, que é a identidade textual do
SeriesKey. O índice lista as séries disponíveis e permite que o treino Polars
carregue somente as partições necessárias para cada work item, sem varrer o
snapshot inteiro.
O snapshot canônico continua imutável para o ciclo de treino. A projeção é
derivada da configuração ativa congelada, principalmente de
series_projection_recipe, e por isso fica documentada no manifest em campos
separados.
Artefatos de treino
O treino persiste o payload binário resolvido pela estratégia em um artifact store separado do storage de ingestão.
Em filesystem:
<root>/org=<organization_id>/model_definition=<model_definition_id>/series_kind=<series_kind>/series=<series_id>/grain=<grain>/strategy=<strategy_key>/version=<version>/artifact.binEm S3, a convenção é a mesma, com bucket e prefixo configuráveis.
O que vai para MLflow
MLflow não substitui o artifact store local/S3 usado pelo Atreides. Ele concentra:
- uma sessão lógica por workflow de treino;
- um run pai por série, nomeado a partir do
SeriesKeye de um sufixonanoid; - child runs por candidata/série com parâmetros, métricas, tags pesquisáveis e referência para o artefato persistido;
training_report.jsonnos runs pais de série quando a composição in-process registra o relatório consolidado; esse arquivo reúne perfil da série, candidatas, configuração resolvida, flags de campeã e metadados opcionais de explicação;- empacotamento pyfunc e registry sync do campeão produzido pelo treino.
Na prática:
- o artifact store guarda o payload serializado pela estratégia;
- MLflow guarda histórico operacional, debugging do treino, o modelo empacotado e a referência registrada do campeão;
snapshot_idsegue junto na lineage da instância treinada e nas tags do run.- estado de campeã, auditoria de promoção, fingerprints, métricas de seleção e referências de serving seguem no domínio e na persistência command-side.
Backends locais e remotos
Para demanda:
- local:
DEMAND_STORAGE_BACKEND=filesystem - remoto:
DEMAND_STORAGE_BACKEND=s3
Para artefatos de modelo:
- local:
ARTIFACT_STORE_BACKEND=filesystem - remoto:
ARTIFACT_STORE_BACKEND=s3
Isso permite rodar localmente sem mudar a semântica geral do fluxo.
O que não deve vazar entre camadas
- domínio não conhece path, bucket nem URI;
- o control plane trabalha com repositórios, promotion state e metadata durável;
- o data plane trabalha com frames, snapshots, parquet e validação estrutural;
- adapters resolvem
file://,s3://e clientes concretos.
Essa fronteira é importante para manter treino e promoção testáveis sem infraestrutura real.
Quando usar esta página
Use esta página quando estiver:
- depurando “onde foi parar” um snapshot ou artefato;
- validando a separação entre
input_pathe snapshot canônico; - ajustando variáveis de ambiente de storage local ou S3.