A nossa reserva de direitos sobre treino de IA estava escrita para ninguém. A linha Content-Signal: search=yes, ai-input=yes, ai-train=no aparecia no robots.txt de wppoland.com exatamente uma vez, no grupo User-agent: *, e por baixo dela estavam vinte grupos de crawlers nomeados.
Segundo o RFC 9309, nenhum desses vinte grupos herda o que quer que seja do grupo do asterisco. O GPTBot, o ClaudeBot, o PerplexityBot, o Google-Extended e o resto da lista liam apenas as suas próprias secções, onde essa linha não existia.
Cada crawler que tivemos o cuidado de nomear à mão era precisamente o crawler que não conseguia ver aquilo que escrevêramos para ele.
Escrevemos sobre isto porque o ficheiro é nosso e o erro também. Verificávamos o robots.txt para perceber se não estaria a bloquear alguma coisa por engano, e nunca para perceber se a declaração chegava sequer ao destinatário.
O que estava exatamente no ficheiro
A estrutura era a que se vê na maioria dos ficheiros que já abrimos: um grupo geral no topo e, por baixo, uma lista de bots nomeados com regras Allow alargadas para endpoints destinados a máquinas.
User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Disallow: /cdn-cgi/
Sitemap: https://wppoland.com/sitemap-index.xml
Agentmap: https://wppoland.com/.well-known/ai-catalog.json
User-agent: GPTBot
Allow: /
Allow: /llms.txt
Allow: /facts.json
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /Parece arrumado. O sinal está lá, os grupos nomeados estão lá, os endpoints para agentes estão listados à parte. O problema é que estas duas coisas não têm contacto uma com a outra. Quem lê o ficheiro como documento vê uma política no topo e um conjunto de permissões por baixo, e acrescenta mentalmente uma relação entre as duas que o parser desconhece: o parser não lê documentos, compara um token com uma lista de nomes, fica com o bloco vencedor e deita fora o resto do ficheiro antes de ler uma única diretiva.
Porque é que uma linha não cobre o ficheiro inteiro
O cliente compara o seu product token com os nomes nas linhas User-agent, sem distinguir maiúsculas de minúsculas, e aplica um grupo: aquele que o nomeia. O asterisco não é o padrão menos específico, é o recurso alternativo, e o RFC 9309 só o usa quando nenhum grupo nomeia o cliente. Quando existe grupo nomeado, o cliente aplica apenas as diretivas desse grupo e o grupo do asterisco deixa de lhe dizer respeito na totalidade. A última frase é o erro inteiro: lê-se como óbvia na especificação e deixa de ser óbvia no momento em que a confrontamos com um ficheiro escrito por nós, porque um ficheiro escrito por nós transporta a nossa intenção, e a intenção é invisível para o único leitor que conta.
Isto não é uma exceção criada para os Content Signals. A mesma regra sempre valeu para Allow e Disallow, e é exatamente por isso que um ficheiro onde alguém acrescentou Disallow: /wp-admin/ só no grupo do asterisco não protege nada contra um bot que tem a sua secção mais abaixo. A diferença está no que vem a seguir.
Com Disallow, a consequência vê-se: a página aparece no índice ou não aparece, e uma semana de dados de indexação diz qual dos dois aconteceu. Com Content-Signal não se vê nada, em nenhuma direção, porque uma declaração de direitos não tem retorno, e uma declaração errada produz exatamente o mesmo histórico observável que uma correta durante todo o tempo que lhe quisermos dedicar.
Content Signals é uma proposta da Cloudflare e não faz parte do RFC 9309, e a Cloudflare ativa esta política por omissão no seu ficheiro robots.txt gerido. O mecanismo de grupos onde essa linha vive, esse, é inteiramente o mecanismo do RFC 9309, por isso a regra do grupo único aplica-se-lhe como a tudo o resto no ficheiro. Uma diretiva nova dentro de um contentor antigo herda as regras do contentor, incluindo aquelas que ninguém foi confirmar antes de a acrescentar.
Três sinais e aquilo que não prometem
A especificação define três sinais, cada um com valor yes ou no:
| Sinal | A que se aplica |
|---|---|
search | construção de um índice de pesquisa e devolução de resultados, ou seja, ligações e excertos curtos |
ai-input | entrega do conteúdo à entrada de um modelo de IA no momento da resposta, ou seja, RAG e fundamentação de respostas |
ai-train | treino e afinação de modelos |
O nosso conjunto search=yes, ai-input=yes, ai-train=no é uma escolha consciente, e o compromisso que existe dentro dela merece ser dito sem rodeios. Queremos ser citados em respostas generativas, porque hoje esse é um dos canais por onde alguém nos encontra, e não queremos entregar o corpus para treino, porque um modelo treinado leva o texto consigo sem deixar caminho de volta ao sítio de onde ele veio. Dizer sim ao primeiro e não ao segundo é aceitar que o mesmo crawler pode estar a fazer os dois trabalhos em dias diferentes, e confiar que ele distingue os dias. A ausência de sinal significa uma terceira coisa, diferente de no: o operador do site não dá consentimento nem o recusa por esta via, e é por isso que o silêncio aqui não equivale a recusa.
Nenhum destes sinais bloqueia o que quer que seja. É uma linha de texto num ficheiro que o cliente pode descarregar ou não, ler ou não e respeitar ou não. O servidor responde ao pedido independentemente do que lá esteja escrito. O bloqueio é uma camada separada, avaliada antes da aplicação, e faz-se com regras de WAF, limites de pedidos ou verificação da identidade do bot, e essa camada custa: corre em cada pedido, pode enganar-se a respeito de uma pessoa e precisa de manutenção à medida que os sinais de identidade mudam.
Uma declaração não custa nada e não impõe nada, o que é uma troca razoável desde que se saiba qual das duas acabámos de publicar. O sinal vale exatamente aquilo que vale uma mensagem inequívoca enviada para a morada certa. A nossa era inequívoca e ia para a morada errada.
Verifique o seu ficheiro com um comando
Demora poucos segundos e funciona em qualquer domínio:
curl -s https://oseudominio.pt/robots.txt \
| awk 'tolower($0) ~ /^user-agent:/ {ua++} tolower($0) ~ /^content-signal:/ {cs++} END {print "grupos User-agent: " ua "\nlinhas Content-Signal: " cs}'Uma ressalva antes de agir sobre o resultado: o que é contado são linhas User-agent e não grupos, e a ABNF do RFC 9309 permite várias linhas User-agent a abrir um único grupo, pelo que um ficheiro que empilhe nomes dessa forma vai acusar uma falha que não tem.
Nesse caso, guie-se pela lista do segundo comando e não pela aritmética do primeiro.
Se o número de grupos for maior do que o número de sinais, a diferença diz quantos grupos não veem a sua reserva. No nosso caso o resultado foi vinte e um para um.
A variante mais detalhada escreve os nomes dos grupos onde falta o sinal:
curl -s https://oseudominio.pt/robots.txt \
| awk '/^[Uu]ser-agent:/ {if (name != "" && !sig) print "sem sinal: " name; name=$2; sig=0} /^[Cc]ontent-[Ss]ignal:/ {sig=1} END {if (name != "" && !sig) print "sem sinal: " name}'O segundo comando é o que vale a pena ligar a uma pipeline, porque a saída dele é uma lista de coisas a corrigir e não um número para interpretar.
Como corrigir
A correção é aborrecida: repetir a linha Content-Signal em cada grupo a que deva aplicar-se. Não há atalho, forma abreviada nem herança que se possa ativar.
User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Disallow: /cdn-cgi/
User-agent: GPTBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Allow: /llms.txt
Allow: /facts.json
User-agent: ClaudeBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
User-agent: PerplexityBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /Implementámos esta alteração a 18 de setembro de 2026, no dia em que este artigo saiu. O sinal está agora em 18 grupos de 23, e os cinco que ficaram de fora são scrapers que já têm Disallow do nosso lado, onde uma autorização só tornaria a mensagem menos clara.
A correção obriga a decidir uma coisa que o ficheiro com a linha repetida não decide sozinho: se o mesmo conjunto de sinais serve todos os grupos. Para um crawler de indexação e para um crawler que recolhe corpus de treino a resposta é diferente, e um ficheiro com vinte linhas idênticas sugere que ninguém pensou no assunto. Um grupo em que search=yes não faz sentido, porque o cliente não constrói índice nenhum, devia ter a sua própria redação, e é ao escrever essa redação que o ficheiro deixa de ser uma cópia e passa a ser uma política.
O segundo buraco: grupos para cada papel
Na mesma leitura do ficheiro percebemos que tínhamos apenas o grupo ClaudeBot e não tínhamos os outros dois: Claude-User, que trata das transferências iniciadas pelo utilizador, e Claude-SearchBot, que trata da fundamentação de pesquisa.
São três papéis distintos e intenções distintas do lado do cliente. Um bot que descarrega a página porque uma pessoa acabou de colar o endereço numa conversa está a fazer algo diferente de um bot que constrói corpus, e faz sentido responder-lhe de outra maneira.
O efeito da ausência desses grupos é exatamente o mesmo que atrás, só que pelo lado oposto: um cliente sem secção própria cai no grupo do asterisco. No nosso caso isso significava que o Claude-User via o sinal correto, porque no asterisco ele estava. Ou seja, num ficheiro em que o sinal não chegava a vinte bots nomeados, chegava aos que não estavam nomeados, exatamente o contrário do que pretendíamos, e produzido pela mesma regra a funcionar tal como está escrita.
Porque é que este erro sobrevive a uma revisão
Três razões, todas estruturais, nenhuma delas distração.
O robots.txt lê-se de cima para baixo e a secção geral parece hierarquicamente superior. Escrever qualquer coisa lá dentro aciona a intuição que trazemos do CSS ou da configuração de servidores, onde a definição geral é o valor por omissão e a específica sobrepõe-se. No RFC 9309 não há sobreposição. Há escolha de um grupo e rejeição do resto do ficheiro.
Segunda razão: não existe ferramenta que assinale isto. Os testadores de robots.txt verificam se um dado endereço é permitido para um dado bot e não sabem nada sobre Content-Signal, porque não é uma diretiva do RFC. A linha passa como comentário aos olhos do validador e como política aos olhos da pessoa, e cada uma das leituras é coerente consigo mesma.
Terceira, e a mais importante: uma declaração de direitos não produz sinal de retorno. Se colocar mal um Disallow, ao fim de uma semana vê isso no relatório de indexação.
Se colocar mal um Content-Signal, não acontece nada observável, e a ausência de acontecimento tem o mesmo aspeto nos dois casos. Esta classe de defeitos encontra-se a ler o ficheiro, não a olhar para os efeitos, o que é incómodo de agendar, porque ler não tem gatilho.
As linhas fora dos grupos enganam, porque essas valem mesmo para tudo
Há neste ficheiro uma coisa que induz diretamente a intuição errada. Além dos grupos User-agent, o robots.txt conhece registos independentes de grupo, e o Sitemap é um desses registos. No nosso ficheiro ele fica logo a seguir ao grupo do asterisco:
Sitemap: https://wppoland.com/sitemap-index.xml
Agentmap: https://wppoland.com/.well-known/ai-catalog.jsonO Sitemap vale para o ficheiro inteiro, independentemente de onde o colocar e de quantos grupos existam por baixo. Ninguém o repete vinte vezes e ninguém precisa. Quem sabe como o Sitemap se comporta e vê o Content-Signal colocado na mesma zona do ficheiro, duas linhas acima, tem todo o direito de assumir que a linha se comporta da mesma forma.
Não se comporta: uma é um registo global, a outra é uma diretiva dentro de um grupo, nada na sintaxe sinaliza a diferença, e ambas são uma linha de dois membros com dois pontos, uma ao lado da outra.
A conclusão prática, quando se lê o ficheiro de outra pessoa: a indentação e a ordem não querem dizer nada, o que conta é se a diretiva está definida como diretiva de grupo. Allow, Disallow e Content-Signal são de grupo. Sitemap não é.
O que este artigo não resolve
Deixamos duas coisas de fora de propósito, porque não são nossas.
A primeira é o efeito jurídico da reserva. Os Content Signals invocam uma reserva de direitos expressa no direito de autor, e um texto nesse sentido está mesmo no comentário no topo do nosso ficheiro. Se e quando essa reserva é eficaz, decide um advogado e não quem edita o robots.txt. O nosso contributo é apenas técnico: se a declaração há de ter algum peso, tem pelo menos de chegar ao cliente a quem é dirigida, e a nossa não chegava.
A segunda é o comportamento de cada operador em concreto. Não medimos que crawler lê o Content-Signal, qual o respeita e o que faz com sinais incoerentes em grupos diferentes. Sem medição própria não temos nada a dizer aqui e não vamos repetir números alheios. A correção que descrevemos vale a pena independentemente desse conhecimento, porque arruma um ficheiro que dizia outra coisa do que o autor pretendia, e isso é um defeito por si só.
O que fazer ao processo
Verificar o alcance do sinal é trabalho de poucos minutos, feito uma vez, mas a manutenção não é de uma vez só. Cada grupo novo acrescentado ao ficheiro, e acrescentam-se com regularidade, porque a lista de crawlers de IA cresce de mês para mês, é um grupo sem sinal enquanto ninguém se lembrar dele.
Por isso o segundo comando acima pertence aos testes e não a uma nota. Uma regra que se verifica sozinha sobrevive; uma regra escrita num documento sobrevive até à edição seguinte feita por alguém que não leu o documento.
Vale também a pena lembrar de que fatia de tráfego estamos a falar. Na nossa medição de agosto de 2026, descrita no artigo sobre tráfego de bots num site pequeno, 72% dos pedidos não vinham de um navegador. O robots.txt é o único sítio onde falamos com essa maioria e a única coisa que essa maioria sabe sobre as nossas condições. Se a frase lá escrita está dirigida ao grupo errado, não é um erro suave, é silêncio.
Fica de pé um limite técnico que convém não disfarçar: o ficheiro apenas afirma, nunca fica a saber se alguém o leu. Quem precisar de mais do que uma afirmação acaba, por força, na camada anterior à aplicação, com todos os custos que essa camada traz.
Lista de verificação curta
- Conte os grupos
User-agente as linhasContent-Signalno seu ficheiro. Se os números não baterem certo, a diferença são grupos sem reserva. - Repita a linha em cada grupo a que deva aplicar-se. A repetição é aqui a forma correta, não um duplicado.
- Decida conscientemente se cada grupo recebe o mesmo conjunto de sinais. Vinte linhas idênticas costumam ser sinal de que ninguém decidiu.
- Confirme se tem grupos separados para papéis distintos do mesmo fornecedor, por exemplo transferências iniciadas pelo utilizador e recolha de corpus.
- Ligue a verificação à pipeline. A lista de crawlers cresce e cada grupo acrescentado começa sem sinal.
- Não conte a si próprio a história de que o sinal bloqueia alguma coisa. O bloqueio é a camada anterior à aplicação, isto é uma declaração.







