5

CUM

Como criei um formato de serialização deliberadamente redundante para meus experimentos de contexto longo em LLMs.

Ilustração de um projeto de software

CUM 4.20.69 por dentro: redundância, custo de tokens e recuperação experimental

CUM, abreviação de Catastrophically Uncompressed Markup, nasceu da vontade de explorar, com humor, o custo dos formatos de serialização em contextos longos. Publiquei um encoder que escreve cada valor 69 vezes, acrescenta metadados verbosos e usa cebola e gato como marcas de sincronização. A principal contribuição é tornar executável o contraste entre redundância, custo de tokens e recuperação por maioria. A documentação pública está concentrada no repositório GitHub DominguesM/cum, incluindo README, licença, pacote e artefatos de validação [1].

Há, porém, um experimento técnico legítimo escondido na piada: repetição permite detectar divergências e, sob um modelo de limitações observadas bem definido, recuperar um símbolo por maioria. Termos como “industrial-grade”, nota de robustez 10/10, imunidade a prompt injection, checksum SHA-512 e conformidade forense pertencem à voz satírica do README [1]. Na versão preservada, implementei somente os comportamentos descritos a seguir [2].

Artefato publicado

No repositório, publiquei um encoder CommonJS de 80 linhas, um script de build, README, licença e imagem. package.json declara cum-encode na versão 4.20.69, expõe src/index.js como módulo e dist/index.js como binário [4]. src/build.js não transpila, otimiza nem empacota: cria dist/, copia o fonte byte a byte e aplica modo executável 755 [3]. Assim, biblioteca e CLI executam essencialmente o mesmo programa.

Publiquei apenas a versão 4.20.69, em 19 de novembro de 2025; ela continuava apontada por latest em 24 de julho de 2026 [6]. Incluí seis arquivos no tarball: LICENSE, README, package.json, src/index.js, src/build.js e dist/index.js. Essa distribuição pequena não substitui testes de comportamento nem uma política própria de verificação de integridade.

Publiquei um script npm test, mas ele chama test/test.js, arquivo que não incluí no GitHub nem no pacote. Portanto, “encoder de referência” é uma autodescrição; não publiquei uma suíte que demonstre conformidade, propriedades de recuperação ou compatibilidade entre implementações. Pelo mesmo motivo, a coluna “Parse Time” do README não corresponde a um parser ou protocolo de medição disponível no projeto.

JSON entra, texto CUM sai

JSON, conforme a RFC 8259, serializa um valor composto por objeto, array, número, string, booleano ou null; objetos contêm pares nome/valor e arrays mantêm uma sequência ordenada [7]. Em intercâmbio entre sistemas, o texto deve usar UTF-8. A RFC também permite que parsers imponham limites de tamanho, profundidade, números e strings, uma precaução especialmente importante quando a entrada pode crescer muito.

O CLI do CUM usa JSON.parse, mas depois reduz o domínio aceito:

Renderizando diagrama...

Um array de entrada é processado diretamente. Para qualquer valor que não seja array, o programa chama Object.values; se encontrar propriedades cujo valor é array, escolhe a primeira na ordem de enumeração e descarta as demais. Caso contrário, trata todos os valores como itens. O nome da propriedade não chega à saída: o rootName padrão continua sendo data. A API JavaScript permite fornecer outro nome como segundo argumento, mas o CLI não o faz.

Esse comportamento produz surpresas. Em {"products":[...],"orders":[...]}, orders é ignorado. Em {"id":1,"name":"Ana"}, os itens internos tornam-se 1 e "Ana"; Object.entries(1) não gera campos, enquanto Object.entries("Ana") enumera caracteres com chaves 0, 1 e 2. null no topo causa erro em Object.values(null). Um array contendo null também falha quando o encoder tenta Object.entries(null).

Gramática operacional

Não publiquei arquivo de gramática nem decoder. A forma abaixo é uma descrição compacta da saída de src/index.js, não uma especificação independente:

documento    ::= cabecalho array-inicio objeto* rodape
objeto       ::= objeto-inicio campo* "CUM.OBJECT_END;"
campo        ::= campo-inicio valor{34} valor-sync valor{34}
campo-inicio ::= 'CUM.FIELD key="' chave '" type="' tipo '" repeat=69;'
valor        ::= "CUM.VALUE=" bruto ";"
valor-sync   ::= "CUM.VALUE=" bruto
                 " CUM.SYNC.ONION=🧅 CUM.SYNC.FELINE=🐱;"
