fix(ir): corrigir um trecho gasta orçamento de reconto - #297
Merged
henokteixeira merged 2 commits intoSep 7, 2026
Merged
Conversation
…ld have `MAX_RETELLS` exists so a team never gets stuck retelling: when it runs out the room stops and asks for a person. It was charged on the telling-back route alone, and a correction does not go through there — it goes through replace, which touched neither the budget nor the request for a person. The one limit the room has against trapping a team did not cover the path the team corrects by, and in a room where nobody reads and the facilitator is a voice, a team stuck in that cycle has no way to ask for help. Only the call that carries a new explanation counts. The service says why in its own words: the product has two corrections and not three, and re-recording the native always means the explanation is redone after it — so that is two steps of one attempt, and charging both would take two from the budget for a single correction, ending the budget in a round and a half and punishing the more complete correction. The neighbour agrees: what marks a spend there is `retelling`, telling one stretch back a second time. The budget is about telling again, not about recording again. Spent on the attempt and not on the result, for the reason already written on the neighbouring route: if only a correction that landed counted, then during a transcriber outage — when every attempt comes back empty — the team could correct forever, the budget would never run out, and the room's only route to a person would be unreachable exactly when the room is broken. A request that cannot succeed still costs nothing. A slice that moved arriving with audio, or a payload over the limit, are refused before anything is spent: a malformed request is not an attempt by the team.
Seven cases through the route, asking what the budget marked and what the room went on to offer. The one that matters most is the control: telling a new stretch back never spends a retell. Without it this becomes "every recording sent spends", and a team telling six stretches back for the first time would be handed to a person without having retold anything — punishing the path where nothing went wrong. Two more for the edges. Dividing is the team hearing two ideas where they told one: two rows against a recording that was already there, no audio over the wire, nothing retold — charging it would spend a team's budget on an act of reading. And the room that stopped says so in its own state, not only in the reply that carried it: a client ignoring the field would otherwise lose the one moment the room asked for help.
8 tasks
henokteixeira
deleted the
henok/eng-685-corrigir-gasta-orcamento-de-reconto
branch
September 9, 2026 18:22
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.
Fecha ENG-685. Independente da pilha 676/679/680 — sai da
maine vai para amain.Summary
MAX_RETELLS = 3existe para que a equipe nunca fique presa recontando: quando o orçamentoacaba, a sala para e pede uma pessoa. Ele era cobrado num lugar só —
POST /back-translation/chunks, e apenas comretelling=true.A correção de um trecho não passa por ali. Passa por
POST /segments/{id}/replace, e essarota não tocava no orçamento. O único limite que a sala tem contra prender uma equipe recontando
não cobria o caminho pelo qual a equipe de fato corrige — e numa sala onde ninguém lê e o
facilitador é uma voz, uma equipe presa nesse ciclo não tem como pedir ajuda.
Esta fatia torna as duas rotas simétricas: somar, gravar o estado, e pedir uma pessoa quando
estourar. Escolhida a saída (a) da issue; a (b) foi descartada.
A decisão de desenho: qual das duas formas de substituir gasta
Substituir tem duas formas, e só a que traz uma explicação nova gasta —
/replacecomarquivo. A chamada sem arquivo, que regrava o áudio nativo, não gasta.
Não é preferência: é o que o próprio código já dizia. O docstring de
capture_segment:Regravar o nativo nunca é uma correção completa — é sempre seguido de uma segunda chamada, com
arquivo, que traz a explicação. São dois passos de uma tentativa. Contar os dois cobraria
duas unidades por uma correção, e a equipe chegaria ao fim do orçamento em uma volta e meia,
punindo justamente a correção mais completa.
E alinha com o vizinho: em
/chunksquem marca o gasto éretelling, documentado como "tellingone stretch back a second time after a finding". O orçamento é sobre contar de novo, não
sobre gravar de novo. Com esta escolha, as duas formas de corrigir custam exatamente 1.
Duas consequências que decorrem dela:
são recusados antes de qualquer gasto — a rota já argumenta que "what is not stored first is
a request that cannot succeed". Requisição malformada não é tentativa da equipe.
sucesso contasse, uma queda do transcritor deixaria a equipe corrigindo para sempre e a rota
para uma pessoa ficaria inalcançável exatamente quando a sala está quebrada.
/replaceSegmentsResponseganhouneeds_person, comoBackTranslationChunkResponsejá tinha. O appnão lê esse campo —
TellingAgain.fromJsonlê apenassegmentsecaptured— então porenquanto o servidor avisa e o cliente descarta o aviso em silêncio. O lado do app está sendo
feito em paralelo; até ele chegar, o comportamento visível nesta rota não muda.
O aviso não se perde inteiramente, e isso importa para avaliar o risco.
mark_needs_persongrava o estado na própria sessão (
status = needs_person), queGET /sessions/{id}serve. Aparada é persistente, não uma menção única numa resposta: qualquer leitura seguinte do estado a
encontra. O caso
test_the_room_that_stopped_says_so_in_its_own_stateguarda exatamente isso.Test plan
Sete casos em
tests/test_internalization_room_segment_verbs.py, todos pela rota, perguntando oque o orçamento marcou e o que a sala passou a oferecer — nenhum lê estado interno.
test_correcting_a_stretch_spends_retell_budgettest_the_budget_runs_out_and_the_room_offers_a_persontest_the_budget_is_spent_on_the_attempt_not_on_the_resulttest_telling_a_new_stretch_never_spends_retell_budgettest_the_telling_back_route_still_counts_the_way_it_countedtest_dividing_a_stretch_is_not_correcting_and_spends_nothingtest_the_room_that_stopped_says_so_in_its_own_stateRED antes da implementação: 1, 2 e 3 vermelhos (
assert 0 == (0 + 1),assert 0 >= 3,assert 0 == (0 + 1)— o orçamento parado em zero); 4 e 5 verdes. Os dois últimos casos foramacrescentados por mim para os casos de borda do plano.
Casos de borda
duas linhas contra um áudio que já estava lá. Nenhum áudio cruza a rede e nada é recontado;
cobrar seria gastar o orçamento da equipe num ato de leitura. Com caso próprio.
demonstra: são três requisições HTTP separadas e o número acumula entre elas.
correção e a marca de parada. Perder a resposta seria pior que o problema; asseverado no
caso do estouro.
Números
Baseline medida na
mainatual antes de tocar em nada: 2344 passed, 5 skipped, 1 xfailed.Depois: 2351 passed, 5 skipped, 1 xfailed — a baseline mais exatamente os sete novos.
ruff check,ruff formatemypy applimpos (596 arquivos).