0014 — No celular, a Ajuda esconde metade do índice atrás de um gesto que a tela não anuncia¶
| Status | CORRIGIDO |
| Branch | fix/0014-ajuda-mobile-pilulas-scroll-horizontal |
| Aberto em | 2026-08-24 |
| Severidade | MÉDIA |
| Apps afetados | web · e2e |
| Revisão do diagnóstico | aprovado na rodada 1 |
| Revisão da correção | aprovado na rodada 2 |
Status:
RASCUNHO→DIAGNOSTICADO→EM CORREÇÃO→CORRIGIDONota de classificação, para quem revisa. O comportamento descrito abaixo é o que a spec 0045, §7.2 especificou, e o código o implementa fielmente. O que este registro sustenta é que a decisão de §7.2 derrota a razão que a própria §7.2 dá para existir — e que isso é conferível na tela, não é questão de gosto. O usuário abriu como
/fixe pediu a substituição do componente; a seção 4 explica por que a causa é a decisão de desenho, e não um erro de implementação dela.E esta branch carrega duas coisas, de propósito. Além da correção acima, o usuário pediu em 2026-08-24 que a Ajuda parasse de rolar junto com o menu da gaveta, ficando fixa como a linha de Novidades — navegação, que não decorre da causa raiz da seção 4. Está isolada na seção 6.3, com critérios próprios (CA13 e CA14), para o portão da correção poder julgá-la separada do conserto. O usuário decidiu que ela entra aqui, e não numa spec própria.
A seção 6.2 registra um caminho que foi construído e depois retirado a pedido dele: um ícone de Ajuda na barra do topo do celular. Ele não está no diff; o texto ficou porque explica como a 6.3 foi encontrada.
1. Sintoma¶
Na tela Ajuda (/ajuda), em celular (375px), o índice de assuntos é uma faixa horizontal de pílulas no topo, e abaixo dela a lista de títulos só do assunto marcado. Com os dois assuntos publicados hoje, o resultado na tela é:
- a segunda pílula ("Gestão de imobiliárias") nasce cortada na borda direita — o texto termina no meio do glifo, cortado pelo
overflowdo contêiner. Não é reticência: a pílula não temtextOverflow: "ellipsis", então nada na tela sinaliza que há mais à direita; - a única linha de conteúdo visível é um tutorial (
Abrir uma análise de crédito, 7:09), com ~79% da tela vazia abaixo dela; - o outro assunto e o tutorial dele existem apenas atrás de um arraste lateral, num elemento cuja barra de rolagem está deliberadamente escondida.
Não há erro de console, nem falha de rede: a tela renderiza como o código manda. As medições que sustentam cada afirmação acima estão na seção 2, tiradas do dev-remote.
2. Reprodução¶
- Logar como
imob@e2e.test(senhaS21d2qu1) no dev-remote. - Abrir
https://dev.garantora.com.br/app/ajudacom viewport de 375 × 812. - Observar a faixa de pílulas no topo e a lista abaixo.
Medido no navegador (Playwright, page.evaluate sobre a tela carregada):
viewport 375 × 812
[data-testid="ajuda-submenu-assuntos"]
top 64px, altura 52px, scrollWidth 433, clientWidth 375 → rola para o lado (58px ocultos)
2 pílulas
[data-testid="ajuda-lista"]
top 124px, altura 44px, 1 linha de tutorial
documentElement.scrollWidth == clientWidth (375) → a **página** não rola na horizontal
Ou seja: o conteúdo termina em 168px de uma tela de 812px; os 644px restantes (79%) estão vazios, enquanto 58px de índice estão fora da vista.
- Ambiente: dev-remote (
https://dev.garantora.com.br/app), bundle reconstruído hoje (commit6d3e165, imagemgarantora-devremote-web). - Superfície: mobile, e o defeito é do breakpoint. Abaixo de
sm(600px,useIsMobile) o conteúdo é a lista de títulos e o desperdício de altura é total; entre 600 e 1199px a mesma faixa aparece, mas ali ela cabe (medido em 900px:scrollWidth == clientWidth == 668) e o conteúdo são cartões, então o sintoma característico — índice cortado — não se manifesta. A partir de 1200px não há faixa nenhuma: é a barra lateral, e a tela está correta. - PWA: não agrava o defeito em si; agrava só a verificação da correção — a tela instalada continua servindo o bundle anterior até o service worker atualizar.
- Dados/pré-condições: basta haver mais de um assunto no catálogo (
apps/web/src/tutoriais/*.json— hojeimobiliariasegestao-imobiliarias). Com um assunto só a faixa não rola e o corte não aparece; o desperdício de altura, sim.
3. Esperado × Atual¶
- Esperado: em 375px, quem abre a Ajuda vê o índice inteiro — todos os assuntos do catálogo ao mesmo tempo, nenhum cortado na borda — e alcança os vídeos de qualquer um deles sem precisar descobrir um gesto que a tela não anuncia. A altura, que é o recurso escasso, é gasta mostrando o que existe. (Que forma isso toma — lista vertical que abre os vídeos dentro — é a correção pedida pelo usuário, e está na seção 6.)
- Atual: vê um assunto marcado e o começo do nome do segundo, cortado na borda; os vídeos dos demais assuntos só existem depois de um arraste lateral não anunciado; e 79% da tela fica em branco.
4. Causa raiz¶
Onde¶
apps/web/src/pages/ajuda/NavegadorDeAssuntos.tsx:67-117— a variantesubmenu: umBoxcomdisplay: flex,flexWrap: "nowrap"eoverflowX: "auto"(NavegadorDeAssuntos.tsx:72,:74e:75), com a barra de rolagem explicitamente escondida emNavegadorDeAssuntos.tsx:79-80("&::-webkit-scrollbar": { display: "none" }escrollbarWidth: "none"). Cada pílula levaflexShrink: 0ewhiteSpace: "nowrap"(NavegadorDeAssuntos.tsx:96e:109).apps/web/src/pages/ajuda/index.tsx:119— a escolha da variante:variante={comBarra ? "barra" : "submenu"}, comcomBarradefinido emapps/web/src/pages/ajuda/index.tsx:40comouseMediaQuery(theme.breakpoints.up("lg")). Logo, todo viewport abaixo de 1200px recebe a faixa, inclusive os 375px.apps/web/src/pages/ajuda/index.tsx:198— a faixa é renderizada acima da grade de conteúdo ({!comBarra && navegador}), e o conteúdo deapps/web/src/pages/ajuda/index.tsx:129-169lista os tutoriais decorrenteapenas (corrente?.tutoriais.map,index.tsx:130).
Não é regressão de implementação: é a decisão de desenho que entrou inteira no commit 22b5020 ("feat(spec 0045): a Ajuda vira um navegador por assunto, e não mais uma grade"), especificada em spec/0045-grupos-e-navegacao-na-ajuda/spec.md §7.2 — "Uma faixa horizontal com os assuntos, rolável para o lado quando não couberem… O que o app já tem de mais próximo é a linha rolável de pílulas do MobileFilterBar". O código faz exatamente isso. O defeito está na decisão, não no cumprimento dela.
O mecanismo¶
A causa é uma analogia errada: §7.2 tomou emprestada a mecânica do MobileFilterBar — faixa rolável de pílulas com item marcado — para uma coisa que não é um filtro, é o índice. As duas mecânicas parecem iguais na tela e diferem no que custa esconder uma opção:
- Num filtro, o que a faixa esconde é uma opção; a lista filtrada continua na tela. Quem não arrasta ainda vê o conteúdo — só vê tudo, em vez de um recorte. Esconder opção atrás de um gesto custa pouco, e é por isso que o
MobileFilterBarpode esconder a barra de rolagem sem prejuízo. - Num índice, o que a faixa esconde é o único caminho até o conteúdo. Em
index.tsx:130a lista abaixo mostracorrente?.tutoriais— os tutoriais do assunto marcado, e só deles. Então cada assunto fora da vista leva junto todos os vídeos dele. O que na origem era "uma opção a menos" vira aqui "uma parte do catálogo que não existe".
Daí sai, elo a elo, o que se vê em 375px:
flexWrap: "nowrap"+flexShrink: 0+whiteSpace: "nowrap"fazem as pílulas manterem a largura do título inteiro numa linha só → o conteúdo mede 433px numa caixa de 375px;overflowX: "auto"contém esse excesso dentro do bloco — o que é a razão de a página não rolar na horizontal (medido:documentElement.scrollWidth == 375), e é também o que faz o excesso ficar invisível;- a barra de rolagem escondida (
:79-80) tira da faixa o indício que o navegador daria de graça. O peso desse elo depende da superfície: em 375px emulado, que é onde a medição desta seção foi feita, a barra existiria; num aparelho de verdade ela é overlay e já estaria ausente em repouso de qualquer forma. A causa não depende deste elo — ela é onowrapcontendo o excesso num bloco que rola, com a lista abaixo presa acorrente; - sobra como único indício o corte da pílula na borda, e ele é acidente de largura, não sinal de desenho: basta a fronteira entre duas pílulas cair perto da borda para a faixa parecer completa estando truncada — o que hoje não acontece por sorte dos dois títulos, e passa a acontecer assim que o catálogo crescer;
- ao mesmo tempo, a faixa cobra 52px de altura para exibir um assunto por vez, enquanto o conteúdo de um assunto (uma linha de 44px, hoje) deixa 79% da tela vazia. A altura, que §7.2 declara ser o recurso escasso em 375px, está sendo gasta no eixo errado: o índice ocupa o eixo horizontal — onde há 375px e faltam — e recusa o vertical, onde sobram 644px.
E é isto que fecha o mecanismo: a §7.2 justifica a lista de títulos (em vez de cartões) dizendo que "uma lista de títulos mostra o assunto inteiro de uma vez, que é o que a pessoa veio ver". A faixa de pílulas aplica o raciocínio oposto ao nível de cima — mostra um assunto de cada vez —, de modo que a tela cumpre a letra da §7.2 e derrota a razão que a §7.2 dá para si mesma. Não há largura de tela em que a faixa deixe de fazer isso: com dois assuntos ela corta; com um catálogo maior, esconde mais.
Por que aqui e não em toda parte: o MobileFilterBar continua correto onde está, porque lá a premissa "o conteúdo permanece visível" é verdadeira. O defeito aparece só na Ajuda, que é o único lugar onde a faixa rolável é a navegação, e não um refinamento dela.
Por que agora: a faixa nasceu com a spec 0045 (commit 22b5020, mesclado nesta semana), que foi também quando a Ajuda passou a ter mais de um assunto. Antes havia grade única sem índice, e portanto nada a esconder.
O alcance¶
- A mesma variante
submenuserve toda a faixa< lg(index.tsx:40e:119), não só o celular. Entre 600 e 1199px o índice também mostra um assunto por vez, e também gastará altura para isso; hoje ele cabe na largura (medido em 900px:scrollWidth == clientWidth == 668), então o sintoma do corte ainda não aparece ali — mas aparecerá assim que o catálogo crescer. Quem corrigir precisa decidir explicitamente o que fazer nessa faixa, em vez de corrigir só os 375px e deixar a mesma causa viva 300px acima. - A causa não está no
MobileFilterBar. Procurei os outros usos da mecânica:grep -rn "MobileFilterBar" apps/web/src— ver seção 7. Nos usos de filtro a premissa se sustenta e não há o que corrigir; o que se copiou para a Ajuda foi a aparência, não a situação. - A página do tutorial não é afetada. Em 375px ela não renderiza a faixa (spec 0045 §7.2, e o e2e
ajuda.spec.ts:430prova comtoHaveCount(0)), então o defeito vive só na tela de lista. - O
useTrazerAVista(NavegadorDeAssuntos.tsx:47-53) existe justamente para compensar o defeito: ele chamascrollIntoView({ inline: "center" })para trazer a pílula marcada à vista. É paliativo da mesma causa — resolve "a marca está fora da tela", não "metade do índice está fora da tela". Se a faixa sair no celular, esse remendo sai com ela ali.
5. Revisão do diagnóstico¶
| Rodada | Critical | Important | Minor | Veredicto |
|---|---|---|---|---|
| 1 | 0 | 0 | 3 | APROVADO |
Resultado: aprovado na rodada 1.
A rodada conferiu no código as 14 citações da seção 4 — as duas dos componentes da Ajuda, as do ajuda.spec.ts, o commit 22b5020 e as três da §7.2 da spec 0045 — e todas batem. Confirmou também, sem rodar navegador, dois números da seção 2: os 52px da faixa (theme.spacing é 4 em apps/web/src/design-system/theme/index.ts:58, então pt: 1 + pb: 1 sobre minHeight: 44) e os 668px de 900px (DRAWER_WIDTH = 232 em apps/web/src/components/custom-sider/index.tsx:25).
Os três Minor foram corrigidos na mesma rodada, e não sobraram pendências:
- O corte não é reticência. A pílula não tem
textOverflow: "ellipsis"; o texto é cortado pelooverflowdo contêiner, no meio do glifo. A seção 1 diziaGestão de imob…, o que sugeria um sinal de desenho onde não há nenhum — e o mecanismo se apoia justamente em não haver. - O exemplo do corte provava o contrário do que afirmava. Com dois assuntos de nomes curtos nada ficaria escondido, então não havia truncamento a "parecer completo". O argumento vale para catálogo maior, e o texto passou a dizer isso.
- O elo da barra de rolagem escondida era mais forte que a superfície sustenta. Em aparelho real a barra é overlay e já estaria ausente em repouso; o elo pesa no 375px emulado, que é onde a medição foi feita. O mecanismo passou a declarar que não depende desse elo.
Pendências aceitas: nenhuma.
Aviso registrado para o portão da correção: o alcance nomeia a faixa de 600 a 1199px, e a seção 6 só prevê mudar ajuda.spec.ts:401. O bloco de 900px (ajuda.spec.ts:378) também afirma ajuda-submenu-assuntos visível — e continua verdadeiro, porque a decisão da seção 10 deixa o tablet como está. Se essa decisão mudar, aquele teste muda junto.
6. Correção¶
apps/api¶
Sem impacto — a Ajuda lê catálogo do bundle (import.meta.glob), não a API.
apps/web — 6.1 A correção da causa raiz¶
- Onde:
apps/web/src/pages/ajuda/NavegadorDeAssuntos.tsxeapps/web/src/pages/ajuda/index.tsx. - O quê: no celular, trocar a faixa horizontal por uma lista vertical de assuntos que abre os vídeos dentro dela — a mesma mecânica de abre-e-fecha que a variante
barrajá usa no desktop (NavegadorDeAssuntos.tsx:137-221), em largura cheia e sem a moldurasticky. Tocar num assunto fechado abre os vídeos dele e navega para/ajuda/:assunto(preservando o endereço e o "Ver o assunto" da §7.2); tocar no aberto recolhe, sem navegar — exatamente o paraoEscolherAssunto/aoAlternarExpansaode hoje. - Com isso a lista de títulos separada (
index.tsx:129-169) deixa de existir como bloco próprio no celular: ela passa para dentro do assunto aberto. As linhas continuam com título truncado, ícone de play e duração, como a §7.2 pede. - Faixa de 600 a 1199px: não muda — decisão do usuário registrada na seção 10.
data-testid: manterajuda-assunto-<id>eajuda-linha-<slug>(o e2e já os usa); o wrapperajuda-submenu-assuntosdeixa de existir no celular e o e2e correspondente passa a valer para o navegador vertical.- Responsividade & PWA: a correção é do celular; não pode mexer na barra lateral do desktop, que está correta. Verificar nos dois viewports, contra o dev-remote reconstruído.
apps/web — 6.2 O atalho na barra do topo — construído e retirado¶
Não está no diff, e a história fica aqui porque explica a 6.3.
O usuário pediu "fixar a Ajuda no menu igual às versões, para ficar sempre visível". Lido como "o único lugar onde novidades aparece e Ajuda não é a barra do topo", isso virou um ícone de interrogação na barra do topo do celular, que foi implementado, testado e chegou a rodar no dev-remote por duas rodadas de portão.
Era a leitura errada, e quem apontou foi o usuário vendo a tela: "a Ajuda no dev-remote ainda está no final do menu no mobile". O que ele queria dizer com "fixar igual às versões" era literal — a linha de Novidades não rola, a da Ajuda rolava. O lugar nunca foi o problema; a rolagem era. Isso é a 6.3.
Com a 6.3 no ar, o ícone virou o segundo caminho permanente para o mesmo destino, e o usuário pediu para tirá-lo e devolver a barra do topo ao que era. Foi retirado por inteiro — o IconButton, os testes que só existiam por causa dele (o do ícone, o do pior caso da barra, o de não vazar para o /admin) e os critérios CA9 a CA12. A barra do topo do celular voltou a ser título + ações da tela, byte a byte: git diff main sobre mobile-shell/index.tsx mostra só a mudança da gaveta.
O que sobra de aprendizado, e é o motivo de isto não ter sido apagado: a pergunta que ofereceu as três opções foi feita cedo demais, sobre um pedido de uma frase, e as três descreviam lugares — nenhuma perguntava o que está errado hoje. A resposta certa estava a um grep de distância, na estrutura da gaveta: três regiões, e as duas linhas em regiões diferentes.
apps/web — 6.3 A Ajuda sai da rolagem da gaveta (pedido à parte)¶
Também não sai da causa raiz da seção 4, e foi o pedido original do usuário — só ficou claro depois de a 6.2 estar no ar, quando ele apontou que "a Ajuda no dev-remote ainda está no final do menu no mobile".
- O que existia. A gaveta tem três regiões (RN1 da spec 0011): cabeçalho fixo, miolo que rola, rodapé fixo. O item da Ajuda era renderizado dentro do miolo (
apps/web/src/components/mobile-shell/index.tsx, o bloco{itemRodape && …}que ficava logo depois dogroups.map), enquanto a linha de Novidades éflex: "0 0 auto"fora dele, logo acima do rodapé de conta. Daí a assimetria que o usuário viu: as duas coisas parecem morar no mesmo lugar, mas só uma fica. - O quê. O bloco da Ajuda saiu do miolo e virou faixa própria,
flex: "0 0 auto", entre o miolo e a linha de Novidades — o mesmo tratamento, pelo mesmo motivo. - A spec 0042 não é contrariada aqui. Ela escolheu "o fim da gaveta" como lugar, e o lugar continua sendo esse; o que muda é ele deixar de ser um fim que se afasta quando a navegação cresce.
data-testid: inalterado (mobile-nav-ajuda) — é o mesmo item, noutra região.
apps/e2e¶
- Teste de regressão: em
apps/e2e/tests/e2e/ajuda.spec.ts, blocoAjuda — mobile. O cenário que hoje passa e precisa mudar de sentido éajuda.spec.ts:401, que exigeajuda-submenu-assuntosvisível em 375px. O teste novo prova o que hoje falha: em 375px, todos os assuntos do catálogo estão visíveis e alcançáveis sem rolagem lateral do índice, e os vídeos do assunto aberto aparecem sob ele. - Da faixa fixa da 6.3: aberta a gaveta em 375px, o item da Ajuda não é descendente de
mobile-drawer-nav— a região que rola —, e continua na tela com o miolo rolado até o fim. A asserção é estrutural de propósito: uma que dependesse de o menu de hoje ser longo o bastante para empurrá-la para fora da tela passaria a mentir no dia em que um grupo saísse.
7. Risco / impacto colateral¶
- Não toca dinheiro, permissão nem isolamento. A Ajuda é tela de leitura sobre arquivo do bundle; nenhum papel vê mais nem menos por causa desta correção (RN7 da spec 0042 continua: todo autenticado vê tudo).
- Contradiz a §7.2 da spec 0045 por decisão do usuário, e a divergência fica registrada aqui em vez de reabrir a spec — seção 10.
- O
MobileFilterBarnão muda. Confirmar comgrep -rn "MobileFilterBar" apps/web/srcque a Ajuda não o importa (ela não importa: usaBoxpróprio), de modo que a correção não alcança as telas de filtro. - Risco de quebrar o desktop: a variante
barrae a variante nova compartilham o mesmo componente. A correção precisa deixar abarraintacta — o e2e de desktop (ajuda-barra-assuntos) é a rede. - Da faixa fixa da 6.3: ela mexe na gaveta de toda tela do celular, e o que muda de verdade é o orçamento de altura: a região que rola perde ~48px para uma faixa fixa a mais. Em telas baixas isso significa menos navegação visível de uma vez — é o preço de a Ajuda não se afastar, e é o mesmo que a linha de Novidades já cobra desde a spec 0043. O
mobile-shell.spec.ts(as três regiões da RN1) e olayout-mobile.spec.tssão a rede. O ícone da 6.2, que teria tocado a barra do topo de toda tela, não está mais no diff — o maior alcance desta branch saiu com ele.
8. Critérios de aceite¶
- [x] CA1. Seguindo os passos da seção 2, em 375px o índice da Ajuda é uma lista vertical: os dois assuntos do catálogo aparecem na tela ao mesmo tempo, nenhum cortado na borda.
- [x] CA2. O índice do celular não rola na horizontal: medido no navegador, o elemento do navegador tem
scrollWidth == clientWidth. - [x] CA3. Tocar num assunto fechado abre a lista de vídeos dele dentro da própria linha e leva o endereço para
/ajuda/:assunto; tocar no assunto aberto recolhe sem mudar o endereço. - [x] CA4. Tocar num vídeo abre o tutorial, e o "Ver o assunto" volta para o assunto de onde a pessoa saiu (comportamento da §7.2, preservado).
- [x] CA5. A página em 375px continua sem rolagem horizontal (
documentElement.scrollWidth == window.innerWidth). - [x] CA6. Alvo de toque de 44px mantido no cabeçalho do assunto e nas linhas de vídeo.
- [x] CA7. O desktop (≥1200px) não muda: a barra lateral à direita continua como está, e o e2e de desktop da Ajuda segue verde.
- [x] CA8. O spec e2e
ajuda.spec.tsfoi atualizado e o cenário novo falha sobre o código de hoje.
Da faixa fixa da seção 6.3:
- [x] CA13. Aberta a gaveta em 375px, o item da Ajuda não é descendente de
mobile-drawer-nav— a região que rola. - [x] CA14. Com o miolo da gaveta rolado até o fim, a Ajuda continua dentro da tela.
Do atalho da seção 6.2: retirados. CA9 a CA12 cobriam o ícone da barra do topo, que foi construído e depois removido a pedido do usuário — ver a seção 6.2. Não há critério em aberto por causa disso: o que eles mediam deixou de existir, e a barra do topo voltou a ser o que era.
9. Plano¶
- [x] Escrever o teste que reproduz o bug e vê-lo falhar (
apps/e2e/tests/e2e/ajuda.spec.ts) — antes de qualquer correção - [x] Corrigir a causa raiz no
apps/web(não há camada de API envolvida) — seção 6.1 - [x] Depois, e em commit separado: o atalho da seção 6.2, para o revisor e um eventual
git revertpoderem separar as duas coisas - [x] Red-green verificado: o cenário novo passa → reverter a correção → rodar → falha → restaurar → passa. Como é correção visual, a prova complementar é o script de screenshot em 375px e em desktop, com as medições de
scrollWidth - [x]
make preflight,make testemake lintsem apontamento novo nos arquivos tocados - [ ] Validar no browser de verdade em 375px e desktop, contra o dev-remote reconstruído (
/devremote-rebuild), reabrindo a tela para furar o cache do service worker
10. Decisões em aberto¶
Nenhuma. As duas que travavam a correção foram decididas pelo usuário em 2026-08-24:
- A faixa de 600 a 1199px não acompanha. A troca vale abaixo de 600px (
useIsMobile, a fonte única do "modo mobile" desde a RN1 da spec 0004). Entre 600 e 1199px ficam as pílulas e os cartões, como hoje: ali a faixa cabe (medido em 900px:scrollWidth == clientWidth == 668), o corte não acontece, e trocar o índice sem trocar os cartões duplicaria os títulos na mesma tela — mais mudança do que o pedido. A causa continua viva nessa faixa, e voltará a morder quando o catálogo crescer a ponto de a faixa não caber em 900px; está registrado aqui de propósito, para não parecer resolvido. - A §7.2 da spec 0045 fica como está, e a divergência é registrada neste fix. A spec é o registro do que foi decidido então; este registro é o de por que a decisão mudou.
11. Revisão da correção¶
| Rodada | Critical | Important | Minor | Veredicto |
|---|---|---|---|---|
| 1 | 0 | 1 | 5 | REPROVADO |
| 2 | 0 | 0 | 4 | APROVADO |
Resultado: aprovado na rodada 2.
O que a rodada 1 apontou, e o que se fez¶
O Important — o colateral de maior alcance da branch não tinha medição nenhuma. O ícone da 6.2 entra na barra do topo de toda tela do tenant abaixo de 600px e come 48px fixos do espaço em que o título disputa flex: 1; a própria seção 7 nomeia mobile-shell.spec.ts e layout-mobile.spec.ts como a rede, e a seção 11 relatava só o ajuda.spec.ts. O revisor achou ainda uma terceira rede que ninguém tinha citado — apps/e2e/tests/e2e/page-header.spec.ts:170, que exige título com mais de 40px em 375px. Foram rodadas as três, contra o dev-remote reconstruído: ver o resultado abaixo.
As correções de rodada:
- CA12 reescrito com piso mensurável. A redação anterior — "sem truncar o título mais do que já truncava" — não pode ser verdade de nenhum desenho que acrescente controle permanente a uma barra de largura fixa, e um CA sem piso se fecha por afirmação. Passou a ser o piso do fix 0005 (>40px), agora medido dentro do próprio teste do ícone.
- Uma asserção que a correção esvaziou.
ajuda.spec.tsexigiaajuda-submenu-assuntosausente na página do tutorial em 375px; como o fix tirou esse elemento de todo o viewport abaixo de 600px, a asserção passou a ser verdadeira de graça — passaria mesmo se a página do tutorial renderizasse o navegador novo e comesse a altura do vídeo. Ganhouajuda-lista-assuntosao lado. - O
useTrazerAVistasaiu da variante do celular, como a seção 4 previa. Ele compensava um índice que não cabia na tela; aqui cabe, escrollIntoViewdentro do<main>rolável moveria a página logo depois do toque sem ter o que corrigir. - CA6 deixou de ser
minHeightlido no código e passou a ser medido: 44px no cabeçalho do assunto e na linha do vídeo.
Dois achados recusados, com o motivo — não por discordância de estilo, mas porque a leitura que os sustenta não bate com o código:
- "o ícone rouba o canto que a ação principal ocupava de propósito". O comentário citado do
PageHeaderdiz que a ação principal é "a última coisa antes dos controles do usuário" — ou seja, há controle de usuário à direita dela por desenho. E é exatamente a ordem da barra do desktop (apps/web/src/components/app-layout/index.tsx:88-93): título, ações da tela, depois os controles do aplicativo (novidades, tema, avatar). Pôr o ícone antes doactionsRefé que divergiria das duas coisas. O raciocínio ficou escrito no código, que era o que faltava. - "
data-testiddo namespaceajuda-*dentro da casca". É o precedente doIconeNovidades, que usaversao-iconena barra do desktop pelo mesmo motivo: o testid nomeia o destino, não a casca que o hospeda. E a derivação a partir dopathé a mesma convenção do item da gaveta logo abaixo (mobile-nav-${path}).
Aceito sem corrigir, e é o que o revisor apontou de mais fino: no teste do índice, a asserção scrollWidth === clientWidth não é a que mata o desenho antigo — sobre um flex-direction: column; width: 100% ela é quase tautológica. Quem mata é a existência do ajuda-lista-assuntos e a borda do segundo assunto dentro da tela. A asserção fica porque guarda outra coisa daqui para a frente (um filho estourando a caixa), mas o comentário do teste que a chamava de "a asserção que morre se a faixa voltar" estava exagerando, e isto aqui é o registro disso.
O teste sobreviveria à reversão? Sim, e a prova não é um git revert mental: os quatro testes foram rodados contra o build sem a correção e vistos vermelhos, e depois contra o build com ela. Como a imagem do web embute o código, cada execução mediu um bundle diferente de verdade.
Vermelho — dev-remote no bundle index-C0Tr_OVA.js (a main, commit 6d3e165, sem uma linha desta branch), npx playwright test tests/e2e/ajuda.spec.ts --workers=1:
✘ o índice mostra todos os assuntos de uma vez, sem rolagem lateral
Error: element(s) not found — getByTestId('ajuda-lista-assuntos')
✘ tocar num assunto abre os vídeos dele dentro da linha, e leva o endereço
Error: element(s) not found — ajuda-assunto-bloco-imobiliarias >> ajuda-linha-…
✘ tocar no assunto aberto recolhe, e recolher não navega
✘ o ícone da Ajuda fica na barra do topo e não passa pela gaveta
Error: element(s) not found — getByTestId('ajuda-icone')
E um deles nasceu falso. Na primeira escrita, "tocar num assunto abre os vídeos dele dentro da linha" passou sobre o código velho: com a faixa de pílulas, tocar num assunto também fazia aparecer a linha do vídeo — num bloco separado, abaixo. Procurar a linha em qualquer lugar da página passava nos dois desenhos. A asserção foi reescrita para exigir que o vídeo seja descendente de ajuda-assunto-bloco-<id>, e só então ficou vermelha. Está registrado porque é exatamente o teste que R1 existe para pegar, e ele quase entrou verde.
Verde — depois de /devremote-rebuild web (bundle index-10iydR45.js), a suíte inteira da Ajuda: 38 de 38, incluindo os 4 acima e os que protegem o desktop (ajuda-barra-assuntos) e a largura intermediária (ajuda-submenu-assuntos em 900px).
Verde de novo, depois das correções da rodada 1 — segundo rebuild, e agora com as três suítes que medem o colateral do ícone na barra do topo:
Entre elas, as que o revisor pediu por nome: layout-mobile.spec.ts:66 (a barra do topo mede 64px e o ícone vem em contêiner de 40px), mobile-shell.spec.ts:115 (só a aba "Mais" abre a gaveta — a RN8 da spec 0011, que o atalho não atropela) e page-header.spec.ts:170 (todo detalhe mostra o título e respeita o teto de ações, com o piso de 40px em 375px).
E a execução final, depois das correções da rodada 2 — terceiro rebuild, com o agencies.spec.ts junto porque o teste novo do CA12 caminha pela lista de imobiliárias:
O skipped é o agencies.spec.ts:93 ("deve cadastrar todas as imobiliárias da seed"), um test.skip que já estava no repositório e nada tem a ver com esta branch.
E a execução final de verdade, depois de o ícone da barra do topo ser retirado a pedido do usuário e de a Ajuda sair da rolagem da gaveta — quinto rebuild:
Numa execução intermediária, um vermelho que não é desta branch. O ajuda.spec.ts:160 ("versão desconhecida … é ignorada em silêncio") falhou uma vez. A evidência barata: o teste não aparece em git diff main -- tests/e2e/ajuda.spec.ts; o diff não toca a página do tutorial nem a escolha de gravação por ?v=; ele passou nas três execuções isoladas seguintes e nas execuções seguintes da suíte. É o estouro de tempo intermitente que o apps/e2e/CLAUDE.md já descreve para o dev-remote — não regressão daqui. Não é a mesma coisa que "já estava quebrado", e não se afirma isso.
A suíte e2e completa não foi executada — só estas quatro.
A guarda do /admin não é prova, e é de propósito. O teste "o ícone da Ajuda não aparece no /admin" passa nos dois lados — antes e depois. Ele não é evidência da correção: é o que impede alguém de mover o botão para dentro da casca e levar a Ajuda do tenant para o painel do SaaS. Os testes que morrem sem a correção são os quatro acima.
As demais suítes: pytest da API 698 verdes, 0 vermelhos (nenhum .py foi tocado — é confirmação de que nada quebrou, não prova da correção). tsc do web limpo. make preflight limpo. ruff não foi executado porque o diff não tem Python.
A medição da tela, que é o que um fix visual deve mostrar (Playwright contra o dev-remote reconstruído, os mesmos números da seção 2):
| antes | depois | |
|---|---|---|
| índice em 375px | faixa: scrollWidth 433 × clientWidth 375 | lista: scrollWidth 359 × clientWidth 359 |
| 2º assunto | cortado na borda | borda direita em 367px de 375 — inteiro |
| altura usada pelo conteúdo | 168px de 812 | 206px de 812, com os dois assuntos na tela |
| ícone de Ajuda na barra do topo | ausente | presente |
| 900px | pílulas + cartões | igual (scrollWidth == clientWidth == 668) |
| desktop 1440px | barra à direita | igual, e sem ícone na barra do topo |
A rodada 2, e o que se fez com os quatro Minor¶
Três foram corrigidos; o quarto é instrução para a hora de commitar.
- O navegador vertical podia vazar para a faixa de 600–1199px sem ninguém notar. O bloco de 900px afirmava
ajuda-barra-assuntosausente, mas não oajuda-lista-assuntos— a mesma lacuna que a rodada 1 fechou na página do tutorial, e justo na faixa em que a seção 10 registra que a causa continua viva de propósito. Ganhou a asserção gêmea. - O CA12 estava medido no caso fácil. A medição rodava em
/credit-analyses, uma lista, que tem no máximo uma ação no topo; quem espreme a barra é o detalhe, com três. Ganhou teste próprio em 375px. E ele nasceu instável: pegava a primeira imobiliária da lista, e medindo o dev-remote descobriu-se que das quatro primeiras uma tem três ações e três não têm nenhuma — então.first()era cara-ou-coroa, e o teste passou isolado e falhou na suíte quando oagencies.spec.tsmudou quem vem primeiro. Foi reescrito para procurar uma linha com 2+ ações entre as oito primeiras e reclamar se não achar nenhuma, em vez de aprovar por engano. Medido com três ações: título de 121px contra o piso de 40. - O ícone era o único dos três caminhos para a Ajuda sem estado ativo. O rodapé da sider e a linha da gaveta recebem
isNavItemActive; o atalho, não — em/ajudaele ficava apagado, convidando a navegar para onde a pessoa já está. Passou a acender (primary.main, ícone emfillpela RN3 da spec 0011,aria-current="page"), com asserção no teste. - Commit separado para a 6.2 — o corte continua limpo por arquivo, e está anotado na seção 9. Fica para a hora de commitar, que é pedido do usuário.
E um achado da rodada 1 que se aceitou sem corrigir, porque o revisor tinha razão sobre o texto e não sobre o teste: no teste do índice, scrollWidth === clientWidth não é a asserção que mata o desenho antigo — sobre um flex-direction: column; width: 100% ela é quase tautológica. Quem mata é a existência do ajuda-lista-assuntos e a borda do segundo assunto dentro da tela. A asserção fica porque guarda outra coisa daqui para a frente (um filho estourando a caixa); o que saiu foi a pretensão do comentário.
Defeitos aceitos: nenhum em aberto.
12. Registro¶
O que era. Em 375px, o índice da Ajuda era uma faixa horizontal de pílulas (NavegadorDeAssuntos.tsx, variante submenu) e, abaixo dela, um bloco separado com os títulos do assunto marcado (index.tsx). A faixa media 433px de conteúdo numa caixa de 375px.
O que virou. Abaixo de 600px a faixa saiu e entrou a variante lista: a mesma sanfona do desktop, em largura cheia e sem moldura, com os vídeos dentro do assunto aberto. O bloco de conteúdo separado deixou de existir no celular — índice e conteúdo passaram a ser a mesma coisa, que é o que faz o catálogo inteiro caber na tela. Entre 600 e 1199px e no desktop, nada mudou.
E entrou junto, a pedido do usuário: a Ajuda saiu da região que rola na gaveta do celular e virou faixa fixa, entre o miolo e a linha de Novidades — o mesmo tratamento que a de versões já tinha. Está isolada na seção 6.3 com CAs próprios, e o plano prevê commit separado.
E saiu, também a pedido dele: o ícone de Ajuda na barra do topo do celular, construído antes de a 6.3 ser encontrada. A barra do topo voltou ao que era; a seção 6.2 guarda a história.
O que divergiu do plano¶
- O pedido "fixar a Ajuda no menu igual às versões" foi entendido errado, e custou três rodadas. Virou um ícone na barra do topo; o que ele dizia, literalmente, era que a linha de Novidades não rola e a da Ajuda rolava. A diferença estava na estrutura da gaveta — três regiões, e as duas linhas em regiões diferentes —, e teria aparecido lendo o
mobile-shellantes de oferecer opções. O ícone foi construído, revisado em duas rodadas de portão e depois retirado inteiro. A lição não é "perguntar mais": é que as três opções oferecidas descreviam lugares, e nenhuma perguntava o que está errado hoje. - O desktop nunca ganhou nada, e isso também foi descoberto no caminho. Lá a Ajuda já estava em toda tela — ancorada no rodapé da sider, fora da rolagem, exatamente o que a 6.3 passou a fazer no celular. A assimetria era só do celular.
- Cinco rebuilds do dev-remote, não um. Cada rodada que mexeu em código pediu outro, porque a imagem do
webembute o bundle e testar sem reconstruir mediria a versão anterior. Dois deles foram do ícone que acabou saindo. - Um teste nasceu falso e outro nasceu instável, e os dois estão contados na seção 11. O falso passava sobre o código velho (procurava a linha do vídeo em qualquer lugar da página, e no desenho antigo ela também aparecia — num bloco separado). O instável dependia de qual imobiliária vinha primeiro na lista. Os dois foram reescritos, não afrouxados.
O que fica em aberto, e é de propósito¶
A causa raiz continua viva entre 600 e 1199px: ali a faixa também mostra um assunto por vez, e voltará a cortar quando o catálogo crescer a ponto de não caber em 900px. É decisão do usuário registrada na seção 10, não esquecimento — e o teste daquele viewport foi mantido de propósito, agora com a asserção que impede a sanfona de vazar para lá.