Text Share Online

12112112

Fiz uma leitura extremamente criteriosa da v5.9, olhando não só a intenção arquitetural, mas também a consistência documental, a executabilidade técnica, a estabilidade operacional e o risco real de implementação equivocada.

Minha conclusão, de forma direta, é esta:

a v5.9 melhorou de forma relevante sobre a v5.8, mas ainda não está no ponto que eu chamaria de versão final blindada.
Ela já está muito próxima disso, porém ainda restam alguns pontos que, sob a ótica de arquitetura de software e operação em produção, eu trataria como obrigatórios antes de carimbar como “ótima”.

Minha nota atual seria algo em torno de 9,6 de 10.

O que mudou de verdade nesta versão foi bom. O problema é que alguns resíduos conceituais da v5.8 continuam vivos dentro da v5.9, e agora eles aparecem mais como inconsistências entre trechos do documento do que como ausência de conteúdo.

1. O que realmente ficou melhor

Antes das críticas, vale registrar que houve avanços claros.

1.1 Consolidação dos arquivos externos

A redução de 7 arquivos para 4 faz sentido arquiteturalmente. Você reduziu dispersão, simplificou a governança e deixou mais claro o papel de cada artefato.

1.2 Versionamento automático por hash

A direção é correta. Remover dependência manual de TAXONOMY_DICT_VERSION é um ganho real de robustez operacional.

1.3 PASSO 3 do CRON deixou de ser placeholder

Isso era uma lacuna séria e agora existe uma direção real de execução.

1.4 Correção de alias_of

A limpeza semântica do enum foi importante.

1.5 Query de confidence_median

Trocar filtro por UUID e incluir pending_review foi uma correção boa e necessária.

1.6 Cobertura de Estagiário e Estagiária

Foi um ajuste pequeno, mas tecnicamente correto e importante para não perder sinal semântico.

Ou seja, a v5.9 não é uma revisão cosmética. Ela avançou de verdade.


2. Os bloqueadores que ainda ficaram abertos

Aqui estão os pontos que eu considero mais sérios.

2.1 O versionamento automático ficou conceitualmente melhor, mas documentalmente ainda está contraditório

Esse é o principal problema da v5.9.

Você diz que:

  1. TAXONOMY_DICT_VERSION foi removida

  2. o sistema virou a fonte de verdade

  3. o campo version interno dos JSONs deixa de ser mantido manualmente

Só que, ao mesmo tempo:

  1. o schema zod ainda exige version

  2. todos os exemplos dos 4 arquivos continuam com "version": "1.2"

  3. a seção “Versão atual” ainda mostra dict 1.2

  4. o texto continua tratando a versão do dicionário como algo estático e humano legível

Isso cria uma contradição de implementação.

Hoje a spec está dizendo duas coisas ao mesmo tempo:

  1. a versão é automática e derivada por hash

  2. a versão continua vivendo dentro dos arquivos e sendo exibida manualmente

As duas abordagens não coexistem bem sem uma regra explícita.

Minha recomendação

Escolher uma só verdade.

A solução mais limpa seria:

  1. remover o campo version dos arquivos JSON

  2. remover version do schema zod

  3. persistir o hash e a versão derivada em uma estrutura própria do banco

  4. deixar claro que o número de versão apresentado ao sistema é derivado e não autoral

Se quiser manter version dentro do arquivo por legibilidade humana, então precisa dizer explicitamente que:

  1. ele é apenas informativo

  2. ele não é usado como fonte de verdade

  3. o loader pode até validá lo, mas não confiar nele

Hoje isso ainda não está fechado.


2.2 O uso de job_runs.metadata reabre uma dependência estrutural que a própria spec vinha reduzindo

Esse ponto é importante.

Ao longo da arquitetura, você separou bem:

  1. curate_runs para histórico operacional da curadoria

  2. curate_run_items para detalhe por vaga

Só que o versionamento automático dos arquivos foi jogado em job_runs.metadata.

Isso traz vários problemas:

  1. job_runs não está formalmente modelado nesta spec como peça central da curadoria

  2. a shape de metadata não foi formalizada

  3. a retenção desse conteúdo não foi definida

  4. a relação entre job_runs e curate_runs ficou conceitualmente torta

  5. você passa a depender de uma tabela que antes parecia estar saindo do centro da arquitetura da curadoria

Além disso, o próprio código de exemplo busca o último run em job_runs, não em curate_runs, o que fragiliza a rastreabilidade.

Minha recomendação

Criar uma estrutura dedicada, algo como taxonomy_revisions ou taxonomy_versions, com:

  1. id

  2. dict_version

  3. hash_bundle

  4. files_payload

  5. created_at

  6. created_by_run_id