tipo         ::= "INT" | "NUM" | "STR"

O contador do laço vai de 0 a 68. SYNC_POSITION vale floor(69 / 2) = 34; por isso o marcador aparece no índice 34, isto é, na 35ª cópia para uma pessoa contando a partir de um. Cada campo tem exatamente 69 ocorrências de CUM.VALUE, das quais uma contém os dois marcadores.

INT é escolhido por Number.isInteger; outros números recebem NUM; todo o restante recebe STR. O parâmetro type passado a emitValue nem sequer é usado. Booleanos, null, arrays e objetos aninhados não têm codificação estrutural própria: a interpolação JavaScript os converte, respectivamente, em textos como true, null, a,b e [object Object]. Strings e chaves não são escapadas. Aspas na chave, quebras de linha, ponto e vírgula ou sequências CUM.OBJECT_END; no valor podem imitar a estrutura.

Logo, a transformação não é injetiva nem reversível em geral. 1.0 já vira o número JavaScript 1 durante JSON.parse; em uma entrada como [{"x":{"a":1}}], o campo x acaba como [object Object]; em [{"x":["a","b"]}], ele vira a,b, indistinguível de outra origem textual. Um parser futuro precisará ou restringir formalmente as entradas ou introduzir escape e comprimento, o que criaria outra versão do formato.

Uso coerente com o código

O caso seguro é um array de objetos rasos com chaves simples e valores escalares sem delimitadores:

npx --yes cum-encode@4.20.69 \
  '[{"id":1,"name":"Laptop","price":3999.9}]'

Como biblioteca, o nome da raiz pode ser preservado explicitamente:

const cumEncode = require("cum-encode");
 
const data = [{ id: 1, name: "Laptop", price: 3999.9 }];
const text = cumEncode(data, "products");
console.log(text);

O início de um campo é CUM.FIELD key="id" type="INT" repeat=69;, seguido por 34 linhas comuns, uma 35ª linha com CUM.SYNC.ONION=🧅 CUM.SYNC.FELINE=🐱 e outras 34 linhas. Ao final, o programa escreve literalmente CUM.CHECKSUM=SHA512-OF-EVERYTHING-ABOVE-REPEATED-420-TIMES;. Nenhum digest é calculado e nada é repetido 420 vezes. Da mesma forma, VALIDATED-CONFORMANT-INSTANCE é texto fixo, não resultado de validação.

Quanto 69 vezes realmente amplia

Se houver NN objetos, FF campos no total e EE itens sem nenhum campo enumerável, a implementação emite:

L=10+2N+70F+E+1N=0L = 10 + 2N + 70F + E + \mathbf{1}_{N=0}

linhas: dez de cabeçalho e rodapé, duas por objeto, uma declaração e 69 valores por campo, mais as linhas vazias produzidas para itens sem campos; o indicador vale um somente quando N=0N=0. No caso usual, com objetos não vazios, os dois últimos termos somem. Há 69F69F cópias de valores e FF linhas de sincronização. Isso não implica amplificação total de exatamente 69 vezes, pois chaves, cabeçalhos, indentação e marcadores também custam bytes.

Para [{"id":1,"name":"Laptop","price":3999.9}], o JSON compacto ocupa 41 bytes. cumEncode produz 5.312 bytes, 5.300 caracteres Unicode e 222 linhas: amplificação de 5312/41=129,565312/41 = 129{,}56 em bytes. O emoji explica a diferença entre caracteres e UTF-8. Com cl100k_base do tiktoken 0.12.0, foram 18 tokens para JSON e 1.929 para CUM, razão de 107,17107{,}17; com o200k_base, 17 e 1.924, razão de 113,18113{,}18. Tokenização não é propriedade universal do texto, portanto modelo e versão devem acompanhar qualquer número.

Em uma janela hipotética de 128 mil tokens, ignorando instruções e saída, caberiam cerca de 128000/18=7111\lfloor128000/18\rfloor=7111 cópias do JSON ou 128000/1929=66\lfloor128000/1929\rfloor=66 documentos CUM desse tamanho. Se o preço de entrada for cc dólares por milhão de tokens, um milhão desses registros acrescentaria 1,9111{,}911 bilhão de tokens sobre JSON, ou aproximadamente 1911c1911c dólares. A repetição também multiplica o texto sensível: um segredo fornecido como valor aparece 69 vezes em logs, buffers e contexto.

Maioria não é mágica

