Um modelo de vídeo aceita mais que uma instrução. Alguns aceitam um primeiro quadro e um último quadro. Alguns aceitam um punhado de imagens de referência. Alguns aceitam um clipe de referência, e então se comportam diferente por causa disso — silenciando sua própria trilha sonora, ou tomando a duração do clipe como duração do resultado. Alguns aceitam um clipe de áudio. Cada modelo desenha esse envelope de um jeito diferente, e a maioria dos nossos só enviava parte dele.
Agora existe um único lugar que descreve o envelope de cada modelo: quantas imagens, se um clipe é permitido e por quantos segundos, se áudio é aceito, se áudio precisa de uma imagem ao lado, se um clipe silencia o som próprio do modelo, se um clipe fixa a duração. Isso foi lido da documentação própria dos provedores, e depois testado nesse mesmo dia com renderizações reais em chaves reais — foi assim que os dois pontos a seguir foram encontrados.
Um arquivo sem extensão
Entregar a um modelo um clipe por link é o caminho óbvio. Isso falha em vários deles, de um jeito muito difícil de adivinhar: o arquivo chega sem extensão, e o modelo valida por extensão, então recusa um mp4 perfeitamente bom por não ser um mp4. Os mesmos bytes enviados inline eram aceitos em todo lugar. Então cada clipe é primeiro recodificado para um formato padrão e enviado inline, com um teto de tamanho acima do qual o caminho de link é usado mesmo assim, com um aviso.
Um nível que ninguém estava recebendo
O segundo estava custando dinheiro aos clientes. Um dos modelos de vídeo não tem nenhum campo de resolução — seu nível de qualidade é ajustado por um campo com outro nome — e a plataforma na frente dele descarta em silêncio campos que não reconhece. Então toda renderização nesse modelo desde que foi adicionado voltava no nível padrão enquanto o cliente tinha pago pelo nível superior. Nada falhava. O vídeo chegava. Simplesmente não era o vídeo cobrado.
O nível agora é derivado da resolução realmente tarifada, e confirmado por sonda.
O Seedance passa para uma via direta
No mesmo período, toda a família Seedance passou do agregador para a API própria do provedor, com o agregador mantido como reserva. Uma linha de modelo, um nome, dois conjuntos de tarifas — e o preço que é cotado para você é o que você paga mesmo quando a via principal falha e a reserva entra, com o livro-razão registrando qual via realmente fez o trabalho, para que nossa própria contabilidade de margem leia a verdade em vez da cotação.
Uma coisa para saber como usuário: quando você anexa um clipe de referência nessa via, o provedor cobra os segundos do clipe em cima dos segundos do resultado. A estimativa no formulário diz isso, e o número cotado antes de executar é o número cobrado.
Encontrado pelo caminho
Três clientes de API não tinham o único atributo que torna visível no nosso container uma classe com nome de provedor. Dois deles eram clientes de texto-para-voz, invisíveis desde o dia em que foram adicionados — motivo pelo qual duas vozes semeadas no catálogo nunca puderam ser realmente servidas. Um teste de reflexão agora faz a compilação falhar na próxima omissão desse tipo, em vez de esperar que alguém repare numa voz que não faz nada.
E a página de busca web que tínhamos lançado no dia anterior respondia 403 em todos os níveis, na web e no mobile. Ela está travada por uma permissão-mãe; as duas sementes de papéis concediam só suas três permissões-filhas, e em lugar nenhum se infere uma mãe a partir de seus filhos. Quatro outras funcionalidades já tinham remendado isso à mão em algum momento. Agora existe uma verificação que percorre a árvore de permissões e falha onde um serviço está travado por uma permissão que nenhum papel possui.