Isso deixa o versionamento:

  1. transacional

  2. auditável

  3. independente do legado de job_runs

  4. semanticamente alinhado ao problema

Hoje a solução funciona como ideia, mas ainda está encaixada na peça errada.


2.3 A rotina de hash tem risco de corrida e promoção de versão não determinística

A pré rotina detectDictChanges() ainda não está pronta para concorrência real.

O problema é simples:

  1. dois runs podem começar quase ao mesmo tempo

  2. ambos leem o mesmo último estado

  3. ambos detectam mudança

  4. ambos geram a mesma próxima versão

  5. ambos persistem resultados em paralelo

Dependendo da ordem de gravação, você pode ter:

  1. mesma versão representando snapshots diferentes

  2. mesma mudança registrada duas vezes

  3. competição entre Fluxo A e Fluxo B por avanço de versão

Outro ponto: o exemplo de código fala em buscar o último run “bem sucedido”, mas a query demonstrada só exclui running. Isso inclui error e partial, o que contradiz o texto.

Minha recomendação

O avanço de versão precisa ser serializado.

A forma mais segura seria:

  1. criar tabela própria de revisões

  2. calcular o bundle hash de todos os arquivos

  3. verificar se esse bundle já existe

  4. se existir, reutilizar a versão existente

  5. se não existir, criar nova versão em transação única com lock

Ou seja, a versão deveria nascer do snapshot, e não de uma contagem oportunista feita no começo de qualquer run.


2.4 curation_status continua sem dominar o documento inteiro

Esse continua sendo o maior problema semântico do pipeline.

A v5.9 afirma corretamente que curation_status é a fonte de verdade. Mas vários trechos críticos continuam usando a lógica antiga:

  1. query de cache ainda usa low_quality = false

  2. índice de pending ainda usa skills IS NULL AND low_quality IS NULL

  3. observação de race condition do Fluxo B ainda usa a lógica antiga

  4. relatórios continuam filtrando por low_quality

  5. o próprio texto de Fluxo A ainda descreve pendência com os critérios antigos em alguns pontos

Isso não é só ruído editorial. Isso cria risco real de duas implementações coexistirem.

Minha recomendação

Fazer uma varredura total e padronizar assim:

  1. fila de curadoria usa curation_status

  2. cache usa curation_status

  3. relatórios operacionais usam curation_status

  4. índices parciais usam curation_status

  5. low_quality fica declarado apenas como compatibilidade legada

Hoje a spec ainda mistura os dois modelos.


2.5 retryable_error continua sem caminho formal de reentrada automática

Esse ainda é um bloqueador real.

A busca de pendentes está definida como:

WHERE curation_status = 'pending'

Só que falhas transitórias movem a vaga para:

retryable_error

Resultado:

a vaga falhou, deveria voltar para a fila, mas o próprio pipeline deixa de buscá la.

O CRON PASSO 3 só trata quarentena por mudança de versão. Não trata retryable_error.

Minha recomendação

Escolher uma das duas abordagens e documentar de forma única:

  1. ou a fila busca IN ('pending', 'retryable_error')

  2. ou existe um job explícito de requeue que converte retryable_error para pending

Enquanto isso não for resolvido, o comportamento real diverge da intenção da spec.


2.6 O caminho de gravação em job_postings continua incompleto

O trecho [CÓDIGO — Atualizar job_postings] ainda não grava explicitamente:

  1. curation_status

  2. reset de llm_parse_fail_count em sucesso

  3. last_curation_error_type

  4. is_internship em reingestão ou em persistência normal

  5. limpeza de quarentena após sucesso

  6. atualização coerente entre sucesso, fallback, low_quality e erro transitório

Hoje você descreve bem o que fazer em falha e quarentena, mas não fechou a matriz completa de persistência do caminho feliz.

Minha recomendação

Adicionar uma matriz explícita do tipo:

  1. status='success' ou pending_reviewcuration_status='curated'

  2. status='fallback' → decidir se continua curated ou se ganha status próprio operacional

  3. status='low_quality'curation_status='low_quality'

  4. status='failed' transitório → curation_status='retryable_error'

  5. quarentena → curation_status='quarantined_llm_output'

Hoje esse fechamento ainda não está completo.


2.7 circuit_breaker_state continua aparecendo como conceito, não como schema

Na v5.8 você já tinha anunciado a persistência do circuit breaker. Na v5.9 isso continua sem schema formal.

Não vi aqui:

  1. migration da tabela

  2. colunas

  3. regra de abertura

  4. regra de fechamento

  5. janela de observação persistida

  6. cooldown efetivo

  7. estratégia de leitura por múltiplas instâncias

Isso é um buraco importante porque o circuit breaker é peça de confiabilidade, não detalhe secundário.

Minha recomendação

