Skip to content

[DEBT] Stabilization narrative over-infers quality ("suggests durable delivery"); no i18n parity guard - #237

Open
rafaeldearaujop wants to merge 1 commit into
mainfrom
fix/stabilization-wording
Open

[DEBT] Stabilization narrative over-infers quality ("suggests durable delivery"); no i18n parity guard#237
rafaeldearaujop wants to merge 1 commit into
mainfrom
fix/stabilization-wording

Conversation

@rafaeldearaujop

Copy link
Copy Markdown

[DEBT] Stabilization narrative over-infers quality ("suggests durable delivery"); no i18n parity guard

Em uma frase: quando um arquivo não é mais mexido, o relatório escreve
"isso sugere entrega durável" — mas ficar parado não prova que está
certo (o paper mostra 22,7% dos defeitos também "sobrevivendo"), e o
vocabulário da marca é justamente "durável", então o over-claim interno
alimenta a promessa externa.

Aberta como PR direta, não como issue: a decisão já foi tomada e o fix
está validado; o texto segue o template tech-debt.yml para
rastreabilidade. Referências arquivo:linha apontam para main @ da16235.
Esta mudança é independente: aplica, testa e valida sozinha sobre
main. Toda
preocupação da análise adversária tem disposição final.


Qual é a dívida?

Três strings de narrativa (EN e PT-BR) inferem durabilidade/qualidade a
partir de persistência (arquivo não revisitado dentro da janela de churn):

Chave em iris/i18n.py EN PT-BR Texto atual (EN)
finding_stabilization_high :129 :1007 "…the majority of changes persisted without further modification. This suggests durable delivery."
trend_finding_stabilization_up :430 :1311 "…compared to the {baseline}-day baseline. This suggests delivery is becoming more durable."
explain_intent_stability_body :325 :1205 "…reveals which types of changes produce durable outcomes and which require further iteration."

Reforçadas pelo dicionário — docs/METRICS.md §1 chama stabilization_ratio
de "Core quality signal" — e pelo docs/ONE-PAGER.md:72: "Platform
teams evaluating which AI tools produce the most durable code"
(enquadramento
de ranking de ferramentas, que o paper desmonta na RQ2).

Segunda parte da dívida: não existe nenhum teste de narrativa ou i18n
(ls tests | grep -i "narrat|i18n|report" retorna vazio). O narrative.py
formata por chave com placeholders nomeados (narrative.py:99-108,720-724);
uma chave faltando numa língua é KeyError em runtime, um placeholder
divergente é erro de format() — e nada pega isso antes do usuário.

Por que é dívida?

  1. Contradiz a Absolute Rule build(deps): Bump actions/setup-node from 4 to 6 #4 (CLAUDE.md:54): "Metrics are
    hypotheses, not truths". A frase transforma uma hipótese em veredito.
  2. Confunde ausência de retoque com correção. O paper mediu o oposto do
    que a frase sugere: de 464.900 issues introduzidas por IA, 105.364
    (22,7%) ainda estão no HEAD
    , incluindo 4.893 com mais de nove meses
    (§V-C, Table VI, p.8). Código não revisitado é, com frequência, código
    que ninguém olhou — não código bom. stabilization_ratio não distingue os
    dois casos, e o texto afirma que distingue.
  3. Alimenta a promessa da marca. "Durável" é vocabulário de produto
    (platform/lib/translations.ts:43"whether AI is making your code more
    durable — or just more"
    ; deck-content.ts:53; README.md §What It Does).
    Quando a métrica de durabilidade real existe (§8, survival_rate via
    git blame), deixar stabilization também se chamar "durável" mistura dois
    instrumentos distintos sob uma palavra.
  4. Custo de não ter guarda i18n: um relatório em PT-BR pode quebrar em
    produção por uma chave esquecida, sem que nenhum teste da CI falhe.

Como chegou aqui?

