Changelog
GitHubTodas as mudanças relevantes, versão por versão. O mesmo arquivo é publicado no repositório e traduzido nos 19 idiomas.
[1.69.2] — 2026-06-12
fix(test): corrige um vazamento de isolamento de testes que deixava npm test sobrescrever seus config/profile.yml e data/scan-history.tsv reais. tests/critical-fixes.test.mjs importava prompts.mjs (→ paths.mjs) no topo do arquivo, então PROJECT_ROOT resolvia para o diretório pai real antes de before() definir CAREER_OPS_ROOT como um diretório temporário — e PUT /api/profile vazava a fixture “Acceptance Test” para o seu perfil real a cada execução. Correção: carregar prompts.mjs via import() dinâmico dentro de before(). Novo tests/test-root-isolation.test.mjs (2 casos) protege toda a suíte contra esse padrão. Sem mudança de código de produção. Suíte 1084 → 1086.
[1.69.1] — 2026-06-12
fix(scan): #/scan não trunca mais silenciosamente varreduras regionais grandes. O conjunto exibido por região estava limitado a 500 (uma varredura RU real de 1352 vagas correspondentes mostrava apenas 500; 852 ocultas — o sintoma “2000 escaneadas, ~600 exibidas”). Ambos os scanners agora usam uma constante compartilhada e substituível por ambiente MAX_STORED_RESULTS (padrão 2000, substituível via SCAN_MAX_RESULTS). Apenas exibição: as adições a pipeline.md / scan-history.tsv já usavam o conjunto sem corte. fix(health/ui): os cartões de verificação do #/health não transbordam mais. Um nome/valor longo colidia com o botão Fix → e o selo de status; a linha agora encolhe e quebra via .health-check-row. Novos testes scan-result-cap + health-card-overflow. Suíte 1079 → 1084.
[1.69.0] — 2026-06-12
feat(scan): autodescoberta de adaptadores do scanner (P-14) — basta colocar um .mjs em server/lib/sources/ para registrar uma nova fonte. Antes da v1.69, a lista de fontes em server/lib/sources/registry.mjs era um array estático mantido à mão: adicionar um adaptador exigia editar tanto <id>.mjs quanto registry.mjs. Fecha a metade pendente do item P-14 do roadmap (docs/ROADMAP.md). Agora cada *.mjs de server/lib/sources/ é carregado dinamicamente no boot do módulo; cada adaptador declara sua identidade através de um bloco autodescritivo export const meta = { value, label, region, configKey? }. Os 12 adaptadores incluídos (ashby / greenhouse / lever / rss / smartrecruiters / workable / workday + geekjob / getmatch / habr / hh / trudvsem) ganharam um meta; registry.mjs usa readdirSync + import() dinâmico resolvido via top-level await (padrão ESM Node 18+). A API pública (SOURCES, SOURCES_BY_REGION, RU_CONFIG_KEYS, getRegionalSources) não muda: todos os imports existentes continuam funcionando. A validação rejeita meta malformados e registra um console.warn por arquivo problemático. Novo tests/sources-registry-discovery.test.mjs com 14 casos. Suíte 1065 → 1079.
[1.68.2] — 2026-06-07
fix(bin): os verbos da CLI via npx / npm link estavam quebrados — o caminho do bin agora é resolvido através de links simbólicos. npm e npx expõem career-ops-ui como um link simbólico em node_modules/.bin/, onde o antigo dirname "${BASH_SOURCE[0]}" apontava para .bin em vez da raiz do pacote — então npx career-ops-ui init executava node node_modules/scripts/init.mjs e falhava com MODULE_NOT_FOUND (execuções locais após npm install não eram afetadas, o que escondia o bug). Agora bin/career-ops-ui.sh e bin/start.sh canonizam SCRIPT_DIR através da cadeia de links (laço readlink + cd -P), de modo que cada verbo funciona a partir do repo, via npm link e via npx. Adiciona um bloqueio de regressão em tests/sh-files.test.mjs que executa um verbo através de um link simbólico no estilo .bin. Suíte 1065/1065.
[1.68.1] — 2026-05-29
fix(scan): timeout de fetch por fonte 10s → 60s. O fail-fast de 10s da v1.67.1 também cortava quadros Ashby lentos mas vivos que só precisavam de mais tempo. Eleva o padrão para um minuto para que eles respondam. Trade-off: uma fonte realmente morta/travada agora ocupa um slot de concorrência pelos 60s inteiros (varredura de pior caso mais lenta), e os que travam cronicamente (Perplexity, Supabase, Resend, …) provavelmente ainda expiram — um ajuste por fonte / menor concorrência do Ashby resolveria de verdade. Override com SCAN_FETCH_TIMEOUT_MS. Suíte 1063/1063.
[1.68.0] — 2026-05-29
feat(scan): painel de filtros de resultados redesenhado — campos rotulados, botão Aplicar, opção Presencial e um filtro de salário que funciona. Cada filtro em #/scan agora é um campo rotulado (rótulo acima do controle, não um placeholder): Buscar · Tipo · Salário de · Salário até · Fonte · Escopo. Um botão Aplicar explícito (além de Limpar, e Enter em qualquer campo) reexecuta o filtro; uma dica na página explica como funciona. A faixa salarial agora filtra de verdade — ao definir um valor de/até, vagas cuja remuneração fica fora da faixa e vagas sem salário informado são descartadas (sobreposição de faixas; moeda ignorada). O filtro de Tipo ganha uma opção Presencial ao lado de Remoto / Híbrido / Realocação. Novas chaves i18n ×9; salaryInRange agora estrito; suíte 1063/1063.
[1.67.1] — 2026-05-29
fix(scan): timeout de fetch por fonte 30s → 10s (fail-fast). A elevação para 30s da v1.67.0 recuperou só ~metade dos quadros Ashby lentos; o resto (Perplexity, Supabase, Resend, DeepL, Ramp, …) trava independentemente do deadline, então um timeout maior só estagnava cada varredura esperando slots mortos. 10s falha rápido nos travamentos crônicos e mantém as varreduras responsivas. Override com SCAN_FETCH_TIMEOUT_MS. Suíte 1060/1060.
[1.67.0] — 2026-05-29
feat(scan): filtro de faixa salarial (de / até) em #/scan, e um timeout de fetch por fonte maior. A tabela de resultados ganha dois campos numéricos — salário de / até — ao lado dos filtros de texto e remoto. O salário em texto livre de cada linha (от 100 000 до 200 000 ₽, 120000-150000 USD, $120K–$150K, …) é parseado para uma faixa numérica e comparado com semântica de faixas sobrepostas; linhas sem salário publicado são mantidas, então o filtro estreita a lista em vez de esvaziá-la (a comparação ignora a moeda — sem conversão cambial). Também eleva o timeout de fetch por fonte de 15s → 30s (override: SCAN_FETCH_TIMEOUT_MS): os payloads includeCompensation do Ashby costumavam levar >15s sob concorrência ×8, então ~30 quadros Ashby expiravam a cada varredura. Novos window.Skills.parseSalaryRange/salaryInRange + i18n ×9; 13 novos testes; suíte 1060/1060.
[1.66.0] — 2026-05-28
feat(scan): as fontes RU agora percorrem TODAS as páginas, não só a primeira. hh.ru, Habr Career e Trudvsem paginavam apenas os primeiros ~50 resultados por consulta; agora seguem a paginação até o fim — &page=N para hh.ru/Habr, offset/meta.total para Trudvsem — deduplicando entre páginas e parando quando uma página não traz nada novo (ou no limite de segurança de 50 páginas). Uma consulta como “Backend разработчик” retorna agora o conjunto completo (ex.: hh.ru PHP 17 → 55+ em 3 páginas; Trudvsem retorna os 72). Cada página mantém o timeout + AbortSignal. 4 novos testes; suíte 1045/1045.
[1.65.0] — 2026-05-28
feat(scan): o hh.ru agora é coletado do seu site público em vez da API JSON — funciona de qualquer IP, sem proxy. api.hh.ru passou a retornar 403 forbidden a qualquer cliente programático independentemente de IP ou User-Agent (bloqueio anti-bot de borda). O site (hh.ru/search/vacancy) serve resultados completos a qualquer cliente tipo navegador, então o adaptador agora parseia esse HTML (como o Habr Career). Remove a variável HH_PROXY de 1.64.0 e a dependência undici — sem proxy, chave ou User-Agent. Testes reescritos para o parser HTML; suíte 1041/1041.
[1.64.0] — 2026-05-27
feat(scan): roteia a requisição ao hh.ru por um proxy russo via HH_PROXY. O hh.ru bloqueia sua API por IP, não por User-Agent — então HH_USER_AGENT sozinho nunca removia um 403 de um nó de saída fora da Rússia. Defina HH_PROXY com a URL de um proxy russo HTTP/HTTPS (ex.: http://user:pass@ru-host:port) e apenas a requisição ao hh.ru passa por ele; as demais fontes mantêm a conexão direta. Construído sobre o ProxyAgent do undici (nova dependência de runtime); o dispatcher é omitido quando HH_PROXY não está definido. 3 novos testes; suíte 1041/1041.
[1.63.2] — 2026-05-27
feat(scan): % de progresso ao vivo + detalhe por fonte no console do #/scan. A barra agora é determinada — os scanners emitem eventos de progresso (EN: por empresa; RU: por consulta) via SSE, e a barra enche com um rótulo “Scanning… NN%” (faixa animada só até o primeiro evento). A primeira falha de cada fonte (timeout / 403 / rede) é registrada em detalhe no console; repetições são suprimidas. 1 teste novo; suíte 1040/1040.
[1.63.1] — 2026-05-27
style(scan): barra de progresso de #/scan mais visível. O indicador agora tem um rótulo visível “Scanning…” e a barra passou para 8px (antes 4px finos), bem perceptível durante o scan. Sem mudança de comportamento.
[1.63.0] — 2026-05-27
feat(scan): timeout por requisição + barra de progresso em #/scan. As requisições de fontes não tinham prazo, então uma fonte travada (ex.: api.hh.ru de um IP bloqueado) podia travar todo o scan. O novo server/lib/fetch-timeout.mjs envolve o fetchImpl dos scanners (makeTimeoutFetch, padrão 15s, via SCAN_FETCH_TIMEOUT_MS); uma fonte expirada é registrada como erro não fatal e o scan continua. #/scan mostra uma barra de progresso durante o scan (scan.progress nas 9 localidades). 7 testes novos; suíte 1039/1039.
[1.62.3] — 2026-05-27
docs: instalação esclarecida (career-ops-ui roda dentro de career-ops/web-ui/) + solução de problemas do init, nas 9 localidades. Seção de instalação reescrita em Option 1 (um curl) / Option 2 (clonar a UI dentro de um projeto career-ops existente como web-ui) + verbos CLI + configuração do provedor + bloco Troubleshooting init. Nota de estrutura aninhada adicionada ao /help §1 Setup; resumo de toda a linha v1.62.* no README. Apenas documentação; sem mudança de código.
[1.62.2] — 2026-05-27
fix(help): o filtro de #/help agora é de texto completo (encontra subseções H3 como RSS). O filtro de busca/TOC da página de ajuda antes correspondia apenas a títulos de seção H2, então a documentação RSS da v1.62.x (um H3 sob §5 Portals & sources) não era encontrada. Agora o corpo de cada seção é indexado no filtro, então buscar p. ex. “RSS” mostra §5. Apenas no cliente; sem mudança de API.
[1.62.1] — 2026-05-27
feat(scan): RSS no filtro de fontes + correção de localização do RSS. O menu suspenso de filtro de fontes em #/scan agora inclui RSS (adicionado a server/lib/sources/registry.mjs + a lista de fallback do SPA), então resultados de portais RSS (LaraJobs, WeWorkRemotely, …) são filtráveis como qualquer fonte ATS. O adaptador RSS não mapeia mais a tag <category> do feed para location — essas tags faziam o location_filter descartar erroneamente vagas remotas; agora location fica vazio e os feeds passam pelo filtro de localização. Tooltips/rótulos do botão de scan e a string da lista de fontes atualizados nas 9 localidades (Workable / SmartRecruiters / Workday / RSS). Snapshot i18n e teste do endpoint de fontes (6 → 7 EN) atualizados.
[1.62.0] — 2026-05-27
feat(scan): adaptador RSS genérico para portais de vagas fora de ATS. Um novo adaptador rss (server/lib/portals/adapters/rss.mjs + server/lib/sources/rss.mjs) permite ao scanner extrair vagas de qualquer feed RSS — LaraJobs, WeWorkRemotely, RemoteOK, golangprojects e outros portais fora de Greenhouse/Ashby/Lever. Sem novas dependências: a análise do feed é baseada em regex com suporte a CDATA e entidades HTML (títulos/empresas sem tags, code points astrais decodificados com segurança). Ativado por empresa via provider: rss / rss: / feed_url: em portals.yml, sem interceptar empresas já associadas a ATS. ALL_ADAPTERS cresce 6 → 7. 29 novos testes; documentado nas 9 localidades do README.
[1.61.1] — 2026-05-22
fix(i18n): localiza o title + aria-label do alternador de tema nos 9 idiomas (MINOR-001). O botão de tema claro/escuro (#theme-toggle) tinha title="Toggle theme" e aria-label="Toggle theme" fixos em index.html — o tooltip e o texto para leitores de tela nunca eram traduzidos, em nenhum idioma. Nova chave top.themeToggle + um handler data-i18n-title em applyI18n() (espelho do fix de aria-label da busca v1.58.15) localizam ambos os atributos na inicialização e a cada troca de idioma. Travado por tests/playwright-theme-toggle-i18n.mjs (9 idiomas + troca em runtime) e dois guards estáticos. Único achado LOW do sign-off da v1.61.0. (MINOR-001)
[1.61.0] — 2026-05-22
feat(i18n): adiciona o francês como 9.º idioma da interface. Novo dicionário por idioma public/js/lib/locales/i18n-dict.fr.js (window.__I18N_DICT_FR), com paridade completa de 668 chaves com o inglês; novo pacote de ajuda docs/help/fr.md (19 H2 / 73 H3, paridade estrutural exata com en). fr fica registrado no seletor de idioma e na autodetecção do navegador (i18n.js), no montador (i18n-dict.js), no index.html (tag <script> antes do montador), no snapshot de teste e em todas as listas de locales dos testes. A tabela de tradução inicial veio do PR #9 (contribuição da comunidade). Sem mudança de lógica: t() e todas as views permanecem inalterados. 1001 / 1001 testes unitários; o sweep de locales do Playwright cresce para 9 subtests. (FR-LOCALE)
[1.60.0] — 2026-05-22
refactor(i18n): divide o megaarquivo de 8 colunas em arquivos por idioma (I18N-SPLIT). O dicionário de traduções ficava em um único public/js/lib/i18n-dict.js; agora há um arquivo por idioma em public/js/lib/locales/ mais i18n-dict.aliases.js, para que um tradutor edite um único idioma isoladamente (padrão i18next / OpenWA). i18n-dict.js passou a ser um montador que reconstrói exatamente o mesmo window.__I18N_DICT, então t() e todas as views não mudam. Carregado de forma síncrona via <script src> — sem build, sem fetch. Um snapshot prova que a migração é sem perdas (678 chaves). Ferramentas e ~25 testes adaptados; novos tests/i18n-locale-files.test.mjs e tests/playwright-locale-sweep.mjs (cada página × 8 idiomas no Chromium real). 994 → 1000 unitários · 62 → 70 Playwright. Sem mudança de comportamento. (I18N-SPLIT)
[1.59.13] — 2026-05-21
fix(i18n): colapsar chaves duplicadas reais com @alias + limpeza final de dados pessoais. Nome real removido de fixtures e relatórios QA (→ Jane Doe); LICENSE/package.json → handle Fighter90. Mecanismo @alias colapsa as 10 chaves idênticas nos 8 locales; nav.config/config.title NÃO são fundidas (divergem em espanhol). 991 → 994 testes. (I18N-CL3)
[1.59.12] — 2026-05-21
fix(i18n): limpeza de i18n-dict.js — pré-fr (I18N-CL1, I18N-CL2, I18N-CL4). Removido dado pessoal em training.coursePh (→ placeholder genérico), followup.lastPh virou dica de formato (não data fixa), adicionado npm run audit:i18n. Grupos de valores duplicados são intencionais (papéis de UI distintos). (I18N-CL1, I18N-CL2, I18N-CL4)
[1.59.11] — 2026-05-21
fix(test): v1.59.11 — a suite e2e-comprehensive agora passa 23/23 (era 11/23). Causa raiz: page.goto(baseUrl + '/#/X') é um no-op para mudanças só de hash no Playwright. Novo helper goRoute(hash) faz bounce por about:blank antes de cada goto. (e2e-harness-r1)
[1.59.10] — 2026-05-21
fix(api): NEW-F1-sub-r1 (v1.59.10) — middleware de .. cru movido para cima de todas as rotas /api. O de v1.59.8 ficava depois de app.all e nunca disparava. Agora roda antes da normalização do Express. (NEW-F1-sub-r1)
[1.59.9] — 2026-05-21
fix(ux): UX-A5-r4 (v1.59.9) — marcador de debug data-toc-spy="active" + lock-test comportamental do scroll-spy do Help TOC. Sexto ciclo. v1.59.9 adiciona marcador, paint inicial síncrono, re-compute com duplo rAF, listener de resize, e limpeza completa em hashchange. (UX-A5-r4)
[1.59.8] — 2026-05-21
fix(ux+api): v1.59.8 — UX-A5-r3 + NEW-F1-sub (HIGH + LOW agrupados). Exceção de doutrina autorizada pelo relatório FINAL-REGRESSION-v1.59.7. UX-A5-r3: #/help troca IntersectionObserver por listener scroll com rAF throttling. NEW-F1-sub: middleware rejeita .. cru em /api/* com 404 JSON. (UX-A5-r3 · NEW-F1-sub)
[1.59.7] — 2026-05-20
fix(api): NEW-D3-cache (v1.59.7) — GET /api/cv envia Cache-Control: no-store. O CV é o artefato principal do usuário; sempre revalidar. (NEW-D3-cache)
[1.59.6] — 2026-05-20
feat(a11y): NEW-D2-motion (v1.59.6) — respeito a prefers-reduced-motion: reduce. Novo bloco @media neutraliza animações, transições e scroll-behavior. (NEW-D2-motion)
[1.59.5] — 2026-05-20
fix(api): NEW-F1 (v1.59.5) — /api/* desconhecido retorna 404 JSON em todos os verbos. app.get → app.all. (NEW-F1)
[1.59.4] — 2026-05-20
fix(ui): NEW-OR1 (v1.59.4) — chip Active/Keys em #/config agora livre de races. Constrói nós antes do swap, token in-flight, cache do último estado bom. (NEW-OR1)
[1.59.3] — 2026-05-20
fix(ux): UX-A5-r2 (v1.59.3) — scroll-spy em #/help reforçado. rootMargin alargado de 10 % para 25 % + estado inicial calculado no mount. (UX-A5-r2)
[1.59.2] — 2026-05-20
fix(ui): v1.59.2 — chip Active/Keys: contagem correta, nome do provedor capitalizado, sem sobreposição. (post-v1.59.1 hotfix)
[1.59.1] — 2026-05-20
fix(test): v1.59.1 — guard NEW-D1 aceita o copy ES polido pelo UX-A11. Regex relaxada. (v1.59.1)
[1.59.0] — 2026-05-20
feat(ui): UX-A14 (v1.59.0) — Passe de auditoria mobile (≤ 420 px). Cinco correções num novo bloco @media (max-width: 420px). (UX-A14)
[1.58.65] — 2026-05-20
test(ui): UX-A2 (v1.58.65) — teste de bloqueio do field-form estruturado de Modes. Novo teste que protege a implementação v1.54.3 contra regressões. (UX-A2)
[1.58.64] — 2026-05-20
fix(i18n): UX-A11 (v1.58.64) — polimento do copy pt-BR. eval.subtitle agora usa aderência do CV, Pontuação, cabeçalho, relatório. (UX-A11)
[1.58.63] — 2026-05-20
fix(ui): UX-A15 (v1.58.63) — tile Pipeline do Dashboard com peso visual primário. O tile Pipeline agora se destaca com borda de destaque, ícone maior e label em negrito. (UX-A15)
[1.58.62] — 2026-05-20
feat(ui): UX-A9 (v1.58.62) — chip sticky de resumo na aba API keys. #/config → API keys agora exibe no topo um chip sticky com o provedor ativo e a contagem de chaves configuradas. (UX-A9)
[1.58.61] — 2026-05-20
docs(readme): UX-A8 (v1.58.61) — seção de limpeza na primeira execução adicionada nos 8 READMEs. Agora documentamos o passo make clean-test-fixtures para limpar as duas URLs fixture QA antes do primeiro scan. (UX-A8)
[1.58.60] — 2026-05-20
feat(ui): UX-A12 (v1.58.60) — Drawer de notificações com Limpar tudo + dispensar por entrada. Novo botão global e × por entrada no painel de notificações. (UX-A12)
[1.58.59] — 2026-05-20
feat(ui): UX-A13 (v1.58.59) — CTA acionável «Fix →» em linhas de saúde com falha. Linhas com FAIL/OPTIONAL agora exibem um botão ghost que leva diretamente à aba de configuração correspondente. (UX-A13)
[1.58.58] — 2026-05-20
fix(ux): UX-A10 (v1.58.58) — proteção contra perder edição não salva em #/cv. Agora beforeunload (fechamento do navegador) e hashchange (navegação SPA) exibem confirmação localizada antes de sair com buffer sujo. (UX-A10)
[1.58.57] — 2026-05-20
test(ui): UX-A7 (v1.58.57) — bloqueio de regressão sobre o contrato de auto-refresh do cost-line. Novo teste estático garante que o evento providers-changed é despachado, assinado, e que todas as views de advisor chamam UI.providerCostHint. (UX-A7)
[1.58.56] — 2026-05-20
fix(a11y): UX-A4 (v1.58.56) — .lang-btn atinge tamanho mínimo de alvo táctil WCAG 2.5.8. Antes os botões de idioma mediam 23–25 px de altura, abaixo do piso de 24×24 px. Agora min-height: 28px + min-width: 28px garantem conformidade WCAG 2.2 AA. (UX-A4)
[1.58.55] — 2026-05-20
feat(ui): UX-A3 (v1.58.55) — chip de provedor ativo no Dashboard. O hero de #/dashboard agora mostra qual provedor LLM está ativo (⚡ Live evals: Anthropic claude-sonnet-4-6 ou 📋 Manual prompt mode). Atualiza automaticamente ao mudar LLM_PROVIDER em #/config e ao recuperar foco na aba. (UX-A3)
[1.58.54] — 2026-05-20
fix(ux): UX-A1 (v1.58.54) — aviso defensivo de estrutura no brief de Deep. Quando o brief salvo não tem ao menos 3 das 6 seções canônicas (Company snapshot / Engineering culture / Recent news / Glassdoor / Interview process / Negotiation leverage), public/js/views/deep.js insere um aviso não bloqueante com link para a referência. Mitigação na UI; a correção no prompt fica no projeto pai. (UX-A1)
[1.58.53] — 2026-05-20
fix(ux): UX-A6 — todo saved-card flui pelo helper único renderSavedCard(). Garante estrutura <span>+<time> em qualquer caminho de render. 948 → 949 unitários. (UX-A6)
[1.58.52] — 2026-05-20
fix(ux): UX-A5 — scroll-spy do TOC em #/help agora dispara corretamente. Regressão de v1.58.45 (setTimeout(0) era muito cedo). Fix: refs diretos a headings + double requestAnimationFrame. 947 → 948 unitários. (UX-A5)
[1.58.51] — 2026-05-20
chore(docs): v1.58.51 — limpeza final do ciclo v1.58.37 → v1.58.50 (14 releases). Sem mudanças de código. qa/ reorganizado (tudo versionado em archive/v158-cycle/); 6 perennials na raiz. REGRESSION-FINAL §13 documenta cada invariante v1.58.37→.50. Baseline sem mudanças (947/947). (housekeeping)
[1.58.50] — 2026-05-20
docs: DOC-1 — qa/REGRESSION-FINAL.md ganha §5a documentando que os corpos de erro do servidor são inglês-por-política. Encerra NEW-D4 como not-a-finding. Fecha a fila v1.58.37 → v1.58.50 de FIX-PROMPT-FINAL-EXHAUSTIVE.md (14 releases). 946 → 947 unitários. (DOC-1)
[1.58.49] — 2026-05-20
chore(tooling): TOOL-1 — make clean-test-fixtures + script para remover linhas example.com de data/pipeline.md do projeto pai. Suporta --dry-run. 4 testes CI-isolated. 942 → 946 unitários. (TOOL-1)
[1.58.48] — 2026-05-20
fix(ux/onboarding): UX-D-B — banner global em #/dashboard quando o perfil ainda usa o template padrão. Novo profileFixtureBanner() exibe .hero-banner--warning ao detectar Profile customized: false em /api/health. Novas chaves i18n onboarding.fixtureWarning + onboarding.fixProfile × 8. 941 → 942 unitários. (UX-D-B)
[1.58.47] — 2026-05-20
fix(ux/naming): UX-D-C — botão “Quick scan” da barra superior renomeado para Abrir Scan (apenas navega, não inicia scan). Atualizado em 8 idiomas. 940 → 941 unitários. (UX-D-C)
[1.58.46] — 2026-05-20
fix(ux): UX-D-D — checklist de #/apply substitui {company}-{role} por slugs derivados de URL/JD. Antes os placeholders apareciam literalmente. Novas funções extractSlugs + substitutePlaceholders reconhecem Greenhouse/Lever/Ashby/Workable/SmartRecruiters/Workday. Fallback [company]/[role]. 939 → 940 unitários. (UX-D-D)
[1.58.45] — 2026-05-20
fix(ux): UX-D-K — scroll-spy no TOC de #/help destaca a seção atual. IntersectionObserver aplica .toc-current ao link cujo H2 está na faixa de leitura. 938 → 939 unitários. (UX-D-K)
[1.58.44] — 2026-05-20
fix(ux): UX-D-L — brief aberto em Saved-research de #/deep ganha botão × inline para fechar. Antes não havia forma de fechar sem rolar ou navegar. Nova chave deep.closeBrief × 8. 937 → 938 unitários. (UX-D-L)
[1.58.43] — 2026-05-20
fix(ux): UX-D-F — submit vazio em #/evaluate exibe toast localizado distinto. Antes confundia vazio com “muito curto”. Nova chave eval.emptyJd × 8. 936 → 937 unitários. (UX-D-F)
[1.58.42] — 2026-05-20
fix(ux): UX-D-J — paridade do chip ETA em todas as páginas de advisor. Antes só #/auto. Agora também #/evaluate, #/deep e as 5 mode-pages exibem ⏱ ~30s (nova chave advisor.eta × 8). 935 → 936 unitários. (UX-D-J)
[1.58.41] — 2026-05-20
fix(ux/truthfulness): UX-D-I — cost-hint refetcha em foco de aba + evento providers-changed. Antes só carregava uma vez; agora re-fetch via visibilitychange + CustomEvent que #/config dispara ao salvar. 934 → 935 unitários. (UX-D-I)
[1.58.40] — 2026-05-20
fix(ux/docs): UX-D-H — regression-lock garantindo que toda URL career-ops.org/docs/... visível continue clicável. Novo tests/external-doc-links.test.mjs valida views/.js e docs/help/.md. 932 → 934 unitários. (UX-D-H)
[1.58.39] — 2026-05-20
fix(ux): NEW-D2 — botão Refresh no header do painel com feedback explícito. Distinto do Refresh do banner; refetch in-place sem reload. 2 novas chaves i18n. 931 → 932 unitários. (NEW-D2)
[1.58.38] — 2026-05-20
fix(a11y): NEW-D3 (WCAG 4.1.2) — input de busca do #/tracker ganha aria-label localizado distinto do placeholder. Antes apenas placeholder; SR não anunciava o propósito. Nova chave track.searchAria × 8 idiomas, distinta do placeholder. 930 → 931 unitários. (NEW-D3)
[1.58.37] — 2026-05-20
fix(i18n): NEW-D1 — H1 de #/pipeline localizado em es/pt-BR/ru + 2 fugas RU corrigidas. pipe.title em pt-BR agora Pipeline de vagas; novo tests/i18n-no-latin-leaks.test.mjs também pegou ru.contacto.title e ru.health.title. 928 → 930 unitários. (NEW-D1)
[1.58.36] — 2026-05-20
chore(docs): v1.58.36 — sweep completo de housekeeping no fechamento do ciclo v1.58.x. Sem mudanças de código. (1) qa/: 3 snapshots versionados (REGRESSION-END-TO-END-v1.58.16/33/35.md) movidos para qa/archive/v158-cycle/. (2) REGRESSION-FINAL.md ganha §12 com todos os invariantes v1.58.4 → v1.58.35. (3) UX-AUDIT-PROMPT.md estendido com 30 linhas. (4) docs/architecture/ atualizado (FRONTEND drawer, TESTING totais 928/62/20/23). (5) CLAUDE.md ganha seção “Lições difíceis do ciclo v1.58.x”. (6) README ×8 com nova linha “Notificações 🔔” + contagem de testes corrigida. Baseline sem mudanças. (housekeeping)
[1.58.35] — 2026-05-20
fix(ui): v1.58.35 — drawer de notificações não abre mais sozinho + nova §18 “Notificações” na ajuda (reportado pelo usuário). Bug v1.58.34: .notif-drawer { display: flex } vencia o [hidden] { display: none } do UA. Fix com .notif-drawer[hidden] { display: none } explícito + drawer só abre ao clicar no sino. Nova §18 nas 8 traduções da ajuda. 927 → 928 unitários. (reportado pelo usuário)
[1.58.34] — 2026-05-20
feat(ui): v1.58.34 — Drawer de notificações (fecha U-13 completamente). Sobre a captura da v1.58.33: nova API UI.onToast(fn), sino 🔔 na top-bar com badge de não lidos, drawer à direita com título/vazio/itens localizados (notif.* × 8). Esc + fechar + clique no sino fecham. 926 → 927 unitários. (U-13 follow-up)
[1.58.33] — 2026-05-20
fix(ux): U-13 + U-14 + U-15 — diário de toasts (cap 50 + UI.getToastHistory()) + regra de segurança .page-header h1 + p + indicador de alterações não salvas em #/cv. Fecha o ciclo v1.58.x. Nova chave i18n cv.unsaved × 8 idiomas. 925 → 926 unitários. (U-13/U-14/U-15)
[1.58.32] — 2026-05-20
fix(ux): U-12 — input do filtro do TOC de ajuda ganha min-width: 16ch para os placeholders KO/JA não cortarem. Nova classe .help-toc__filter. 924 → 925 unitários. (U-12)
[1.58.31] — 2026-05-20
fix(ux): U-11 — o cabeçalho Legitimacy do Tracker agora exibe um chip ⓘ com tooltip localizado explicando a escala (Alta/Atenção/Suspeita). Nova chave i18n track.col.legitimacy.help × 8 idiomas. 923 → 924 unitários. (U-11)
[1.58.30] — 2026-05-20
fix(ux): U-10 — botões Normalize / Dedup / Merge do Tracker desabilitados quando data/applications.md está vazio. Tooltip localizado (track.fixEmpty × 8 idiomas) explica o porquê. 922 → 923 unitários. (U-10)
[1.58.29] — 2026-05-20
fix(ux): U-9 — a linha contador ↔ filtro de #/pipeline empilha verticalmente em viewports estreitas. Nova classe .pipeline-controls + @media (max-width: 720px) estica o filtro a 100% da largura. 921 → 922 unitários. (U-9)
[1.58.28] — 2026-05-20
fix(ux): U-8 — o bloco do prompt gerado fica colapsado por padrão nas 7 páginas de modo. Envolvido em <details class="prompt-block">; sumário mostra “Show prompt (N lines)” localizado (prompt.show / prompt.lines × 8). Copy + Run-live continuam visíveis. 920 → 921 unitários. (U-8)
[1.58.27] — 2026-05-20
fix(ux): U-7 — divisores ASCII === de verify-pipeline.mjs removidos do modal de resultado. Regex ^={10,}$ aplicada no handler antes de renderizar. 919 → 920 unitários. (U-7)
[1.58.26] — 2026-05-20
fix(ux): U-6 — o chip “Active companies N/M” em #/scan explica N vs M via tooltip + aria-label. Nova chave scan.activeCo.help × 8 idiomas. 918 → 919 unitários. (U-6)
[1.58.25] — 2026-05-20
fix(ux/ia): U-5 — Dashboard deduplica CTAs (botão Open Pipeline do header e tile Scan all sources removidos). Sidebar e hero já cobrem ambas as rotas; o 4× Pipeline / 4× Scan da QA v1.58.3 fica 2× cada. 917 → 918 unitários. (U-5)
[1.58.24] — 2026-05-20
fix(ux): U-4 — toasts de erro escondem o postfix “(MÉTODO /caminho · HTTP NNN)” em um <details> recolhido. O detalhe técnico segue no DOM (invariante BUG-006), mas o título fica limpo. Nova chave i18n toast.details × 8 idiomas. 916 → 917 unitários. (U-4)
[1.58.23] — 2026-05-20
fix(ux): U-3 — placeholder de lastContact em #/followup agora é calculado como hoje − 14 dias. Antes era o ISO congelado 2026-04-21 que envelhecia mal; agora é computado em render via new Date() + setDate(getDate() - 14). 915 → 916 unitários. (U-3)
[1.58.22] — 2026-05-20
fix(ux): U-2 — o H1 de #/auto não quebra mais em 2 linhas por causa do ✨ inicial. O emoji é movido para um <span class="page-icon" aria-hidden="true"> separado; .page-header--icon usa display: grid com coluna dedicada para o ícone. 914 → 915 unitários. (U-2)
[1.58.21] — 2026-05-20
fix(ux): U-1 — H1 + subtítulo do #/cv agora batem com as demais páginas (supersede UX-9 v1.56.0 by design). Chip .cv-breadcrumb removido; header usa <h1 class="page-title"> + <p class="page-subtitle">. Invariante de único <h1> preservado. 913 → 914 unitários. (U-1)
career-ops-ui v1.267.1 · page 6/9 · mirror of the project changelog for cvstart.org