Adicionar seção formal com tabela própria, por exemplo:

  1. breaker_name

  2. state

  3. window_started_at

  4. window_failures

  5. window_total

  6. opened_at

  7. cooldown_until

  8. last_transition_at

Sem isso, a solução ainda está só na intenção.


2.8 similarity_score continua sendo mencionado sem existir no schema

Você ainda escreve:

“registrar similarity_score no curate_run_items

Mas ele não existe no schema da tabela.

Esse é um problema objetivo.

Minha recomendação

Adicionar explicitamente:

similarity_score NUMERIC(5,4)

Sem isso, a spec manda persistir algo que a migration não suporta.


2.9 A distinção entre batch_output_parse_error e item_output_parse_error ainda não foi refletida no modelo persistido

A ideia está correta e madura. Mas o schema continua sem espelhar isso.

Hoje o enum de error_type continua com llm_output_parse_error genérico.

Então a spec pede uma distinção operacional que o banco não consegue representar claramente.

Minha recomendação

Ou você:

  1. adiciona dois tipos distintos ao enum

ou

  1. diz explicitamente que essa distinção é apenas lógica interna e nunca é persistida

Hoje ainda ficou ambíguo.


3. Inconsistências novas ou remanescentes

3.1 domains.json foi simplificado, mas a lógica antiga ainda aparece no pipeline

Você removeu is_idiomatic e is_compound_valid, mas ainda restaram referências a eles no texto.

Exemplos claros:

  1. o fluxo de validação ainda pergunta sobre is_compound_valid

  2. a gramática ainda fala em domínios adjetivais não idiomáticos

  3. o documento ainda raciocina em cima de uma semântica que a nova versão declarou removida

Isso precisa ser limpo.


3.2 family_synonyms.json introduziu uma família que não existe na lista fechada

Você colocou:

"Assessor": "Assessor"

Só que Assessor não está na lista oficial de famílias válidas.

Isso quebra a coerência da taxonomia fechada.

Minha recomendação

Ou:

  1. adiciona Assessor ao conjunto fechado com regra própria

ou

  1. remove essa entrada

Do jeito que está, o arquivo contradiz a gramática oficial.


3.3 As referências a arquivos antigos não foram totalmente removidas

Ainda encontrei resíduos de nomenclatura antiga, como:

  1. siglas.json

  2. equivalencias.json

  3. cross_domain_map.json

Eles aparecem em comentários, exemplos, notas de governança e até em trechos de lógica.

Isso é perigoso porque abre espaço para implementação híbrida.


3.4 O prompt ainda continua duplicando mapeamentos exatos

A tabela inicial diz que os mapeamentos explícitos saíram do prompt. Mas no P9 eles continuam listados de forma concreta.

Mesmo com a nota dizendo que são “referência semântica”, na prática continuam sendo mapeamentos literais dentro do prompt.

Isso enfraquece o princípio:

o prompt ensina a pensar, o JSON guarda o que saber.

Minha recomendação

Deixar no prompt apenas o princípio e 1 ou 2 exemplos ilustrativos, não a lista inteira.


3.5 A seção mensal ainda cita cross_domain_map.json

Esse é um resíduo objetivo da versão anterior.

Se o arquivo foi absorvido por domains.json, ele não deveria mais aparecer em governança mensal.


4. Problemas de integridade de dados que ainda merecem correção

4.1 source em job_canonical_roles ainda não está NOT NULL

Hoje está como default, mas sem NOT NULL.

Eu colocaria NOT NULL sem hesitar.


4.2 Falta garantir rejected_reason quando status='rejected'

Isso está dito semanticamente, mas não está fechado como constraint.

Eu adicionaria:

CHECK (status != 'rejected' OR rejected_reason IS NOT NULL)


4.3 Falta impedir auto referência em alias_of_id e merged_into

Hoje um canônico pode, em tese, apontar para si mesmo.

Mesmo que a aplicação nunca faça isso, eu barraria no banco.


4.4 Falta garantir que destino de alias_of e deprecated seja semanticamente válido

Idealmente:

  1. alias_of_id deve apontar para um canônico active

  2. merged_into deve apontar para um canônico active

A spec hoje descreve isso conceitualmente, mas não fecha a integridade.


5. Problemas operacionais e métricos

5.1 O recálculo de distinct_sources_count continua estruturalmente frágil

Esse problema ainda não foi resolvido.

O PASSO 2 do CRON faz join de job_canonical_role_sources com job_postings apenas por canonical_role_id.

Isso não garante que a empresa contada seja exatamente a mesma empresa que ainda possui vaga ativa naquela janela.

Em outras palavras:

você pode recontar fontes históricas de um canônico só porque existe alguma vaga ativa daquele canônico.

Minha recomendação

