O acervo — avaliação de arquitetura
Varredura de~/ved/asset-pipeline-dashboard(assets.did.lu), no commit1826b91(0.21.0), em 01/10/2026. Medida pela régua da casa (REGUA.md), que foi escrita no mesmo dia.
>
Quatro varreduras independentes cobriram metáfora, alcance, forma e contradições; um agente adversarial contestou as notas antes do fecho. Onde a régua usa este projeto como exemplo de calibração, as afirmações dela foram reverificadas uma a uma contra o código de hoje — e três delas não se confirmaram. Estão corrigidas na seção final.
1. A metáfora em uma frase
O acervo é uma casa que guarda corpos. Entra pela porta, a oficina mede o que custa, a esteira produz o leque de tamanhos, a peça fica guardada, a ficha diz o que ela é, a galeria mostra, a lixeira recebe o que ninguém quis — e quem edita mora fora.
Essa frase não existe escrita em lugar nenhum do repositório. Ela foi construída a partir dos cabeçalhos, e cada substantivo dela vem de um arquivo que se declara assim na primeira linha útil: src/oficina.js:1, src/esteira.js:1, src/routes/porta.js:2, src/lixeira.js:1, src/ficha-publica.js:2, src/galeria-publica.js:2, src/corpo-canonico.js:2. Não foi inventada pelo avaliador — foi lida.
A frase mais próxima de uma declaração é um título: docs/editores.md:1 — "# Editores — o acervo guarda, quem edita mora fora". Ela declara uma fronteira da casa, não a casa. Grep por metáfora|vocabulário em README.md, PROGRESS.md e docs/ devolve 8 ocorrências, todas de uso técnico; não há docs/metafora.md.
A metáfora é única e se compõe, e isso foi testado, não assumido. O critério foi o objeto circulante: "corpo" e "peça" atravessam porta, oficina, esteira, ficha, galeria e lixeira — cada módulo não tem a sua própria imagem, é uma estação por onde o mesmo corpo passa. E as imagens se citam hierarquicamente, não em paralelo: src/esteira.js:4-6 declara que "a oficina mora no acervo, na subida", e src/variantes.js:3-5 diz que "a esteira sabe apertar um .glb; a oficina sabe medir o que ele custa. Este módulo é o que liga as duas ao acervo". A relação é sempre de contenção: o acervo é a casa, os outros são cômodos. Uma oficina dentro de uma casa que guarda material é um museu com ateliê de restauro — existe no mundo, e é por isso que a composição se sustenta.
Duas peças ficam fora da casa, e a própria obra as marca como fora: bancada/LEIA-ME.md:3-4 (a bancada é oficina de quem constrói o acervo, não da casa — "não entram no servidor, não são provas do corredor") e src/ceu.js:4-7 (o céu é item guardado, não cômodo).
A bancada/ merece uma nota, porque pela forma ela parece o x/ que a régua condena no video-mocap — 16 arquivos diag- e print- versionados — e não é. Cada um tem seção própria no LEIA-ME.md dizendo que pergunta responde e que defeito real o motivou: a ficha da peça sem CSS, a barra de carregamento que nunca saía, o canvas colapsado em 150 px, os oito cartões vazios da galeria em produção. O documento diz por que nenhum deles aparecia no corredor — "o cartão desenhou?' não é uma pergunta que se faça ao servidor". Gaveta é onde se põe o que não se soube classificar; aqui cada ferramenta nasceu de um defeito nomeado. É o inverso.
O que contradiz a frase é o documento de entrada. README.md:1 abre com "assets.did.lu — Pipeline universal de assets" e README.md:5 chama a interface de "Painel". O texto que um agente lê primeiro diz pipeline e painel; o código que ele vai editar diz acervo e estante.
2. Notas
| # | Critério | Nota | Evidência |
|---|---|---|---|
| 1 | Metáfora central | 2 | Operante em 39 de 56 arquivos (src/esteira.js:1, src/oficina.js:1, src/routes/porta.js:2); nunca declarada; README.md:1 contradiz; pastas de 1º nível não contam história |
| 2 | Fisicalidade da metáfora | 3 | Medidor: 1 arquivo (vendor) e 1 falso positivo em 56; zero agentes-que-mandam; src/peca-de-humano.js:2, src/fila-oficina.js:2, src/chave-de-edicao.js:2 |
| 3 | Alcance na estrutura | 3 | Degrau 5 em 13 conceitos: migrations/026_peca_de_humano.sql:174-180 (CHECK de 55 ossos), MIME application/vnd.did.acervo.arvore+json (src/navegador.js:108), resposta pública em PT (src/catalog.js:360-409) |
| 4 | Linguagem ubíqua | 1 | Dos 8 conceitos centrais, 1 tem nome único; /api/projects e /api/projetos vivos (server.js:354,371); "corpo" com 2 sentidos na mesma frase (src/routes/porta.js:209); nenhum gate de vocabulário |
| 5 | Modularidade | 2 | Troca real em 0.20.0 (e0b99d0) fechou buraco de conferência; GCS sai com 1 arquivo; mas SQL cru em 30 arquivos |
| 6 | Isolamento | 2 | 152 asserções no gate curto (test/integracao-editores.js:564-589,654); public/app.js com 4.616 linhas e zero vazamento; mas sem gate estrutural de fronteira, assets escrita de 16 lugares |
| 7 | Coesão | 2 | Zero pastas-gaveta; 33 de 41 passam no teste da frase; mas public/app.js com 12 assuntos e src/ plano com 41 arquivos |
| 8 | Objetos a serviço da metáfora | 2 | Zero classes e zero Manager/Service/Handler — mas a obra tem coisas (item, peça, corpo, coleção) e nenhuma existe como objeto: 16 arquivos escrevem assets por SQL, 13 dão UPDATE, e não há src/item.js |
| 9 | Desenhabilidade | 2 | 21 das 23 caixas têm corpo e as ligações são relações (não imports), mas a caixa central é a cinza — ver §4 |
| 10 | Ausência de contradições | 2 | Três buracos vivos (§5), mas toda disputa de posse está decidida e escrita; as 49 rotas batem 100% com os 4 docs que as citam |
Soma: 21 / 30.
O critério 8 saiu de 3 para 2 no passe adversarial, e vale dizer por quê: o argumento que sustentava o 3 era que "o único módulo com estado ésrc/fila-oficina.js— uma fila, que é coisa, com estado, chamada de fila". A afirmação é falsa. São sete:src/contratos.js:32,src/corpo-canonico.js:68,src/esteira.js:119,src/esteira-ceu.js:110,src/esteira-miniatura.js:84,src/gcs.js:7,src/tipos-da-casa.js:471— cinco deles caches de boot, que não são coisas. Com a premissa caindo, o que resta é o teste inverso que a régua manda aplicar, e ele reprova: a obra tem coisas evidentes e nenhuma delas é objeto no código.
O medidor de cinco segundos. Arquivos com nome de abstração no projeto inteiro (fora node_modules): 1 — public/vendor/BufferGeometryUtils.module.js, vendor do Three.js. Identificadores em src/: 1 — fonteUtilizavel (src/fonte.js), falso positivo, adjetivo em português. Ampliando para public/ (que a régua não varreu): mais 1 — installPasteHandler (public/app.js), verdadeiro positivo.
A régua registrou "1 em 36 arquivos de src/". Hoje são 56 (41 em src/ + 15 em src/routes/): o projeto cresceu 20 arquivos sem produzir um único gerenciador. A busca explícita por abstração com nome bonito — orquestrador, maestro, regente, gestor, coordenador, despachante — devolve zero.
A camada que puxou o resultado para baixo é a B (o alcance), e dentro dela o critério 4. E o diagnóstico é preciso: não é que o alcance seja raso — ele é 3. É que a metáfora alcançou fundo sem aposentar o que havia antes, e as duas eras coexistem no mesmo nível, publicadas.
A nota 3 em alcance foi atacada e resistiu, e o argumento que a salvou merece registro porque inverte uma leitura fácil. O ataque é forte no papel: 39 das 67 rotas são inglês técnico e 9 das 12 tabelas também, o que parece a descrição literal da nota 2 ("código e dado falam outra língua"). Mas a pergunta certa não é que nome tem a tabela — é que nome tem o campo que o consumidor recebe. src/catalog.js:351-432 é a função que monta a resposta de toda busca e listagem: dos 33 campos publicados, só cinco são inglês (id, slug, url, sha256, status), e quatro desses são vocabulário universal da web. Os outros 28 são nome, categoria, licenca, origem, autor, uso, medidas, osso, projeto, url_canonica, url_imutavel, exige_credito. E a escolha é declarada: src/catalog.js:343-345 — "Vocabulário estável e em português — quem lê isso está decidindo se usa o asset, não inspecionando o banco." A tabela é inglês; o dado que atravessa a fronteira é português. É o critério 6 ajudando a pontuar o 3: o consumidor não precisa saber o nome da coluna, e não sabe.
Um dado que a régua não previu e que vale para o critério 3: a metáfora chegou ao Dockerfile. Dockerfile:2 abre com "A imagem do acervo — Node, e as duas ferramentas da OFICINA", e as 110 linhas de comentário do arquivo explicam que a oficina é quem decidiu a imagem-base, porque uma das ferramentas dela não é Node. A régua tem cinco degraus de profundidade e o quinto é "dado e borda"; o empacotamento está abaixo disso, e mesmo lá o vocabulário se sustenta.
3. O desenho
relatorios/acervo.svg — publicado junto com este relatório.
Cada caixa é um objeto que o código nomeia; cada seta é uma ligação que existe (import, chamada HTTP, escrita em disco, registro em banco). Caixa cinza é peça sem corpo físico; linha tracejada é ligação que o desenho precisou e o código não tem. A cor separa o que nasceu depois de setembro do que é de abril e não foi convertido — porque essa fronteira, como se verá, explica quase tudo.
4. Onde o desenho não fechou
① Peça sem corpo: a coisa que a casa guarda não tem corpo no código. O acervo é uma casa que guarda itens, e não existe src/item.js — nem src/peca.js, nem src/acervo.js. A coisa guardada mora como linha na tabela assets, e 29 dos 56 arquivos escrevem SQL direto nela; 13 dão UPDATE. Cada cômodo tem nome, prosa de abertura e assunto próprio; a coisa que eles guardam, não. É por isso que a caixa do meio do desenho é cinza: todas as setas passam por um lugar que ninguém batizou. O conceito mais central do produto é o único sem peça.
② Ligação que não existe no mundo: a estante. No desenho, a estante é o móvel onde as coisas ficam — é o que a palavra promete. No código ela é só uma tela (server.js:392, public/app.js:3695) que lê a listagem de projetos: não guarda nada, não tem módulo em src/, não tem dado. O próprio projeto sabe e escreveu: test/integracao-estante.js:5-7 — "Ela não tem porta própria: lê a mesma listagem que todo editor lê." O móvel virou vitrine, e no desenho isso aparece como uma caixa que recebe seta e não emite nenhuma.
③ Duas peças invisíveis. A primeira é o encaixe — a pose da peça sobre o osso. Ele é dado real: lido (src/humano.js:262), servido na ficha (src/ficha-publica.js:589), documentado (docs/tipos-da-casa.md:415). Mas não tem módulo, coluna nem prova — e palavra sem dono ganha segundo sentido: em test/unidade-oficina.js:5 e test/integracao-oficina.js:18, "prova-se o encaixe" quer dizer "prova-se a integração". A mesma palavra nomeia um dado do domínio e uma categoria de teste. A segunda é a ausência de qualquer peça entre o código e o banco. O desenho precisou de uma prateleira e encontrou uma tabela que 29 arquivos tocam diretamente. Não há camada de persistência; src/db.js é um Pool de nove linhas com query() pass-through. É isso que torna o Postgres a única dependência que nenhuma troca contorna.
5. Contradições
Internas
C1 — A porta aceita um campo e o joga fora. Tipo 3. (a mais cara, e a única que já custa dinheiro)
- Quem manda:
ez3d/src/acervo.js:152enviadescricaoparaPOST /api/ferramentas/ez3d/sync. - Quem descarta:
src/routes/ferramentas.js:209-218— oINSERT INTO assetslista 23 colunas edescriptionnão é uma delas. A porta responde 201 e não grava.
O EZ3D mediu isto em produção: ez3d/src/acervo.js:234-236 — "Medido em 30/09 contra a porta de PRODUÇÃO com arquivo real: depositei com descricao preenchida, respondeu 201, e a ficha saiu description: null." E construiu uma segunda chamada HTTP por cima (descrever(), ez3d/src/acervo.js:255) cujo comentário diz que ela desaparece sozinha no dia em que a porta aceitar. A contradição não só existe — já pagou desenho alheio. Dois detalhes mostram como o buraco se esconde. src/routes/ferramentas.js:208 tem um comentário afirmando que o sync protege description de ser apagada pela curadoria automática — protege um campo que nunca foi gravado. E src/routes/ferramentas.js:277 devolve descricao: resultado.description na resposta: a porta publica de volta o campo que nunca gravou, então quem depositou recebe um eco vazio e tem motivo para acreditar que funcionou. test/integracao-ez3d-sync.js não pega.
Deve ganhar o acervo: gravar a coluna. Aceitar, responder 201 e descartar é a pior falha possível — a que parece sucesso.
C2 — O mesmo UPDATE em dois lugares, já divergindo. Tipo 1.
src/escrita-de-corpo.js:271-281esrc/routes/porta.js:422-432escrevem as mesmas nove colunas, na mesma ordem.
src/escrita-de-corpo.js:1-18 foi criado exatamente para matar essa duplicação e nomeia as três portas; src/routes/porta.js:69 importa o módulo e :379 promete que "passam pelo mesmo código" — mas o ramo da linha 422 ainda escreve por conta própria. E os dois já divergiram: src/escrita-de-corpo.js:264-269 preserva medida_autor/unidade_autor da versão anterior ("um lápis continua tendo 18 cm depois de ganhar mais polígonos"); src/routes/porta.js:432 passa as medidas cruas. Um item que sobe por esse ramo perde a medida declarada pelo autor — divergência silenciosa, o tipo mais caro. E o agravante que fecha o caso: src/escrita-de-corpo.js:255-263 escreve que "sem este resgate, uma versão corrigida do modelo apagaria em silêncio a medida que alguém declarou". O outro caminho faz exatamente o que esse comentário diz que não se pode fazer. Os dois UPDATE são idênticos byte a byte nas oito colunas; a única diferença é o parâmetro que carrega o estrago. Além disso, src/routes/uploads.js:230 chama ligacoes.validar() direto, sem passar pelo módulo comum: a convergência das três portas é 2/3, não 3/3 como o commit e0b99d0 afirma.
Deve ganhar escrita-de-corpo.js — o projeto já decidiu isso por escrito; falta terminar.
C3 — 142 KB de documentação descrevem um produto que não existe mais. Tipo 3.
PROGRESS.md:3— "Última atualização: 2026-09-22"; a versão mais alta citada em suas 59 KB é 0.17.3 (PROGRESS.md:1001).README.md:1170para em 0.17.0.package.json:3—"version": "0.21.0".
Não é só atraso: os dois documentos declaram ativamente a metáfora antiga. README.md:1 e PROGRESS.md:1 abrem com "Pipeline universal de assets", e PROGRESS.md:13 descreve o produto como "Serviço universal pra gestão de assets (arte, áudio, etc)" — sem uma palavra de corpo, osso, peça, humano, editor ou lixeira, que é tudo o que o projeto fez nos últimos quarenta dias.
Isto agrava o critério 1 além do que eu havia escrito. Não é que a metáfora não esteja declarada: é que a declaração mais visível que o projeto faz sobre si mesmo é a da metáfora que ele abandonou. Um agente que chega lê 142 KB dizendo pipeline e painel, abre src/ e encontra oficina, esteira e lixeira. A doc não está em silêncio — está dizendo a coisa errada, alto.
C7 — Sete das onze provas de tela não têm comando que as rode. Tipo 3.
test/corredor.js:11-14declara que a bateria de tela "roda à noite" e não é pré-condição de publicar.- Cruzando
test/tela/*com os 48 scripts depackage.json: têm comandopainel-permissao.js,prova-modos.mjs,prova-galeria-modos.mjs,prova-deslocamento.mjs. Não têm nenhum:bancada-galeria-humanos.js,bancada-humano-de-pecas.js,bancada-humano.js,banco-de-prova-arvore.js,ficha-ligacoes.mjs,prova-humano.mjs(29 KB) eprova-tres-pecas.mjs. Não há no repositório corredor noturno nem agendador que as chame.
O diagnóstico está escrito pelo próprio projeto, duas linhas acima da declaração: test/corredor.js:5-9 — "uma suíte que só roda quando alguém se lembra dela não é uma rede de segurança: é um arquivo." Aplicado a si mesmo, sete arquivos. O corredor resolveu esse problema para as provas de texto e não o resolveu para as de tela.
Com os vizinhos
C4 — O leitor do mocap exige o que o acervo não garante. Tipo 2.
- Quem exige:
video-mocap/acervo/leitor.mjs:68— o clipeidleé obrigatório, "sem ele, T-pose silenciosa". E ele procura o manifesto emscene.userDatae depois nos nós (leitor.mjs:72-83). - Quem não garante:
src/humano.js:203-214montaclipessem nunca exigiridle, esrc/tipos-da-casa.js:172declara um caminho só para o manifesto (scene.extras.clagComponent).
Um pacote sem idle passa pelo acervo como humano animado válido e reprova no mocap. Um pacote com o manifesto num nó é legível pelo mocap e invisível para o acervo. Deve ganhar almost-humanoid, que é o dono declarado do contrato — e o acervo já cede a posse por escrito em src/tipos-da-casa.js:156-160: "O dono do contrato NÃO é o acervo." A spec tem de dizer onde o manifesto pode morar; hoje cada lado assume.
C5 — O acervo lê CCP 1.4 e não declara que lê. Tipo 2, atenuado.
src/humano.js:248,270cravam a 1.4 — é a única versão nomeada no acervo.almost-humanoid/docs/CCP-MANIFEST-1.5.md:1é a spec atual.
Aqui a régua está desatualizada: a 1.5 isentou o acervo por escrito (CCP-MANIFEST-1.5.md:459-461 — "O campo pecas.ossos que já existe lá não precisa mudar de lugar") e escreveu a precedência (:250 — "quando os dois endereços existem, proporcao.ossos vence"). Isso é dívida com dono, motivo medido e regra escrita — o padrão que a própria régua elogia. A contradição residual é menor e real: o acervo não declara que versão suporta. Um pacote 1.5 com proporcao.ossos entra, o acervo não vê a seção, não avisa, e a ficha sai incompleta em silêncio.
C6 — "Projeto" é duas coisas, com dois endereços públicos vivos. Tipo 2.
server.js:371monta/api/projects→src/routes/projects.js, que lê a tabelaprojects: a pasta, o balde onde os arquivos de um jogo moram.server.js:354monta/api/projetos→src/routes/projetos-acervo.js, que não lêprojects: lêassets, porque uma obra editável é um item do acervo como outro qualquer.
Duas entidades distintas, dois endereços, e a única diferença entre os endereços é a língua em que a mesma palavra foi escrita. public/app.js:3616-3628 documenta a ambiguidade em doze linhas — honestamente, mas em comentário. Custa uma leitura a cada vez, para sempre, e nada reprova quem errar. O mesmo padrão em coleções (/api/collections e /c/:slug). Deve ganhar a obra para /api/projetos, e a pasta deveria se chamar outra coisa — mas o dado já está publicado, e esta é a contradição mais cara de desfazer de todas.
O que foi investigado e descartado
Oito suspeitas não produziram os dois lados e por isso não entram, mas vale dizer quais, porque metade do valor de uma varredura é o que ela isenta: rotas documentadas que não existem (as 49 rotas batem 100% com os quatro docs que as citam); código morto em src/ (zero arquivos sem importador); public/editor-de-mentira/ (é dublê vivo da suíte, usado 10 vezes em test/integracao-editores.js); as três esteiras escrevendo a mesma tabela (fronteira declarada em src/esteira-ceu.js:12-14, um dono de dado e três produtores de bytes); miniaturas.js + esteira-miniatura.js (produtor e persistidor, separação justificada em src/miniaturas.js:5-7); custo calculado em dois lugares (há um único UPDATE assets SET custo no repositório); contratos duplicados nos vizinhos (zero ocorrências de marked-scene e did-project fora do acervo); e metáfora que se contradiz — procurei o par incompatível e não achei.
6. Ações propostas
Ordenadas por nota que movem por hora gasta. Horas são de trabalho de agente.
| # | Ação | Horas | Critério | De → para |
|---|---|---|---|---|
| 1 | Gravar description no INSERT de src/routes/ferramentas.js:210 e cobrir em test/integracao-ez3d-sync.js | 0,5 h | 10 | reforça 2 |
| 2 | Reescrever as 20 primeiras linhas de README.md e PROGRESS.md com a frase da metáfora, e trocar public/index.html:6 | 1 h | 1, 2, 10 | 1: 2 → 3 |
| 3 | Terminar a extração: src/routes/porta.js:422 passa a chamar escrita-de-corpo.js, e src/routes/uploads.js:230 idem | 2 h | 10, 5 | 10: 2 → 3 |
| 4 | Um gate que carregue public/corpo/humanoid-base.bonemap.json e o confronte com almost-humanoid/src/rig/canonical-bones.js | 3 h | 4, 10 | 4: 1 → 2 |
| 5 | Versionar as portas de que o acervo é dono (porta-de-escrita@1, porta-dos-editores@1), com a sentinela que já existe para marked-scene@1.0 | 4 h | 6, 4 | 6: 2 → 3 |
| 6 | Dar corpo à coisa guardada: um src/item.js dono das leituras e escritas de assets, começando pelos 13 que dão UPDATE | 8 h | 5, 6, 7, 8, 9 | 8: 2 → 3; 9: 2 → 3 |
| 7 | Aposentar um dos dois nomes de "projeto": /api/projetos fica com a obra, a pasta é renomeada, /api/projects responde com aviso de depreciação | 8 h | 4, 10 | 4: 2 → 3 |
A ação 6 não é a mais barata, mas é a única estruturalmente necessária — e isso só ficou claro no passe adversarial. O acervo tem um defeito de arquitetura, e ele aparece três vezes na régua com nomes diferentes: no critério 8 (não há objeto onde a obra tem coisa), no 5 (o banco é substrato, não peça) e no 9 (a caixa cinza no meio do desenho). Não são três problemas que por acaso convergem — é um só, visto de três ângulos. Enquanto a coisa guardada não tiver corpo, 16 arquivos continuam negociando direto com a tabela, e nenhum dos três critérios sobe.
As ações 1 a 4 somam 6,5 horas, movem três critérios e são todas de acabamento: as 1 e 3 restauram gate que o projeto já decidiu ter, e a 4 constrói o gate que falta na jornada inteira — ele não existe em nenhum dos cinco repositórios.
A ação 2 mudou de natureza no passe adversarial e ficou mais urgente do que eu havia escrito. Eu a tinha formulado como "escrever a frase que falta". É pior: README.md:1 e PROGRESS.md:1 declaram ativamente a metáfora antiga — "Pipeline universal de assets" —, e PROGRESS.md:3 está datado de 22/09 com a última versão citada sendo a 0.17.3 contra a 0.21.0 em produção. Os dois documentos maiores do repositório, somando 142 KB, descrevem um produto que não existe mais: não mencionam humano, peça, osso, editor nem lixeira. Não é lacuna, é contradição tipo 3 na superfície mais lida — e é uma hora de trabalho.
7. O que eu não consegui avaliar
~/ved/almost3dfoi lido, mas há trabalho não commitado de outra sessão em voo nessa pasta. Não encontrei nada que toque o acervo (zero menções amarked-scene,did-projectouboneco-de-massinha), mas qualquer conclusão sobre ela precisa ser reconfirmada com a árvore limpa.- Não rodei a suíte. A avaliação é de leitura; os gates foram avaliados pelo que reprovam segundo o código, não por execução.
test/tela/(11 arquivos de prova de navegador) não foi exercitado, então não sei se alguma prova de tela está quebrada hoje. - Não medi o comportamento em produção. A contradição C1 está provada pela medição que o EZ3D fez em 30/09 e escreveu no código, não por chamada minha à porta.
README.md(83 KB) ePROGRESS.md(59 KB) foram lidos por amostragem dirigida, não integralmente. Pode haver mais contradição tipo 3 escondida neles — a que achei (C3) é estrutural e provavelmente a maior.
8. Onde a régua precisa ser corrigida
A régua usa este projeto como calibração em seis pontos. Quatro se confirmaram; três não. Como outras varreduras vão herdar essas afirmações, elas precisam ser corrigidas na fonte.
ERRADO — mixamorigHead não é o dialeto do acervo. A régua cita src/corpo-canonico.js:16-18 como prova de que o acervo fala Mixamo, e conclui que a jornada tem quatro dialetos de osso em conflito. As linhas citadas são o comentário que explica por que existe um mapa de tradução: "O corpo herdou os nomes do Mixamo (mixamorigHead) e a captura usa os padronizados da casa (head)." O mixamorigHead está do lado do arquivo, não do vocabulário. O acervo fala VRM puro — src/peca-de-humano.js:69-124 lista os 55 ossos como head, neck, leftUpperArm, hips, e migrations/026_peca_de_humano.sql:174-180 os crava num CHECK. Isso muda a resposta à pergunta do founder: a jornada EZ3D → acervo → mocap → humano animado não quebra no nome do osso. Três dos quatro projetos falam VRM; o único divergente é o video-mocap, que fala Mixamo-limpo porque captura de um rig Mixamo de verdade, e a divergência tem ponte. A lacuna real é menor e mais barata: não existe teste que confronte os dois mapas (a ação 4).
ERRADO — "pipeline" não é resíduo do nome do repositório. A régua diz que o nome do repo é "o único artefato que ainda diz pipeline dashboard". A palavra está viva em seis superfícies: public/index.html:6 (o título da aba de quem abre assets.did.lu), src/gcs.js:4 (GCS_PREFIX = 'assets-pipeline', que põe a palavra na URL de cada peça já publicada — https://st.did.lu/assets-pipeline/…), server.js:399 (o log de boot), package.json:2, package.json:5 (a description, que é a definição da obra que todo agente e todo painel de deploy lê) e README.md:1. Só "dashboard" é resíduo morto. A do bucket é a única que não dá para consertar de graça — as outras cinco são cinco linhas.
OMISSÃO — a régua não rodou no acervo o teste que ela mesma chama de "o mais rápido que existe". As pastas de primeiro nível (bancada contratos docs migrations public scripts src test) lidas em sequência não contam história: 6 de 8 são layout de qualquer projeto Node. Toda a metáfora vive dentro de um src/ plano de 41 arquivos em ordem alfabética, com routes/ como única subdivisão — e routes/ é divisão por tipo de arquivo, não por tema. É por isso que a nota em metáfora central aqui é 2 e não 3, divergindo da leitura implícita da régua.
DESATUALIZADO. A contagem do medidor era "1 em 36 arquivos de src/"; hoje são 56, e o numerador continua 1. A régua não conhece a migração 028 (4 colunas novas, todas em português) nem as 8 rotas de lixeira/varredura. E a afirmação de que "balde só vive em comentário" deixou de valer na 0.20.0: test/integracao-editores.js:76 declara const balde = new Map() e :166 registra app.get('/balde/*') — o sinônimo que vivia em comentário virou identificador.
CERTO, e vale registrar. O par calibrador lixeira (degrau 5) × estante (degrau 3) confirma-se em todas as cinco células. A tabela asset_parts com coluna papel e comentário em português (migrations/006_collections.sql:193-205) são mesmo três vocabulários em cinco linhas. "Corpo" tem mesmo dois sentidos em src/routes/porta.js, e na mesma frase: a mensagem de erro da linha 209 é "corpo vazio — mande os bytes do arquivo no corpo do PUT". E o veredito do medidor de cinco segundos — degrau 3 — sustenta-se melhor hoje do que quando foi escrito.
9. A leitura que eu levaria para a mesa
O acervo não tem problema de rigor. Tem uma conversão que parou no meio.
A evidência que organiza tudo é cronológica, e é quase binária. Datei a criação dos 56 arquivos de código do servidor e cruzei com a presença do cabeçalho que nomeia o objeto físico. Dos 14 nascidos até 04/08, zero têm cabeçalho. Dos 42 nascidos de 23/08 em diante, 39 têm. A mesma fronteira explica o banco (9 tabelas em inglês até a 027, 3 em português depois), as rotas (39 em inglês nos arquivos de 001–018, 28 em português nos de 019 em diante, zero exceções nos dois sentidos) e a divisão entre src/catalog.js e src/peca-de-humano.js.
Isso não é "a metáfora não alcança a infraestrutura", que seria limitação natural e cara. É "a metáfora nasceu em agosto e ninguém voltou para converter o que já estava construído" — que é trabalho finito, e barato, porque a parte cara já foi paga. Decidir qual é a imagem é o difícil, e está feito. O que falta é terminar.
E onde o projeto decidiu, decidiu com uma qualidade acima da média da casa. Cada gate abre com o incidente datado que o motivou e com o raciocínio de por que a saída óbvia seria pior: test/unidade-tipos-da-casa.js:12 — "Uma conferência que nunca reprova é um comentário", que é a tese central da régua escrita pelo projeto antes de a régua existir. scripts/confere-contratos.js:8-20 explica por que a cópia vendorizada continua sendo o que executa (ler a URL no upload poria o servidor de outra casa no caminho crítico da porta e tornaria a entrada não-determinística) e por que a sentinela separada é o que avisa. test/corredor.js:17-37 documenta por que uma prova foi expulsa do gate curto: media tempo de montagem junto com permissão, e o que separa o código do ar não pode depender de quanto a máquina está ocupada.
A régua abre dizendo que na casa a lei sem gate não pegou e o gate sem lei pegou. O acervo é a prova positiva dessa tese: nunca escreveu lei de vocabulário nenhuma, e tem nove gates executáveis, quatro deles no caminho da publicação.
Mas há um defeito que não é de acabamento, e o passe adversarial foi quem o isolou. Eu havia distribuído o problema em três critérios diferentes, com três nomes diferentes. É um só: a coisa que a casa guarda não tem corpo no código. Não existe src/item.js. O item mora como linha na tabela assets, e por isso 16 arquivos negociam diretamente com ela e 13 dão UPDATE. Esse único fato é o que aparece como nota 2 no critério 8 (não há objeto onde a obra tem coisa), como nota 2 no critério 5 (o banco é substrato, não peça trocável) e como a caixa cinza no meio do desenho, no critério 9.
A consequência prática é visível: a contradição C2 — dois UPDATE idênticos, um dos quais apaga em silêncio a medida declarada pelo autor — só é possível porque não há dono. Num projeto onde o item fosse um objeto, não haveria dois lugares escrevendo as mesmas oito colunas, porque não haveria dois lugares.
O resumo que eu levaria à mesa, então, é de duas frases. O acervo tem uma metáfora física genuína, consistente da primeira linha dos arquivos até o campo JSON que sai pela borda e até o Dockerfile — e ela nunca chegou à única coisa que a casa existe para guardar. A dívida de acabamento é grande mas barata (seis horas e meia movem três critérios); a dívida estrutural é uma só, custa oito horas, e é a diferença entre um projeto bem escrito e um projeto bem construído.
Sobre futuro, que é o que importa: este é um projeto que sabe decidir e sabe provar. Ele construiu nove gates sem nunca ter escrito uma lei, documentou cada um com o incidente que o motivou, e expulsou do caminho crítico a prova que não cabia ali. A régua diz que um projeto que tira 14 com metáfora clara tem mais futuro que um que tira 22 sem nenhuma. Este tira 21 com metáfora clara, e a lista do que falta cabe num dia de trabalho.