Com 69 observações corretamente alinhadas, a maioria estrita exige 35 votos. Ela corrige no máximo 34 substituições adversariais, desde que as outras 35 cópias permaneçam corretas e que o parser saiba quais linhas pertencem ao campo. Sob erros independentes com probabilidade pp, a chance idealizada de recuperar o valor correto é:

P(correto)=k=034(69k)pk(1p)69k.P(\text{correto})=\sum_{k=0}^{34}{69 \choose k}p^k(1-p)^{69-k}.

Para p=0,20p=0{,}20, o resultado é aproximadamente 0,9999999873; para p=0,40p=0{,}40, 0,9539497565. Essa é a probabilidade de preservar uma maioria estrita sob o modelo binomial, não uma garantia geral de recuperação. Ela não descreve truncamento contíguo, exclusão de linhas, corrupção correlacionada, adulteração intencional nem um valor malicioso repetido corretamente 69 vezes.

A alegação do README sobre recuperar após perder 98,5% do payload não decorre da maioria. Se cada cópia sobrevivesse independentemente com probabilidade 1,5%, a chance de restar ao menos uma seria apenas 10,98569=64,75%1-0{,}985^{69}=64{,}75\%; a chance de sobreviverem 35 ou mais seria aproximadamente 4,96×10454{,}96\times10^{-45}. Uma única cópia pode bastar para uma heurística de apagamento, mas não oferece votação nem prova de integridade. Em truncamento de cauda, campos posteriores podem desaparecer por inteiro.

Como testar um parser e a recuperação

Não publiquei um parser. Para conduzir um experimento verificável, preciso congelar uma gramática, declarar quais entradas são válidas e separar três tarefas: reconhecer estrutura, detectar dano e reconstruir valores. Uma primeira versão pode aceitar apenas objetos rasos e extrair os 69 textos de cada campo; maioria seria aplicada à sequência de bytes, sem confiar no type ou no rodapé.

Renderizando diagrama...

O corpus deve incluir inteiros-limite, decimais, Unicode, strings vazias, aspas, novas linhas, delimitadores CUM, objetos vazios e entradas deliberadamente fora do subconjunto. Para cada taxa de falha, execute muitas sementes publicadas. Meça sucesso sintático, detecção de corrupção, igualdade exata com o JSON normalizado, precisão e revocação por campo, recuperação falsa, bytes, tokens, latência e pico de memória. Não contabilize “erro detectado” como “valor recuperado”.

Os baselines precisam controlar orçamento: JSON único mede eficiência normal; 69 documentos JSON idênticos isolam o efeito da repetição; JSON com hash autenticado mede detecção; e um código de apagamento ou correção de erros compara redundância estruturada. Truncamento de prefixo, sufixo e intervalo interno deve ser separado de perdas independentes. Um invasor que conhece a votação exige testes próprios, pois independência deixa de ser hipótese válida.

Segurança e operação

O risco mais imediato é negação de serviço por amplificação. A função constrói arrays de linhas, concatena campos, objetos e documento completo em memória. Não há limites para tamanho da entrada, quantidade de objetos, campos ou comprimento dos valores. Um serviço que aceite JSON não confiável pode consumir CPU, heap, largura de banda, armazenamento e orçamento de LLM em proporção muito maior que a requisição. Limites devem existir antes de JSON.parse e antes da codificação; timeouts e cotas depois da expansão chegam tarde.

Como não implementei escape, o texto CUM permite injeção estrutural. O rodapé não autentica nada, e maioria replica uma entrada hostil em vez de neutralizá-la. Redundância não protege contra prompt injection: repetir uma instrução adversarial 69 vezes pode aumentar, não diminuir, sua presença no contexto. Para integridade real, use um MAC ou assinatura sobre uma serialização canônica, preserve a chave fora do payload e verifique antes de interpretar dados.

O CLI lê dados do primeiro argumento. Segredos podem permanecer no histórico do shell e aparecer na lista de processos. Além disso, npx baixa e executa código; fixar @4.20.69, conferir origem, integridade e tarball reduz ambiguidade, mas não substitui política de dependências. A orientação da RFC 8259 contra eval continua válida; aqui o uso de JSON.parse é a escolha correta [7].

Benchmark reproduzível

O benchmark abaixo mede geração, não parsing, porque ainda não implementei um parser CUM. Ele faz aquecimento, nove amostras de dez mil operações e reporta a mediana por operação. Execute em máquina ociosa, registre versão do Node, CPU e sistema, e não misture esse microbenchmark com tempo de rede ou tokenização.

const os = require("node:os");
const encode = require("cum-encode");
 
const data = [{ id: 1, name: "Laptop", price: 3999.9 }];
const iterations = 10_000;
const samples = 9;
 
function measure(fn) {
  for (let i = 0; i < 1_000; i++) fn();
  const values = [];
  for (let sample = 0; sample < samples; sample++) {
    const start = process.hrtime.bigint();
    for (let i = 0; i < iterations; i++) fn();
    values.push(Number(process.hrtime.bigint() - start) / 1e6 / iterations);
  }
  return values.sort((a, b) => a - b)[Math.floor(samples / 2)];
}
 
const json = JSON.stringify(data);
const cum = encode(data);
const cumMs = measure(() => encode(data));
const jsonMs = measure(() => JSON.stringify(data));
 
console.log({
  node: process.version,
  platform: `${os.platform()} ${os.release()} ${os.arch()}`,
  cpu: os.cpus()[0].model,
  jsonBytes: Buffer.byteLength(json),
  cumBytes: Buffer.byteLength(cum),
  jsonMs,
  cumMs,
  slowdown: cumMs / jsonMs,
});

Instale exatamente cum-encode@4.20.69 e execute o arquivo com a mesma versão de Node registrada. Em uma medição em Apple M4, Darwin 25.5.0 arm64 e Node 24.16.0, as medianas foram 0,000111 ms para JSON.stringify e 0,008006 ms para CUM, cerca de 72,3x; tamanhos foram 41 e 5.312 bytes. São resultados locais, não uma propriedade garantida. Frequência dinâmica, JIT, coleta de lixo e ordem dos testes afetam nanossegundos. Para reproduzir tokens, conte os dois textos com o mesmo tokenizer e fixe sua versão; os números anteriores usaram tiktoken==0.12.0.

Nome, licença e contexto profissional

O nome e a numeração fazem parte da sátira, assim como “CUM Standards Consortium”. Em inglês, porém, o acrônimo tem conotação sexual e a licença expande um palavrão. Isso pode acionar filtros de conteúdo, políticas de assédio, bloqueios de URL, revisão jurídica ou constrangimento em logs, tickets e apresentações. Equipes profissionais deveriam usar um alias neutro em demonstrações e evitar o pacote em caminhos onde nomes são exibidos a clientes. O problema é sociotécnico, não falha do algoritmo, mas afeta adoção e operação.

O manifesto declara WTFPL; o arquivo LICENSE reproduz o título da WTFPL v2 e acrescenta uma longa “Extended Enterprise-Grade Verbose Edition”, inclusive linguagem sobre patentes, responsabilidade e entidades fictícias [5]. Não se deve presumir que essa variante tenha exatamente o mesmo efeito jurídico do texto padrão. Projetos reais precisam de revisão de licença, inventário do texto efetivamente distribuído e avaliação por jurisdição; este artigo não oferece parecer jurídico.

Concebi CUM como provocação e bancada de laboratório. Com seu código, mostro que repetição tem preço, que marcadores não são checksums e que uma proposta de recuperação só ganha validade quando acompanhada por gramática, modelo de falha, decoder e medidas. Não o apresento como formato de produção, porque não registrei justamente esses elementos. Como piada técnica reproduzível, a versão 4.20.69 é pequena no fonte, enorme na saída e útil para ensinar a desconfiar de adjetivos onde deveriam existir testes.

Referências

  1. Domingues, M. “CUM – Catastrophically Uncompressed Markup”, README da branch main, 2025. GitHub.
  2. Domingues, M. src/index.js, encoder de referência CUM 4.20.69, branch main, 2025. GitHub.
  3. Domingues, M. src/build.js, branch main, 2025. GitHub.
  4. Domingues, M. package.json, branch main, 2025. GitHub.
  5. Domingues, M. LICENSE, branch main, 2025. GitHub.
  6. npm, “cum-encode: metadados, versões e distribuição”, consultado em 24 jul. 2026. Registro npm.
  7. Bray, T., ed. “The JavaScript Object Notation (JSON) Data Interchange Format”. RFC 8259, IETF, dez. 2017. doi:10.17487/RFC8259.
@techreport{bray2017rfc8259,
  author      = {Tim Bray},
  title       = {The JavaScript Object Notation (JSON) Data Interchange Format},
  institution = {Internet Engineering Task Force},
  type        = {RFC},
  number      = {8259},
  year        = {2017},
  month       = dec,
  doi         = {10.17487/RFC8259},
  url         = {https://www.rfc-editor.org/rfc/rfc8259}
}