A solução correta passa por uma destas opções:

  1. armazenar normalized_company também em job_postings

  2. vincular a evidência da source a uma vaga específica

  3. recalcular por last_seen_at confiável e vinculado ao posting

Do jeito atual, o recálculo ainda pode super contar.


5.2 partial continua com regra estreita demais

Hoje continua assim:

partial = failed > 0 AND curated > 0

O problema continua igual:

  1. se houver apenas fallback e falha, sem curated, o run não é claramente partial

  2. se todas as vagas falharem por timeout, mas sem falha estrutural de banco, a classificação fica ambígua

Minha recomendação

Redefinir assim:

  1. success quando failed = 0

  2. partial quando houver mistura de resultado útil e falha técnica

  3. error quando nenhuma vaga puder ser processada por falha sistêmica real

Hoje a semântica ainda está mais apertada do que o comportamento operacional pede.


5.3 A query “Throughput por hora” continua contando runs, não batches

Ela usa curate_runs, mas chama a contagem de “batches”.

Está metodologicamente errada.


5.4 A query de “Cobertura de cache” ainda não mede hit rate real

Ela mede volume manual versus volume via API.

Isso é uma métrica útil, mas não é cobertura de cache no sentido técnico.

Para cache de verdade, faltam eventos como:

  1. cache_hit

  2. cache_miss

  3. fantastic_called

  4. fantastic_returned_zero

  5. chave de busca normalizada


5.5 O checklist de deploy ainda não incorporou tudo que a própria v5.9 exige

Você acrescentou a variável EMBEDDING_SIMILARITY_REPLACE_THRESHOLD, o que foi bom.

Mas ainda faltam itens explícitos para:

  1. circuit_breaker_state

  2. estrutura de versionamento de taxonomia

  3. revisão completa de renome de arquivos

  4. validação de ausência de conceitos removidos como is_compound_valid


6. Questões de modelagem e implementação que ainda merecem endurecimento

6.1 O schema zod de domains.json ainda aceita combinações semanticamente inválidas

Hoje ele permite coisas como:

  1. is_prohibited=true sem prohibited_reason

  2. canonical="X" junto com is_prohibited=true

  3. canonical apontando para si mesmo

  4. redirecionamentos em cadeia não documentados

Minha recomendação

Adicionar superRefine para impor:

  1. is_prohibited=true exige prohibited_reason

  2. is_prohibited=true não pode coexistir com canonical

  3. canonical não pode gerar ciclo

  4. redirecionamento deve ser de um salto só, ou então a resolução precisa ser documentada com detecção de ciclo


6.2 O lookup de equivalences.json ainda precisa de regra lexical mais explícita

Você escreve que a sigla é expandida antes de ruído geográfico, mas ainda não ficou suficientemente formalizado se o matcher é:

  1. exato no título inteiro

  2. por token

  3. por expressão

  4. por fronteira de palavra

  5. com precedência contextual

No caso de AM, isso é especialmente crítico.

Sem esse fechamento, um desenvolvedor pode implementar do jeito errado e reabrir o bug.


6.3 O reingestion ainda continua resetando menos do que deveria

O bloco de ON CONFLICT melhorou, mas eu ainda resetaria também:

  1. seniority_inferred

  2. low_quality

  3. last_curation_error_type

  4. quarantined_at

  5. quarantine_reason

  6. quarantined_at_prompt_version

  7. quarantined_at_dict_version

  8. is_internship

Se a vaga foi republicada com conteúdo novo, o estado de curadoria antigo deve morrer por completo.


7. Meu veredito final sobre a v5.9

A v5.9 está melhor que a v5.8. Isso é inequívoco.

Mas, sob uma ótica de arquitetura madura, ainda não é a versão final ótima por cinco razões principais:

  1. o versionamento automático ainda está contraditório e mal ancorado estruturalmente

  2. curation_status ainda não dominou toda a spec

  3. retryable_error ainda não volta automaticamente para a fila

  4. há conceitos removidos que continuam vivos em vários trechos

  5. ainda faltam peças formais importantes, como circuit_breaker_state e similarity_score

Minha classificação

Aprovada para staging forte e shadow mode sério.
Ainda não aprovada como spec final definitiva de produção plena sem mais uma rodada de endurecimento.

O que eu trataria como obrigatório antes de chamar de versão final

  1. fechar o desenho de versionamento automático em estrutura própria

  2. migrar toda a spec operacional para curation_status

  3. resolver o fluxo de reentrada de retryable_error

  4. formalizar circuit_breaker_state

  5. adicionar similarity_score

  6. limpar todos os resíduos de arquivos e flags removidas

  7. corrigir o recálculo de distinct_sources_count

  8. endurecer constraints de integridade em job_canonical_roles

  9. fechar a persistência completa do caminho feliz em job_postings

Share This: