Changelog - 21/06/2026
Semana de 15/06 a 21/06. Daqui pra frente o changelog é semanal (arquivos YYYY-MM-DD-weekly.md, datados no último dia coberto). A fonte de verdade do front-web-base é a branch main-7k — a main está defasada e não reflete o que foi pra produção.
Semana 15–21/06 — cache overhaul: CACHE_GENERATION como token único de rotação
front-ops/config/cache/generation.ymlvira a fonte operacional de verdade (opsf00c642): o arquivo carregacurrent: apcsrasj-v3, é lido no deploy e injetado como--var CACHE_GENERATIONnowrangler deploy. Bumpar pelo workflow novobump-cache-generationflipa de uma vez a namespace do Cache API doplatform-cache, ocacheKeyPrefixdoapi-cliente oGLOBAL_VERSIONdofront-service-api; sem o arquivo, o deploy cai no default in-source (fail-open). É separado doBUILD_ID, que já rotaciona a cada deploy — oCACHE_GENERATIONé o "nuke from orbit" que o padrão legado de pasta-nova-por-deploy fornecia.cache-status.ymlcomplementa como leitura read-only.- Base conectado à máquina nova (
b445a6b5a): binding declarado noworker-configuration.d.ts;app/services/platform-cache.server.tsmantém umstoresByGenerationchaveado pelo token, então o cache de isolate rotaciona atomicamente;app/services/api.server.tsderivacacheKeyPrefixcomoapi-cache-<gen>e ligadelegateCaching: truenas rotas já cacheadas na camadaplatform-cache, eliminando o drift de TTL duplo que causou o postmortem de/payment-providersem 05/2026.app/routes/api/cache/purge.tspassa a delegar aocreatePurgeHandlerdo core (mesmo contrato detag/glob/scope/dry_run, comextractApiErrorno lugar de[object Object]) e nasceapp/routes/api/cache/inspect.ts, endpoint GET que lista recursos, tags e namespace corrente e, com?include=state, sonda o Cache API. - TTLs apertados e falhas de fallback visíveis (
239651ff4):KV_SSR_TTLcai de 12h pra 1h (o valor antigo era resquício da premissa "rebuild a cada 12h"), entraMAX_API_CACHE_TTL = 3600com clamp emgetApiCacheRule, e erros de fallback de asset em KV e R2 passam a ser logados — antes eram engolidos em silêncio, deixando problema de permissão ou bucket invisível no Logpush.public/_headersreduz/icons/*de 1 ano pra 30 dias. - Defaults e purge seletivo no
front-ops(b36e445):brandConfigsai de 3600s ehomeRowsde 7200s, ambos pra 60s + SWR 300s, então mudança de backoffice reflete em menos de 60s; toda resource ganhatagspra o purge mirar fatias em vez de derrubar tudo;staleIfErrorSecondscapado em 6h.manual-cache-purge.ymlsobe pra v3 comtags(CSV),glob,scopeedry_run.8645ac2criaconfig/cache/service-api-defaults.ymlcom 19 regras consumidas no deploy do service-api — base e service-api passam a compartilhar a mesma taxonomia de tags. skip_post_deploy_purgepor environment (ops2d83a4c, aplicado em0d4437ee64f130f): workers atrás de Cloudflare Access devolvem 404 no purge pós-deploy porque ocurlsegue o redirect de login sem service token. Até os service tokens entrarem no workflow, o environment pode sair do purge por segmento — a rotação doCACHE_GENERATIONjá torna as entradas anteriores inalcançáveis — e um step de notice registra o skip no run summary.front-service-apicom política externalizada (f80791d):DEFAULT_GLOBAL_VERSION = apcsrasj-v3,getGlobalVersion(env)lendoCACHE_GENERATION→BUILD_KEY→ default, política vinda deenv.SERVICE_API_CACHE_POLICY_JSON(era hardcoded) e/v2/cache/purgecom o mesmo contrato do base.scripts/build-cache-policy.mjsresolve o YAML por--file,FRONT_OPS_PATHou irmão../front-ops. 27 testes novos, com8d9fe4fdocumentando o fluxo no README.
PSI honesto — todo branch específico de bot foi removido
- Bots passam a receber exatamente a mesma página que usuário real (
08fd669a0). Isto reverte o padrão de otimização por bot documentado em abril: oroot.tsxtinha um elemento decorativo de LCP falso (gateado porisBot || true, ou seja, renderizava pra todo mundo), oentry.server.tsxremovia o script de boot da hidratação e reescrevia o viewport pra crawler, euseIsBot()gateavaSlideshow,Marquee,VerticalMarquee,StepCarousel,CookieConsentBanner, os dois widgets de banner da home euseCustomThumb. Tudo isso saiu: bots hidratam como usuários, então o Lighthouse mede TBT/INP reais em vez de uma página sem JS, e a auditoria de acessibilidade passa a refletir o viewport de verdade. Mantido de propósito: o skip deisBotRequestna geração de remarketing-ID no loader do root — higiene de dado, invisível, não afeta o que o PSI mede. - Worker de edge sem discriminador de bot (
5dad940a7): oisBotsai da chave de cache doworkers/middleware.ts(o HTML é idêntico pra qualquer UA agora) e o guard!isBotno caminho de SPA-shell autenticado sai como defesa morta. Comentários obsoletos que ainda afirmavam mascaramento de bot foram corrigidos em oito arquivos. - Hack anti-FOUC removido (
73c032fa4): o par<body style="visibility:hidden">+visibility: visible !importantescondia a página até o CSS chegar, mas o stylesheet principal já sobe render-blocking — o browser sozinho retém o primeiro paint. O hack era redundante em produção e arriscava tela branca se o CSS demorasse ou falhasse. - Scripts de terceiros voltam a carregar eager (
74259e8a2): othird-party-schedulertinha um encadeamento de gates (LCP + primeira interação + 7s + idle) e descartava tudo em auditoria sintética; evento disparado antes do GTM inicializar era silenciosamente perdido, sem fila de replay, então quem convertia sem interagir nunca era rastreado.scheduleThirdParty(fn)roda imediatamente e só o kill-switchthirdPartyScriptsDisabledsobrevive. OuseAnalyticsperde o gate!isBote o atraso de 7s dopageviewReady, e sai o Meta Pixel duplicado e hardcoded doAnalyticsInitializer, que dupla-inicializava o pixel e vazava entre todas as brands. - Regra que fica valendo: o que for deferido por performance tem que ser deferido pra todo visitante, nunca só pra bot, pra o score continuar honesto.
Analytics — um page_view por navegação
page_viewdisparava ~59 vezes na home (c72d9eb4b). OuseAnalytics()é chamado por cerca de 27 componentes só pra ler os métodostrack*, mas os efeitos de init de tracker e depage_viewviviam dentro do hook — então cada consumer disparava o seu, um por card de jogo montado. O antigo atraso de 7s mascarava o problema e ainda piorava: aquele gate era um ref virado porsetTimeout, que nunca re-executava o efeito, então opage_viewinicial na prática nunca era despachado (a queixa de "eventos desaparecendo"). Os efeitos foram extraídos pra umuseAnalyticsBootstrap()de mount único, chamado uma vez peloAnalyticsInitializer;useAnalytics()fica sem side effect.- Container GTM secundário no 7k, atrás de autorização —
5eb1fff32adiciona,222a93c1fgateia por autorização explícita e12ab06e7dautoriza pra stage. Canal Floodlight DV360 opt-in emcl-bet7k-comeng-7k-bet(0f14c99f4); Pendo nabetpontobet-bet-br(59c60a10f);af2e11f6fempurraselect_contentproanaLayerno clique do card de torneio.
Game assistant e drawer de pré-jogo
game-assistant: menu flutuante estilo AssistiveTouch dentro do jogo (252cd26b0) — botão mobile-only visível só em jogo fullscreen, arrastável com edge-snap, posição persistida por usuário e clamp inferior region-aware pra nunca sobrepor outros widgets flutuantes. Abre um card com saldo real ao vivo, stepper de depósito rápido reusando oCtaButtonda casa, toggle de favorito e opções config-driven que abrem bottom sheets de carteira (com paridade de bônus/cashback), notificações, recompensas, missões, torneios e info do jogo.7519bb64asobe os labels como override de i18n no base (temporário, aguardando core) e79cdfbd33gateia a feature só na7k-bet-br.- Missões e torneios filtrados por relevância do jogo (
c4ea27e12): o utilfilterByGameRelevance(gameKey, providerName, items)aplica cascata estrita jogo-específico → provedor → todos, com tiers mutuamente exclusivos. Aplicado só nos sheets do assistant —MissionsSection,TournamentsSection, rows da home e páginas/vipficam intocados. - Saga do cap de altura dos sheets, com causa-raiz encontrada —
cf1c3fc8e,c80410889,81af6a9e2e finalmente3cd78fe66: oSheetContainerdoreact-modal-sheet5.6.0 sobrescrevecontainerStyle.heightpor detent depois do style do caller, e no detentcontentsobrescreve também omaxHeight— então nem CSSmax-heightnem altura fixa comsnapPointscapavam. Só o detentdefaultpreserva omaxHeight, e é o que o modo capado passa a usar.e3ec07b27fecha com back-to-preview e refresh de carteira. - Drawer de pré-jogo config-driven (
ab7846ada): bottom sheet mobile intersticial que abre no toque no card, com hero, métrica de RTP/payout, CTA "Jogar agora" e rows "Confira também". O clique passa poruseGameActivation, que mantém o<Link>como fonte de verdade da navegação e só intercepta em mobile + flag. Gateado porfeaturesConfig.preGameDrawer, ligado só nadonald-bet-br. Iterações emdc965d465,5c6978219,386b3b352,a3f17dbc4;8a21db3bdliga o widget "Pagou hoje";c08362ccbfaz o CTA já pedir o launch em tela cheia, eliminando o segundo toque.
Recuperação de chunk e tela de versão obsoleta
- "Aba velha, deploy novo" deixa de virar erro cru (
87cd10e94). Quando os nomes hasheados de chunk desaparecem do CDN após redeploy, qualquer import lazy num client defasado lançaTypeError('Failed to fetch'). Entramapp/utils/version.client.ts, fonte única de comparação de build-id (envolvendo o fetch de/api/version, rota do próprio Worker, confiável até com o BFF fora) que tratanullcomo "não sei dizer" e não classifica como obsoleto, eapp/utils/chunk-reload.client.ts, comisChunkLoadError(err)e auto-reload guardado por marcador emsessionStoragenuma janela de 10s pra impedir loop, falhando fechado quandosessionStoragenão existe. Oentry.client.tsxliga listeners deerroreunhandledrejection, e oErrorPageganha o estadochunkKind(pending,stale-version,generic) — enquanto o/api/versionestá em voo aparece spinner neutro em vez de piscar um 500 que vai virar a tela amigável. Suportado pelo corefd10a1d.
Esportes — First v4 e geometria do iframe
- Token de launch da First deduplicado e navegação interna v4 corrigida (
f9aa638f0): o endpoint de launch passa a ser escolhido pelo cookieis_authenticatede deduplicado por identidade de auth, então F5 de usuário logado emite um token em vez de dois; a URL de launch é cacheada por sessão (auth-keyed, TTL curto).eventlistTabe o chip da home passam a reload do iframe, porque o iframe v4 dropa deep-link de tab viapostMessage; a URL do browser é sincronizada peloLOCATION_CHANGEdo v4, agora path-only. - Altura do iframe endurecida, com causa-raiz estrutural (
8ee6dc32e):--mobile-nav-hera estática emtailwind.css(56px) com override imperativo emuseEffectpra 64px só na família 7k — mutando a geometria depois do paint e criando race na montagem do sportsbook; as variantesillustrated,illustrated-tabsegrid-tilesrenderizam alturas diferentes e nunca atualizavam a var. Agora oBottomNavShellpublica--mobile-nav-ha partir dooffsetHeightreal do<nav>viaResizeObserver, no padrão de--header-h, com o valor estático virando fallback de SSR. Em paralelo,useSportsAvailableHeightganha trailing-rAF, recompute pósresize/orientationchangee limpeza de--sports-hno unmount. Complementos:41fd5fb44,b3fa7bc24e031159fc0. @cactus-agents/sports-rogueavança de^0.9.0pra^0.10.1na semana (f03de4e16,ec4ba2555,d737034eb).
Auth, cadastro e validação
- Cadastro BR não deixa mais submeter com CPF não validado (
9da4ea87a): no fluxo de CPF não existe campo de data de nascimento —birthDatevem do lookup do documento. Quando o CPF já está cadastrado, o lookup falha comDOCUMENT_TAKENe nunca preenchebirthDate, mas o form deixava submeter; ovalidateRegisterInputentão reportavaREQUIRED_BIRTH_DATE→ "Informe sua data de nascimento", mensagem sem sentido porque o campo não existe. Agora o submit é bloqueado e o erro real do documento aparece. Só dispara quandorequestDocument && country === "BRA". - Saque não repete passos de validação já cumpridos (
52a23e170): o perfil é atualizado antes de avaliar o gate, então módulos já validados dofirstWithdrawdeixam de aparecer como pendentes por snapshot defasado, eEmailStep/PhoneStepauto-avançam quando o campo já está validado em vez de travar no retorno "já validado" do BFF. O liveness por saque forçado porwithdraw.frequentfica intacto.50a536ccdsobe oValidationStepsModalacima dos modais de pagamento prioritários.
Core / SDK
@cactus-agents/platform-cache(5334086): exportaDEFAULT_CACHE_GENERATION(apcsrasj-v3) como fonte única;CacheApiStoreaceitacacheGenerationeloggeropcionais, tornando visíveis erros transitórios de KV/Cache API; expõefindResourcesByTag,findResourcesByTagGlobelistAllTags; e ganha ocreatePurgeHandler({ engine, secret, originDomain })compartilhado entre base e service-api. Mais de 80 testes novos.@cactus-agents/api-client(0a897c2):ServerCacheConfig.delegateCachingpermite pular por completo o cache próprio do api-client pra quem já envolve as chamadas complatform-cache;DEFAULT_CACHE_KEY_PREFIXpassa aapi-cache-apcsrasj-v3.@cactus-agents/payments+i18n(665a089): contrato de Pagamentos v3 aditivo — roteamento porhub_payment_methods,client_request_ideprovider_codeno payload,PaymentStatusV3,normalizeDepositStatusetransformWithdrawResponse. Contrato legado inalterado quando os campos novos não vêm. No i18n, chaves de sucesso de saque nos 7 locales.@cactus-agents/i18n(fd10a1d):stale_version_title,stale_version_message,stale_version_ctaeshow_detailsemlayout.error, nos 7 locales.
Brand Overrides
- donald-bet-br concentra o volume da semana. Destaques: depósito e saque em etapas (
d563b9478), modais de auth com floating-label (67d067426), drawer mobile do sidebar flutuante com abas contextuais (9686ecdcd), menu do usuário em painel flutuante (95bc60355), home BFF-driven em modo misto (c96c25567), card de torneio showcase com filtros estilo cassino (55063e9e9) e detalhe redesenhado (64defee69,b81b021cb), home legada curada em 8 rows (827e76c79), grade in-place com banners 2-up (0920a10b2), menu de navegação rápida fixo no topo (603cbb055), filtro de provedor in-place (cf774c0e5) e o botão "Já paguei" do Pix verificando status antes de confirmar (f2ecc1c6d) e depois oculto (e8c17770d). - Redesign de torneio isolado atrás de config (
df01e51ee): o redesign e osGamificationFiltersrestilizados tinham sido aplicados em componentes compartilhados, vazando o visual da donald pra todas as brands. EntraGamificationUiConfigcomtournamentDetailLayoutefiltersStyle(default clássico no base, donald flipando pra showcase/chip), maisheaderStyle.authCtaUsesHeaderButtons(defaultfalse). - 7k-bet-br: "Copa dos Palpites" ganha acesso no menu lateral (
2cba186bc), deep-link#copa-dos-palpites(5242e905d), pill alinhada em 40px (e33159645) e item no bottom nav (08962957c), e é renomeada pra "Bolão 7K" (206f77f7f). Bottom nav alinhada ao Figma (c2da25746), menus Cassino e Esportes iniciando recolhidos (c41c3b454), borda em gradiente na Copa do Mundo (248d7d45a), carrossel "Jogos do Álbum de Figurinha" no cassino (74ac10af3) e row da home renomeada pra "Top 10 - Álbum" (cf38b1f3f).98703321eremove perfil e roletas do Xand Avião;996e6697eadiciona a campanha "Roleta Premium Neto V2". - betpontobet-bet-br: Política de Privacidade Open Gaming v2.0 publicada (
ecc42a8e0). Família 7k:849f9d7a8adiciona o exportfooterFollowque faltava nos overrides — sem ele a brand recebiaundefined, o sintoma clássico de campo novo não propagado.
Pagamentos
- Contrato Pagamentos v3 consumido atrás da flag
paymentsV3(8642d7475): flag nova com defaultfalseecasateste-comemtrueno dia zero, propagada pra todos os overrides. No depósito,client_request_idpor tentativa (reusado no retry, renovado em "novo QR"),provider_codeepayment_methodencaminhados a partir dohub_payment_methodsdo provedor selecionado, resultado Pix usandoexpires_in,copy_pasteecharge_id, e status normalizado pornormalizeDepositStatus. No saque,client_request_id+provider_codee tela de sucesso distinguindo aprovado automático de pendente de aprovação. As rotas internas passam a expor oreasondo BFF no envelope. Brand com a flag desligada mantém o fluxo legado byte a byte. - Polling de status por
transaction_id, nãocharge_id(b6b561301): o endpoint/wallet/charge/{id}espera otransaction_id(ex.casatestecom_19502), não ocharge_idnumérico — o polling v3 mandava ocharge_ide todo deposit-status falhava. Volta a usar sempreresult.transactionId, no legado e no v3.b94c28b8ahabilita a flag nacl-bet7k-compra teste em stage.
Infra / CI/CD
fecadmganha um uplift grande (5ca4a85): dark mode com tokens de tema substituindozinc-*/whitehardcoded, primitivos novos emcomponents/ui/(Table, Tabs, DropdownMenu, Avatar, Breadcrumb, Pagination, ToggleGroup, UserMenu) todos Radix-based e tematizados por token,CommandPaletteglobal, botão de cache, husky e CI. Os ajustes de CI que fecham esse uplift caem na semana seguinte.front-service-api-dev-proxyganha deploy próprio —de4bd2eadiciona o workflow (wrangler deploy no push pramain),f2ff6eadocumentaPROXY_FROM, o padrão de lookup de secret e o fluxo de deploy no README, ed4d57a5resolve 3 erros de typecheck que travavam build estrito.- CODEOWNERS repontado pro grupo de ruleset novo em todos os repos: base
631d22020, core19aea0a, ops4f631f3, service-api360c1f8, e2edef626b, dev-proxy2af7019. Opsdd53d6batualiza também as referências de team de deploy protection em vários environments. - Environment
7wins-cccriado (ops8020ff6) e adicionado ao dropdown de dispatch do base (f00dc6b42, com9856f63ddsincronizando comops/main); opsdaa9800e base63dafb4e2adicionam o environment de esportes dabetpontobet.c65a7564dremove as env vars mortasFAV_GAMES_API_URLeFAV_GAMES_API_KEY.
Documentação
- Runbooks de cache no
front-cactus-docs—129618epublica arquitetura, estratégia e operação de cache, e5dd9530atualiza os guias de SDK e template proplatform-cache0.14 e pro overhaul. É o último conteúdo substantivo que o repo de docs recebeu antes da lacuna que este lote de entradas semanais fecha. 97aa0eeadiciona o guia de deploy/environments e corrige docs de CI/CD defasados;67dcdd5atualiza orequired_teamde deploy protection;a03ce81adicionatemplate/favoritesao sidebar interno.