A narrativa de stabilization é do v0 (stabilization.py docstring: "This is
the core signal/noise proxy in Iris"
), quando era o único proxy de
durabilidade. Quando durability.py (blame no HEAD) chegou, o vocabulário
não foi separado. A ausência de testes de i18n é dívida de origem: o módulo
nasceu como dicionário plano e nunca ganhou invariantes.

Plano de migração

  • Reescrever as 3 chaves em EN e PT-BR, preservando placeholders
    ({ratio} · {delta} {recent} {baseline} · {feat_ratio} {fix_ratio} {refactor_ratio}):
    • finding_stabilization_high → "…Persistence indicates low rework, not verified correctness." / "…Persistência indica pouco retrabalho, não correção verificada."
    • trend_finding_stabilization_up → "…Less of the recent code is being reworked." / "…Menos do código recente está sendo retrabalhado."
    • explain_intent_stability_body → "…which types of changes are revisited soon after landing and which are not." / "…quais tipos de mudanças são revisitadas logo após entrarem e quais não são."
  • docs/METRICS.md §1: "Core quality signal" → "Core rework signal", com
    a frase: "Persistence means a file was not revisited within the window —
    it is not evidence of correctness (unreviewed or defective code persists too)."
  • docs/ONE-PAGER.md:72 → "Platform teams understanding how AI-assisted
    changes hold up after they land" (remove o enquadramento de ranking).
  • tests/test_i18n_parity.py (4 testes): mesmas chaves em todas as
    línguas; mesmos placeholders por chave; .format() das 4 chaves de
    stabilization com os argumentos que narrative.py passa; guarda de
    vocabulário ("durable/durável/duráveis") nas 3 chaves reescritas.
  • finding_stabilization_low mantida como está (ataque 3).
  • CHANGELOG: uma linha ("narrative wording") no release.

Critérios de aceite (antes do merge)

  • Revisão das duas frases em PT-BR por falante nativo do time, na PR
    (ataque 5). As frases estão no plano acima; a revisão é de tom, não de
    correção.
  • CI verde no job cli.

Deadline / gatilho pra pagar

Antes do próximo release da CLI (é texto; entra em qualquer versão), e
antes de qualquer material externo novo que cite "79% vs 64%".


Evidência de validação (isolada: main + só esta mudança)

  • tests/test_i18n_parity.py passa nas duas línguas; ao rodar pela primeira
    vez sobre main não encontrou nenhuma chave ou placeholder divergente
    pré-existente — a dívida i18n era de ausência de guarda, não de bug
    latente.
  • Suíte completa: 477 pass / 0 fail (LC_ALL=C; 473 da base + 4
    novos).
  • A/B end-to-end (engine base vs engine com esta mudança, mesmo
    repo-alvo, runs em par, gh desabilitado, 90 dias): metrics.json
    byte-idêntico (zero chaves alteradas, adicionadas ou removidas).
    report.md EN: exatamente 2 frases diferem (finding_stabilization_high,
    explain_intent_stability_body), com e sem --trend. A terceira string
    (trend_finding_stabilization_up) só renderiza quando a estabilização
    melhora entre janela recente e baseline
    (narrative.py:668-674,717-725) — neste repo a estabilização caiu 7 pp
    (30 d vs baseline de 90 d), então renderizou trend_finding_stabilization_down,
    inalterada e idêntica nos dois relatórios; a string _up é coberta pelo
    smoke de .format() em test_i18n_parity.py, não pelo E2E. Nenhuma outra
    linha de narrativa mudou. PT-BR: idem.
  • README.md:23 ("AI-assisted code stabilizes at 79% vs 64%") mantida:
    é afirmação factual sobre a métrica, não inferência de qualidade.

Como reproduzir

LC_ALL=C pytest tests/ -q                                   # 477 passed
iris <repo> --days 90 --no-push --lang en --out /tmp/en     # ver "Persistence indicates low rework"
iris <repo> --days 90 --no-push --lang pt-br --out /tmp/pt  # ver "Persistência indica pouco retrabalho"

Análise adversária (pós-implementação) — toda linha com disposição final

