feat(sala): a resposta diz qual trecho ainda não foi contado - #299
Merged
Merged
Conversation
`first_untold` é o complemento de `told_back` sobre a mesma lista, e fica ao lado dela para que a contagem que trava o analista e o endereço para onde a equipe é mandada não possam discordar. O primeiro na ordem da passagem, não um qualquer: a equipe conta a passagem na sequência dela, e mandá-la para um buraco no meio enquanto há um anterior aberto inverte a ordem do próprio trabalho. Receber a lista em vez do id da sessão é o que mantém uma versão retirada fora da resposta: só trechos que já contam são olhados.
O fail-safe da família H já sabia que faltava um trecho; não dizia qual. Sem endereço, o app só tinha um movimento — devolver a equipe à tela de ensaio, que apaga todas as gravações da passagem. Uma explicação faltando custava a manhã inteira. `untold_segment_id` ganha campo próprio em vez de reusar `finding_segment_id` porque os dois pedem coisas diferentes da sala: um achado é um trecho que a equipe contou e sobre o qual o analista tem uma correção; este é um trecho sem nenhuma retrotradução. Ler um pela ausência do outro é exatamente a inferência que causou o defeito. Nada da fala muda: a linha da família H, o `checked` falso e o analista que não lê subconjunto continuam como estavam.
Os cinco casos do critério de aceite, pela rota, do jeito que o app a chama. Cada um foi provado ser um portão de verdade por mutação: nomear o último em vez do primeiro derruba só o caso da ordem; olhar a tabela crua derruba só o caso da versão retirada; desligar o portão derruba o caso que protege o fail-safe, que passava de saída.
O parágrafo do docstring dizia uma garantia que `first_untold` não dá: entregue a ela `retired_segments(...)` e ela aponta uma versão retirada. A propriedade é de `final_segments`, e repeti-la aqui é a duplicação contra a qual o docstring do próprio módulo avisa. O caso que protege o fail-safe só afirmava coisas que já passavam antes desta fatia — um portão incapaz de reprovar. Agora afirma o que é novo: que ter endereço não vem junto com `checked` verdadeiro nem com um achado do analista. Reprova com a resposta de antes da fatia. E dividir um trecho é o outro jeito de abrir um buraco: as duas metades nascem sem nada que a equipe disse e ficam onde o pai estava, que é onde a ordem da passagem deixa de ser coluna e vira caminhada. Caso novo, além do plano.
This was referenced Sep 2, 2026
This was referenced Sep 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
🤖 Generated with Nori
Quando a equipe grava um trecho na língua materna mas nunca o conta na língua-ponte, o servidor já parava com o fail-safe da família H (
UNTOLD_STRETCH) — mas a resposta não dizia qual trecho faltava. Sem endereço, o app só tinha um movimento: devolver a equipe à tela de ensaio, o que apaga todas as gravações da passagem. Uma explicação faltando custava a manhã inteira.first_untold(segments)emapp/services/internalization_room/segments.py— o primeiro trecho, na ordem da passagem, que conta e não carrega retrotradução. Fica ao lado detold_backde propósito: a contagem que trava o analista e o endereço para onde a equipe é mandada saem da mesma lista e não podem discordar.finish()(app/api/internalization_room/back_translation.py) passa a devolver esse endereço junto com a linha da família H.Nada da fala mudou. Nenhum arquivo de prompt e nenhuma linha falada foi tocado — o diff são quatro arquivos, todos de código.
O campo que a fatia do app vai ler
Em
BackTranslationVerdictResponse(app/models/internalization_room.py). É oIRSegment.id(UUID em texto), o mesmo endereço quefinding_segment_idusa. Vem preenchido apenas na resposta do fail-safe H; em todo o resto do caminho ficanull.Na resposta do trecho não contado:
checked: false,findings_remaining: 0,finding_kind: null,finding_segment_id: null,audio_urlcom a linha H sintetizada,fixed_line: "".Por que campo próprio e não reusar
finding_segment_id. Os dois pedem coisas diferentes da sala. Um achado é um trecho que a equipe contou e sobre o qual o analista tem uma correção — o app toca o achado e pede para recontar. Um trecho não contado não tem retrotradução nenhuma — o app precisa abrir a gravação da língua-ponte pela primeira vez. São telas diferentes. Reusar um campo obrigaria o app a inferir qual dos dois casos é pela ausência definding_kind, e inferir significado pela ausência de um dado é exatamente o que produziu este defeito. Os dois campos são mutuamente exclusivos por construção: o caminho do H retorna antes do analista rodar.Compatível com app antigo: campo novo, default
null, nenhum campo existente mudou de nome, tipo ou significado. Sem migração — o dado já existia nas colunas atuais.Test plan
Cinco casos novos em
tests/test_ir_the_room_names_the_untold_stretch.py, todos pela rota, do jeito que o app a chama:checkedfalso, o analista não lê subconjunto, e a linha falada continua vindo deutterances(FailSafe.UNTOLD_STRETCH, ...).Cada caso foi provado ser um portão de verdade por mutação, e cada mutação é pega exatamente pelo caso que deveria pegá-la:
O caso que protege o fail-safe passava na RED na primeira versão — só afirmava coisas que já estavam certas, o que é um portão incapaz de reprovar. Foi endurecido para afirmar o que é novo (endereço não vem com
checkedverdadeiro nem com achado do analista) e agora reprova contra o comportamento de antes da fatia.Para verificar:
Suíte inteira: 2350 passaram, 5 skipped, 1 xfailed, 0 falhas (9m00s).
ruff check,ruff format --checkemypy app/limpos.Achados fora do escopo desta fatia — registrados, não consertados
Encontrados na autorrevisão e verificados no código. Nenhum deles é tocado por este PR.
release.py:153pode publicar um trecho com"text": null. A variável local se chamatold_back, mas recebeawait final_segments(...)— a lista inteira, contada ou não. O bloqueadorno_telling_back(:170) só testa se a lista está vazia, e_segment_view(:88) serializa"text": segment.transcript. Uma sessão que contou tudo, foi analisada limpa, regravou um trecho e nunca o recontou passa pelos dois bloqueadores e entrega o artefato ao Refine com um trecho de texto nulo.first_untoldé exatamente o predicado que esse bloqueador quer.used_fail_safecontinuaFalseno ramo do trecho não contado, embora a linha venha dechoose(FailSafe.UNTOLD_STRETCH, ...). Pré-existente; quem apura telemetria por esse campo subconta este caminho.add_chunk:74chama detoldo resultado definal_segments— que inclui os não contados. Comportamento correto, nome enganoso agora quetold_backefirst_untoldmoram no mesmo módulo.tests/test_ir_the_analyst_reads_all_of_it_or_none.py:8afirma que regravar a materna é o único jeito de ter um trecho final sem explicação. Dividir um trecho também é — as duas metades nascem sem retrotradução. Já estava desatualizado antes desta fatia.Share Nori with your team: https://www.npmjs.com/package/nori-skillsets