# Ataque Resposta Disposição
1 Importa uma alegação de outro instrumento. O paper mede sobrevivência de issues; o Iris mede persistência de arquivos. A ressalva é epistêmica, não empírica: não afirma que código persistente é ruim; afirma que a métrica não licencia a inferência de correção. Válida por lógica; o paper só ilustra o risco. ✅ Mitigado (a redação nova não faz alegação empírica).
2 O teste de vocabulário é opinativo e frágil. Guarda de regressão escopada a 3 chaves, para esta dívida. Decidido: manter a guarda. Codifica uma Absolute Rule permanente (#4) em três strings e só dispara se alguém reintroduzir exatamente esta dívida. A docstring do teste explica como mudar de forma deliberada.
3 Assimetria deixada. finding_stabilization_low ainda diz "may indicate significant corrective effort". Está hedgeada ("may") e concatenada a systemic_stabilization_low, que oferece leituras alternativas. A positiva não tinha hedge nenhum; por isso foi o alvo. Decidido: não tocar. "Corrective effort" é o vocabulário estabelecido do projeto para churn (churn_calculator.py docstring, relatório) — mudar uma string criaria inconsistência com o resto.
4 "Durável" continua em todo o resto — copy da platform, deck, README.md. Intencional: nesses lugares "durável" refere-se à métrica de durabilidade (survival_rate via blame), uso correto. O problema era stabilization pegar a palavra emprestada. ✅ Fora de escopo por desenho.
5 Qualidade da redação em PT-BR não revisada por falante nativo do time. Gramaticalmente correta; tom pode ser ajustado. Critério de aceite: revisão na PR (seção acima).
6 Toca i18n.py, um arquivo de 1.780 linhas sem testes, em duas línguas. Exatamente por isso a issue inclui a guarda de paridade e o smoke de format(). ✅ Mitigado — e a mitigação sobrevive à issue.

Fora do escopo

  • Copy da platform, deck e README.md que usam "durável" para a métrica de durabilidade.
  • Renomear stabilization_ratio ou mudar seu cálculo.
  • Traduções adicionais.

Issues relacionadas (verificado contra as 63 issues do repo, abertas e fechadas — sem duplicata)

Nenhuma issue existente trata da redação da narrativa de stabilization nem
de testes de i18n (busca por título e corpo em 2026-09-08). #189
(fechada, aiPct semanal sem tamanho mínimo de amostra) é o precedente mais
próximo em espírito — também corrigia uma leitura enganosa de um número
correto.

Referências

  • Paper: Y. Liu, R. Widyasari, Y. Zhao, I. C. Irsan, J. Chen, D. Lo, Debt Behind the AI Boom, arXiv:2603.28592v2 [cs.SE], 2026 — §V-C "Persistence of AI-Introduced Debt" e Table VI (p.8-9); §V-B RQ2 sobre não ranquear ferramentas (p.8).
  • Código (main @ da16235): iris/i18n.py:129-133,325-330,430-434 (EN) e :1007-1011,1205-1210,1311-1315 (PT-BR); iris/reports/narrative.py:97-108,668-674,717-725; iris/metrics/stabilization.py:1-16.
  • Docs: docs/METRICS.md §1 e §8; docs/ONE-PAGER.md:19,37,72; docs/PRINCIPLES.md; CLAUDE.md:54 (Rule build(deps): Bump actions/setup-node from 4 to 6 #4).

…parity guard

Three narrative strings (EN and PT-BR) read persistence as durability: a file not revisited within the churn window is not evidence of correctness (Liu et al. 2026 report 22.7% of AI-introduced issues still at HEAD). Reword them, drop 'quality signal' from METRICS.md, and add tests/test_i18n_parity.py — key parity, placeholder parity, format smoke and a vocabulary guard for Absolute Rule #4.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@rafaeldearaujop rafaeldearaujop added the type: tech-debt Código sub-ótimo conhecido, workaround, ou cleanup pendente label Sep 8, 2026
@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
clickbus-iris Ready Ready Preview Sep 8, 2026 11:41pm UTC

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: tech-debt Código sub-ótimo conhecido, workaround, ou cleanup pendente

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant