Changelog

GitHub

Todas as mudanças relevantes, versão por versão. O mesmo arquivo é publicado no repositório e traduzido nos 19 idiomas.

[1.125.3] — 2026-07-23

Corrigido

  • Prompts LLM em dinamarquês e hindi respondiam em inglês (reportado por usuário) — LOCALE_NAMES e os cinco blocos de SCAFFOLD_STRINGS em server/lib/prompts.mjs nunca foram estendidos para da nem hi, então resolveLocale() caía para en e todo prompt de IA — deep research (ao vivo e manual), modos, avaliação, entrevista, networking, CV Studio — perdia sua diretiva # Output language nesses dois idiomas. Ambos agora são de primeira classe: diretiva de idioma + scaffolding localizado. O gate de regressão em tests/locale-scaffold.test.mjs agora varre a lista canônica de 17 locales em vez de 12 fixos, e um novo gate estrutural reprova qualquer chave de scaffold que caia para o inglês — um futuro locale que esqueça prompts.mjs não pode mais ser lançado (+12 testes, suíte agora 1969).

[1.125.2] — 2026-07-22

Corrigido

  • Deep research com Gemini: HTTP 502 (MALFORMED_FUNCTION_CALL) (#145, contribuição de @Alien10140) — o prompt ao vivo de /api/deep mandava o modelo «Use WebFetch / WebSearch» e salvar o relatório em arquivo, mas provedores de API headless não têm canal de ferramentas; o Gemini respondia com uma chamada de função em vez de texto, aparecendo como um 502 vazio. buildDeepPrompt e bundleProjectContext agora aceitam a flag headless: execuções ao vivo (Anthropic/Gemini/cascata de fallback) recebem um prompt sem ferramentas que escreve o relatório a partir do contexto embutido, enquanto o prompt de copiar-e-colar para o Claude Code mantém as instruções de ferramentas. +1 teste em tests/critical-fixes.test.mjs.

Alterado

  • Padrões do Gemini atualizados além do descontinuado gemini-2.0-flash (#144, contribuição de @Alien10140) — o dropdown de Configuração, o fallback do servidor em gemini.mjs (que divergia em silêncio da dica), a cadeia de fallback do OpenRouter, config.geminiModelHint ×17 e o guia de ajuda ×17 agora nomeiam gemini-3.6-flash. O novo gate anti-deriva tests/gemini-default-model.test.mjs (+5 testes) fixa todas as superfícies no mesmo literal — a suíte chega a 1957 testes.

[1.125.1] — 2026-07-21

Corrigido

  • SuccessFactors: tenants RMK multimarca mantêm seu caminho de marca (pai #2099, pós-v1.22.0) — holdings que operam várias marcas adquiridas a partir de uma única instância RMK compartilhada as diferenciam por um segmento de caminho (careers.nemetschek.com/Bluebeam/ vs …/Vectorworks/); o adaptador costumava colapsar a URL configurada para sua origem, escaneando silenciosamente as vagas da marca pai. O endpoint agora preserva o prefixo da marca, removendo apenas um segmento final /search/ ou /tile-search-results/ para que nada nunca se duplique sobre si mesmo; tenants de domínio único permanecem byte a byte inalterados. Novo helper exportado resolveTenantBase + 1 bloco de teste portado em tests/sources-successfactors.test.mjs.

[1.125.0] — 2026-07-21

Adicionado

  • cvstart.org: seção “Fontes de vagas” na landing — uma nova seção entre as capturas de tela e o comparativo lista todas as 67 fontes de scan como chips clicáveis (62 boards/ATS em inglês + os 5 boards russos sob seu próprio subtítulo), cada um linkando para o site público da fonte. A lista é sincronizada com o registry de adaptadores ao vivo no momento do build (sync-assets.mjs → facts.sources), de forma que nunca pode ficar dessincronizada do app; um mapa de links curado em Sources.astro é protegido pela nova tests/site-sources.test.mjs. A navegação do cabeçalho ganhou uma âncora Fontes; 4 novas chaves i18n do site ×17. Também foi corrigida a lista inLanguage do JSON-LD da landing, à qual ainda faltava hi.

[1.124.0] — 2026-07-21

Adicionado

  • Cinco fontes de scan (paridade com o pai v1.22.0, #1808/#1572/#2024/#2055) — Welcome to the Jungle (API JSON de todo o board), Agentic Engineering Jobs (board de engenharia agentic/IA), Jobvite (ATS por tenant sem autenticação), Gem (ATS por tenant) e Alibaba Group (API JSON de carreiras, padrão Meituan/Tencent). Cada uma é um par source + adaptador fixado por host e isolado para CI; o registry agora traz 67 adaptadores (62 EN + 5 RU); o fallback do dropdown Source de #/scan e seu gate de deriva foram atualizados; cinco novas suítes tests/sources-{wttj,agenticjobs,jobvite,gem,alibaba}.test.mjs.

Corrigido

  • Arbeitsagentur: remoto em todo o território somente quando homeofficetyp é VOLLSTAENDIG (pai #1981) — a consulta homeoffice=nv_true também retorna vagas híbridas, então a passagem de verificação de remoto agora confirma cada resultado no endpoint de detalhes da vaga em pequenos lotes e falha de forma segura (um erro de consulta mantém a cidade real da vaga, para que os filtros de localização continuem valendo).
  • SmartRecruiters: URLs públicas de vagas construídas sem /postings/ (pai #2047) — os links agora levam à página pública da vaga em vez de um 404, para tenants cujo site público omite esse segmento.

Notas

  • O pai v1.22.0 também trouxe mudanças do lado da CLI que a web UI não invoca via shell ou já cobre de outra forma: o template de CV zh-CN + tipografia do PDF, o modo /expand, ajustes de cache de prompt do provedor (Gemini/OpenAI/Ollama), o detalhamento de tokens por etapa (a web UI tem seu próprio medidor de uso), a serialização por trava de escrita do tracker (a web UI roteia gravações por withFileLock desde a v1.21), as flags de CLI visa_filter e data-de-publicação absoluta do scan (a web UI tem seu próprio filtro de idade “Publicada em até”) e a semeadura de deduplicação de fontes já vistas (o scanner da web UI mantém sua própria dedup de histórico de scan).

[1.123.0] — 2026-07-17

Adicionado

  • Source de scan Oracle Recruiting Cloud (paridade com o pai v1.21.0, #1929) — a API REST recruitingCEJobRequisitions sem autenticação dos sites de carreira Oracle Fusion/ORC (JPMorgan Chase, Oracle, BNY Mellon, American Express, Honeywell, …): host fixado em *.fa[.<região>][.ocs].oraclecloud.com, o número do site resolvido a partir do careers_url de cada empresa rastreada, paginação por offset com um teto rígido de páginas, e cabeçalhos com aparência de navegador cientes de WAF. O registry agora traz 62 adaptadores (57 EN + 5 RU); o fallback do dropdown Source de #/scan e seu gate de deriva foram atualizados; nova suíte CI-isolada tests/sources-oraclecloud.test.mjs.

Corrigido

  • Detector de repostagens: títulos base permanecem distintos de vagas irmãs com sufixo de especialização (pai #1922) — “Senior Analytics Engineer” não agrupa mais com “Senior Analytics Engineer, People Analytics”: quando os tokens de um título são um subconjunto estrito dos tokens do outro e o token extra é uma especialização real (não uma palavra de base), os dois passam a ser tratados como vagas postadas separadamente. Anotações de repostagem (“(Repost)”, “relisted”) agora são tratadas como ruído semântico via stopwords. +2 asserções em tests/detect-reposts.test.mjs.

Notas

  • O pai v1.21.0 também trouxe mudanças do lado da CLI que a web UI não invoca via shell ou já cobre de outra forma: o aviso de reaplicação para empresas repetidas (a web UI já tem o cooldown de reaplicação desde a v1.84.0), as flags --format/--report da carta de apresentação, os modos de prompt de e-mail de red-flag / panel-intel / no-show da entrevista, os sinais de confiança do scan e a persistência de saúde dos portais (a web UI roda seu próprio scanner em processo com trust-validator e a página de saúde dos Portais), e as extensões de estatísticas/salary-gap (relayadas somente leitura e com fail-soft).

[1.122.0] — 2026-07-16

Adicionado

  • Hindi (हिन्दी) — o 17º idioma — dicionário completo da interface (~1.110 chaves), o guia de ajuda embutido no app na íntegra (paridade de 29 H2 / 105 H3), README.hi.md, um novo CHANGELOG.hi.md (começando na v1.122.0, seguindo o precedente de de/it/tr), a landing do cvstart.org + as páginas de Metodologia/Licença/Changelog/Ajuda, o seletor de idioma (🇮🇳), a detecção automática do idioma do navegador e uma captura de tela do dashboard localizada. Todos os gates de paridade ×16 agora rodam ×17: paridade do dicionário i18n + snapshot, gates de H2/H3 da ajuda, paridade do CHANGELOG, check-i18n do site e a varredura de locales do Playwright.

[1.121.0] — 2026-07-16

Adicionado

  • cvstart.org: páginas de Metodologia, Licença e Changelog — a landing ganhou três novas seções em todos os 16 idiomas, ao lado do bloco de Comparativo já existente: /methodology/ (a rubrica de pontuação em seis dimensões de 0,0 a 5,0, o limiar de 4,0 para candidatura e as regras que o sistema nunca segue — um resumo localizado de career-ops.org/methodology), /license/ (o texto canônico da MIT com o ponteiro para o NOTICE.md) e /changelog/ (este mesmo arquivo, renderizado por locale a partir dos 16 CHANGELOGs traduzidos do repositório). Nova entrada Metodologia no cabeçalho e links de Recursos no rodapé; o sync-assets.mjs agora sincroniza o CHANGELOG ×16 e a LICENSE para o site no momento do build, para que as páginas nunca fiquem dessincronizadas do repositório.
  • Links para a metodologia em toda a documentação — o README (nos 16 idiomas), a lista canônica do §1 do guia de ajuda embutido no app (nos 16 idiomas) e a wiki agora linkam career-ops.org/methodology (além do FAQ e do glossário), ao lado dos guias já existentes de career-ops.org/docs.

Alterado

  • Banner de release e badges do README atualizados (testes 1850, release v1.121.0) — o banner ainda anunciava a v1.119.5.

[1.120.0] — 2026-07-16

Adicionado

  • O Manifesto CareerOps (paridade com o pai v1.20.0) — o projeto pai lançou o Manifesto CareerOps (MANIFESTO.md · career-ops.org/manifesto) e agora o expõe no seu README, no updater e no dashboard em Go. A web-ui segue o mesmo caminho: um novo link no rodapé da barra lateral abre a página do manifesto (nova chave i18n footer.manifesto nos 16 locales), o guia de ajuda embutido no app ganhou o §29 “O Manifesto CareerOps” nos 16 idiomas, o README explica o que é o manifesto e como assiná-lo, e o rodapé da landing cvstart.org também tem um link para ele.

Notas

  • O pai v1.20.0 também corrigiu a supressão de habilidades conhecidas no modo direcionado do upskill, silenciou o dotenv para que o stdout de scan --json continue analisável, e corrigiu o template HTML de CV para que o cabeçalho de um cargo permaneça junto com seus marcadores — superfícies do lado da CLI que a web-ui não invoca via shell; nenhuma mudança de código foi necessária na web-ui.

[1.119.5] — 2026-07-13

Corrigido

  • O botão de idioma da landing não quebra mais — com as bandeiras da v1.119.2 o rótulo do seletor no cabeçalho (ex.: «🇷🇺 Русский») podia quebrar em até três linhas em larguras estreitas de desktop; o rótulo do seletor e todas as opções do dropdown agora usam whitespace-nowrap — bandeira + endônimo sempre em uma linha. A lista de idiomas do rodapé passou de uma grade rígida de duas colunas para uma linha com quebra de itens de linha única — «🇧🇷 Português (Brasil)» também não quebra mais no meio do nome.

[1.119.4] — 2026-07-13

Alterado

  • LICENSE nomeia o autor — a linha de copyright agora diz: Sergei Emelianov (Fighter90) https://sergey-cv.com and career-ops-ui contributors (texto MIT canônico intacto). Um novo NOTICE.md detalha o licenciamento: quem detém o copyright, o que exatamente a concessão MIT cobre (código, docs, traduções, a landing, a wiki), o que NÃO cobre (seus dados em runtime, o projeto pai, o conteúdo dos job boards, marcas registradas), a tabela de componentes de terceiros (express/js-yaml — MIT; Astro/Tailwind — MIT; as fontes Figtree e JetBrains Mono — SIL OFL 1.1; sharp — Apache-2.0) e uma linha de atribuição opcional.

[1.119.3] — 2026-07-13

Adicionado

  • SECURITY.md — a política de segurança para a qual o CONTRIBUTING apontava agora existe: versões suportadas, fluxo de reporte privado (o repositório tem o private vulnerability reporting do GitHub habilitado — aba Security → «Report a vulnerability»), o modelo de ameaças para um app de usuário único em localhost (no escopo: XSS via vagas hostis / SSRF / path traversal / vazamento de segredos / enfraquecimento de CSP; fora do escopo: DoS no próprio localhost e problemas do projeto pai) e a linha de base de hardening para revisores.

[1.119.2] — 2026-07-13

Adicionado

  • CONTRIBUTING.md — o guia do contribuidor para o qual a landing e o README sempre apontaram agora existe: instalação, mapa do projeto, as regras rígidas de segurança/no-build, níveis de teste, o passo a passo dos «dois registries» para adicionar uma fonte de escaneamento, o contrato i18n ×16, convenções de commits/PR e o processo de release.
  • Bandeiras de idiomas na landing — o seletor de idiomas do cvstart.org, a grade de idiomas do rodapé e o banner «leia no seu idioma» agora mostram a bandeira de cada locale ao lado do seu endônimo (o mesmo conjunto de indicadores regionais do <select> de idioma do app; degrada para letras de região onde faltam glifos de bandeira).
  • Correções do rodapé da landing — o link morto de Discussions (recurso não habilitado no repositório) agora aponta para a wiki do projeto, e o rodapé credita o autor: Sergei Emelianov (sergey-cv.com · LinkedIn).

[1.119.1] — 2026-07-13

Corrigido

  • O filtro de fontes do #/scan alcançou o registry — a lista estática FALLBACK_SOURCES por trás do dropdown Source (usada apenas quando GET /api/scan/sources está inacessível) ficou silenciosamente defasada desde a v1.87.0: faltavam 20 provedores no fallback offline (Amazon, Avature, SAP SuccessFactors, Get on Board, Dassault Systèmes, beesite, HigherEdJobs, JibeApply (iCIMS), softgarden, Cornerstone, Phenom, Radancy, Deutsche Bahn, EchoJobs, TKMS, Heckler & Koch, Rheinmetall, LaraJobs e os novos Meituan / Tencent). Sincronizada com os 61 e agora protegida por um teste de deriva que quebra a CI quando a lista do cliente diverge do registry do servidor (valores E rótulos). +1 teste (1845).

[1.119.0] — 2026-07-13

Paridade com o career-ops pai v1.19.0 + renovação da landing cvstart.org.

Adicionado

  • 2 novos provedores de escaneamento — Meituan (zhaopin.meituan.com) e Tencent (careers.tencent.com): as APIs JSON públicas sem autenticação dos boards tech chineses, detectadas pelo host ou selecionadas por um provider: explícito, com busca server-side por palavra-chave, paginação e deduplicação por URL — agora 61 adapters (56 EN + 5 RU). +20 testes (1844).
  • Bloco de contribuidores na landing — o cvstart.org mostra os avatares de todos que contribuíram com código (API /contributors do GitHub em tempo de build, bots filtrados), localizado nos 16 idiomas, com link para o grafo completo de contribuidores.
  • Contador de estrelas do GitHub ao vivo na landing — o badge do cabeçalho agora se atualiza no cliente a partir da API do GitHub a cada visita (o snapshot de build fica como fallback), e uma reconstrução semanal agendada do Pages mantém o snapshot e a lista de contribuidores frescos; as chamadas de API no CI são autenticadas por token.

Corrigido

  • As requisições Workday CXS levam cabeçalhos de navegador (pai #1813) — tenants atrás do Cloudflare (visto ao vivo: geico) respondem 500 a requisições sem UA/accept-language/origin/referer comuns; o fetcher agora deriva o origin e o slug do site da própria URL CXS. As requisições do Glints ganharam o mesmo UA de navegador + origin/referer, ambos da constante compartilhada BROWSER_LIKE_USER_AGENT em http-json.mjs.

[1.118.4] — 2026-07-10

Corrigido

  • As varreduras do hh.ru retornavam 0 resultados a partir de um IP russo (links de subdomínio regional) — a partir de um IP residencial russo, o hh.ru redireciona a busca (302) para um subdomínio regional (sochi.hh.ru, spb.hh.ru, …) e devolve os links de vagas nesse subdomínio. O parser procurava o link do título pelo host fixo https://hh.ru/vacancy/ e não casava com nenhum dos regionais, então uma varredura totalmente funcional registrava 0 em silêncio. Agora aceita qualquer host *.hh.ru (anúncios em adsrv.hh.ru/click?… continuam excluídos — não têm caminho /vacancy/<id>) e canonicaliza cada URL de resultado para https://hh.ru/vacancy/<id>. Verificado ao vivo: 17 vagas reais são parseadas de uma página sochi.hh.ru que antes dava 0. +1 teste (1824).

[1.118.3] — 2026-07-10

Corrigido

  • hh.ru retornava 0 resultados em silêncio (interstitial de verificação de VPN) — o hh.ru agora redireciona com 302 as redes que marca como VPN/proxy (IPs de datacenter) para um interstitial /vpncheeck (“VPN мешает работе сайта”) que responde HTTP 200 sem nenhum cartão de vaga, então o scan reportava 0 sem erro algum. O scanner agora detecta o redirecionamento pela URL final da resposta, desativa o hh.ru pelo resto da execução e imprime uma dica honesta: o tráfego precisa realmente sair por um IP residencial — um VPN/proxy em nível de sistema pode continuar ativo mesmo com o botão do navegador desligado. +1 teste (1823).

[1.118.2] — 2026-07-10

Manutenção

  • Follow-up do landing (#118) — site/README.md reconciliado com o Astro 7 (o upgrade de segurança do #116), import sem uso removido e +4 guardas executáveis para os scripts de build do landing: o gate de paridade i18n comprovadamente falha com um dicionário quebrado e o sync-assets nunca escreve fora de site/ — suíte 1822. Dois alertas do CodeQL resolvidos (um corrigido na fonte, outro dispensado como comportamento intencional de build).

[1.118.1] — 2026-07-10

Corrigido

  • Escaneio do hh.ru fora da Rússia — o hh.ru agora devolve HTTP 451 (bloqueio legal regional) a IPs não russos nas páginas públicas de busca. O scanner trata o 451 como o 403: após o primeiro bloqueio o hh.ru é desativado pelo resto da execução com uma mensagem honesta no log apontando para IP russo / saída VPN, sem desperdiçar as consultas restantes nem as demais fontes RU. Ajuda §7 atualizada nos 16 idiomas. +1 teste (1818).

[1.118.0] — 2026-07-09

Pacote de paridade com o career-ops pai v1.18.0.

Adicionado

  • 9 novos provedores de escaneamento — Cornerstone OnDemand (csod), Phenom (phenom), Radancy (radancy), Deutsche Bahn (deutschebahn), EchoJobs (echojobs), TKMS (tkms), Heckler & Koch (hecklerkoch), Rheinmetall (rheinmetall), LaraJobs (larajobs) — agora 54 adaptadores. O adaptador do Lever também detecta boards do tenant EU (jobs.eu.lever.co).
  • Status Hired no tracker (paridade com o states.yml do pai): ofertas aceitas ganham estado canônico próprio, um badge comemorativo e um banner de «vaga conquistada» no #/tracker; o funil e as conversões o contam como tendo avançado por todas as etapas.
  • Aba Histórico em #/stats — relay somente leitura do stats.mjs do pai (resumo histórico do tracker, taxas do funil acumulado, totais do scanner, cobertura de portais) mais observações de remuneração do salary-gap.mjs (desejado vs anunciado vs real, por candidatura). Novas rotas GET /api/stats/lifetime e GET /api/stats/salary-gap — shell-outs de zero tokens, degradação segura {available:false} sem o projeto pai.
  • 28 novas chaves i18n nos 16 idiomas; guia de ajuda §14/§26 atualizado em todos.

Testes

  • +38 testes unitários (três suítes de paridade de provedores + rotas de relay/status) — 1817 no total.

[1.117.2] — 2026-07-06

Correção de tracker vazio para os shell-outs de paridade. Os scripts do pai saem com código 1 e um JSON {error} estruturado quando o tracker ainda não tem candidaturas; o quadro de follow-up e a aba de padrões mostravam isso como «script-error». Ambas as rotas agora o transmitem como um estado vazio saudável (available:true, empty:true) e a UI mostra sua mensagem honesta de «nada ainda». Verificado ao vivo contra um pai real.

Novo: nenhum.

[1.117.1] — 2026-07-06

Endurecimento do v1.117.0 (triagem CodeQL). Os três endpoints shell-out (GET /api/followup, POST /api/followup/seed, GET /api/stats/patterns) agora carregam o limitador por IP compartilhado (geram um processo filho por requisição; no-op em loopback). A extração de texto por URL do Adicionar ao CV remove tags até ponto fixo e depois apaga todo </> restante — saneamento comprovadamente completo para texto de prompt LLM. Sem mudanças para entradas válidas.

Novo: nenhum.

[1.117.0] — 2026-07-06

Pacote de paridade com o pai — seis capacidades do career-ops pai trazidas à UI. (1) Quadro de cadência de follow-up em #/followup com urgência por candidatura (🔴/🟠/🟡/🔵) do followup-cadence.mjs, mais o botão Semear datas (followup-seed.mjs --backfill). (2) Padrões de rejeição: quarta aba de Estatísticas que executa analyze-patterns.mjs (somente leitura) — mistura de resultados, recomendações e taxa de avanço por fornecedor ATS. (3) Adicionar ao CV: um cartão do CV Studio transforma uma URL ou texto colado em tópicos ATS baseados SOMENTE nessa fonte (apenas sugestões, sem gravações; o fetch de URL é protegido contra SSRF). (4) 4 novos provedores de scan — beesite, HigherEdJobs (RSS), JibeApply (iCIMS), softgarden — o registro agora tem 50 adaptadores (45 EN + 5 RU), todos no dropdown do Scan. (5) Etapa de pré-varredura de desqualificadores no checklist do Apply. (6) Runner reconcile (/api/run/reconcile). Rotas shell-out degradam com honestidade sem os scripts do pai.

  • Novo módulo server/lib/routes/followup.mjs (31.º) + novas rotas + 8 arquivos source/adapter. Testes: 6 + 7 novos; suíte 1737 → 1750. 41 chaves i18n ×16. Ajuda §13/§17/§24/§26 ampliada ×16.

Novo: GET /api/followup, POST /api/followup/seed, GET /api/stats/patterns, POST /api/cv-studio/add-entry, POST /api/run/reconcile.

[1.116.0] — 2026-07-06

Medidor de uso refeito + primeiro teste ponta a ponta de widgets. O medidor de uso de IA (v1.114.0) foi corrigido e fixado corretamente: agora fica fixado no fim da barra lateral esquerda (toda a largura, com a mesma superfície) e reserva embaixo um espaço igual à sua altura para que o menu nunca seja coberto — a navegação e o rodapé de versão sempre rolam livres acima. Ele atualiza ao vivo (a cada 15 s, ao focar a aba e ao mudar de rota), e cada linha de janela mostra agora <tokens> · <custo estimado> real (as barras escalam contra a janela de 30 dias) em vez de uma “parcela” sempre em 100%. Além disso: uma barreira typeof durável no importador de CV fecha na origem o falso positivo recorrente de type-confusion do CodeQL, e um novo teste ponta a ponta do Playwright exercita ambos os widgets persistentes num navegador real.

  • public/js/lib/usage-hud.js + app.css, server/lib/cv-import.mjs. Testes: tests/playwright-widgets.mjs (2 E2E) + tests/usage-hud.test.mjs (10). Ajuda §6 ampliada ×16.

Novo: nenhum.

[1.115.0] — 2026-07-06

Acabamento de design (conservador, marca coral mantida). Uma passada leve de refinamento sobre o sistema de design compartilhado — sem reestruturar, sem mudar a paleta. Os cartões de métricas do painel agora se elevam e ganham uma borda coral ao passar o mouse (como os blocos de ação rápida); os cartões de conteúdo se elevam um pouco; os botões primary / dark / danger ganham uma sombra em repouso e uma leve elevação ao passar o mouse; números grandes se alinham com tabular-nums; e os controles interativos recebem um halo coral suave atrás do anel de teclado de 2px. Todo movimento respeita prefers-reduced-motion, e o halo é restrito aos controles — nunca um *:focus-visible global.

  • Somente CSS (public/css/app.css); sem mudanças de marcação, i18n, rotas ou CSP. Testes: tests/design-polish-v1115.test.mjs (5). Verificado ao vivo com Playwright.

Novo: nenhum.

[1.114.0] — 2026-07-06

Medidor de uso e custo de IA na barra lateral (canto inferior esquerdo). Uma seção USO compacta agora fica no fim da barra lateral (um cartão fixo no canto inferior esquerdo se não houver barra lateral; inferior direito em RTL) em cada página. Mostra seu uso de tokens LLM em janelas de 24h / 7d / 30d — cada uma como <tokens> · <parcela%> com uma barra verde (parcela do total histórico) — mais um rodapé com o custo estimado de 24h. Os dados são o resumo somente leitura GET /api/usage de data/llm-usage.jsonl (só local), a mesma fonte da página #/usage; o custo é uma estimativa e execuções no modo manual são grátis e não contadas. Recolhível — o cabeçalho alterna e o estado persiste.

  • Novo widget cliente public/js/lib/usage-hud.js carregado de index.html, montado na barra lateral acima do rodapé de versão (alternativa de canto fixo). Seguro para CSP; com tema e espelho RTL. Sem nova rota de servidor. Testes: tests/usage-hud.test.mjs (8). 3 novas chaves i18n ×16.

Novo: nenhum.

[1.113.0] — 2026-07-06

Assistente flutuante “Pergunte à ajuda” em cada página. Um botão de chat com um robô e gradiente agora flutua no canto inferior direito (inferior esquerdo em RTL) de cada página. Toque para abrir um chat compacto que responde a perguntas de uso baseando-se SOMENTE no guia de ajuda no seu idioma — o mesmo endpoint da página #/docs-assistant (POST /api/docs-assistant/ask), então nunca lê seu CV, perfil ou rastreador. Ao vivo com uma chave LLM; sem chave → um prompt pronto. O cabeçalho mostra um avatar de robô + status online; chips iniciam perguntas comuns; Esc ou clique fora fecha; oculta-se na página #/docs-assistant.

  • Novo widget cliente public/js/lib/docs-fab.js montado globalmente a partir de index.html; seguro para CSP; estilos com tema e espelho RTL em app.css. Sem nova rota de servidor. Testes: tests/docs-fab.test.mjs (8). 6 novas chaves i18n ×16. Ajuda §1 ampliada no lugar.

Novo: nenhum.

[1.112.0] — 2026-07-06

Consolidação de docs e QA. Sem mudança de código visível. O documento de convenções SDD (docs/sdd/CONVENTIONS.md) é atualizado para os 30 módulos de rota atuais (era 24) e a base de testes atual; o prompt de QA definitivo de todo o projeto (qa/QA-REGRESSION-PROMPT.md) é consolidado — mecânica de release atualizada (v1.111, parentVersion 1.17.0, publicação disparada pelo release), a tabela de adições §14 corrigida (Excluir do Scan reetiquetado v1.109.0) e ampliada com o fechamento do CodeQL de v1.111 — para valer sozinho como o único prompt de regressão de toda a funcionalidade. Adiciona um teste de cobertura para o ramo de upload superdimensionado.

Novo: nenhum.

[1.111.0] — 2026-07-06

Segurança — fechamento do backlog do CodeQL. Três reforços de defesa em profundidade que fecham os achados de análise estática restantes na origem em vez de descartá-los. stripDangerousMarkdown agora escapa o < de qualquer abertura de tag perigosa truncada (uma carga terminando em <script/<iframe/…), de modo que sua saída não contém nenhuma tag perigosa viva. A importação de CV lê o tamanho do buffer enviado por meio de uma coerção explícita com Number() — uma barreira contra confusão de tipos. As linhas de papel dos modos agora são strings de template interpoladas com String.replace em vez de funções armazenadas, removendo por completo a chamada de despacho dinâmico. Sem mudança visível para o usuário.

  • server/lib/security.mjs, server/lib/cv-import.mjs, server/lib/prompts.mjs. Testes: tests/security-hardening-v1111.test.mjs (7) + teste de guarda v1108 atualizado. Sem mudanças de i18n/ajuda/rotas.

Novo: nenhum.

[1.110.0] — 2026-07-06

Atualização de docs e QA (todos os idiomas). Sem mudança de código. O prompt de QA do projeto todo é atualizado para v1.109.0 com um novo §14 (v1.98→v1.109), e os prompts perenes de UX-audit e design-export ganham a superfície atual. Cada parágrafo de ajuda adicionado em v1.100–v1.109 agora está traduzido para os 16 idiomas.

Novo: nenhum.

[1.109.0] — 2026-07-06

Filtro Excluir no Scan + visão geral do pipeline (paridade de layout com a web principal). Em #/scan, a caixa Pesquisar trata vírgulas como OU (“cargos a encontrar”) e um novo campo Excluir oculta qualquer linha cuja empresa/cargo/local contenha alguma palavra separada por vírgula (ex. senior, staff); ambos são lembrados nas suas buscas salvas. Em #/pipeline, uma faixa de visão geral compacta mostra seu pipeline num relance — N na caixa, N rastreadas e as contagens de Applied / Responded / Interview / Offer do tracker, cada chip liga a #/tracker.

  • Somente cliente (sem nova rota/gravações). public/js/views/scan.js + public/js/views/pipeline.js. Testes: tests/scan-pipeline-ui-v1109.test.mjs (2). 4 novas chaves i18n ×16. Ajuda §7 + §8 ampliadas no lugar.

Novo: nenhum.

[1.108.0] — 2026-07-06

Reforço de segurança (triagem do CodeQL, rodada 2). Mais três achados de baixa severidade corrigidos: o construtor de prompts resolve a linha de papel do idioma por chave própria + typeof === function para que um idioma adulterado não despache a um método de protótipo (unvalidated-dynamic-method-call); o slug do nome do arquivo PDF é limitado a 200 caracteres antes do regex para que uma entrada só de hifens não retroceda (ReDoS polinomial); e a importação de documentos coage um filename array (cabeçalho repetido) para string (type-confusion). Sem mudança de comportamento para entrada válida.

  • server/lib/prompts.mjs, server/lib/routes/runners.mjs, server/lib/cv-import.mjs + tests/security-hardening-v1108.test.mjs (3). Em v1.106–v1.108 o backlog de análise estática foi de 167 a ~14, com cada achado realmente relevante para segurança corrigido e o restante (falsos positivos protegidos/sanitizados + lint de nível nota) descartado com justificativa.

Novo: nenhum.

[1.107.0] — 2026-07-06

Reforço do sanitizador (defesa em profundidade XSS em repouso). stripDangerousMarkdown — que neutraliza HTML perigoso no markdown de CV/vaga armazenado para que qualquer consumidor que ignore o cliente com escape-ao-renderizar continue seguro — agora executa sua limpeza de tags até um ponto fixo (repetir até estabilizar) para que uma remoção que reforme um payload (ex. <scr<script></script>ipt>) seja capturada, corresponde a tags de fechamento de script/style/etc. com lixo no final (</script foo>) e remove um abridor executável não fechado. O comportamento para markdown válido não muda — só remove mais.

  • server/lib/security.mjs: laço de ponto fixo (limitado a 8 passagens) + padrões de fechamento [^>]*> + remoção de abridor não fechado. +3 casos de regressão em tests/cv-xss-bypasses.test.mjs. O limite XSS autoritativo continua sendo o escape na saída (UI.md); isto reforça a garantia em repouso e fecha os achados do CodeQL correspondentes.

Novo: nenhum.

[1.106.0] — 2026-07-06

Reforço de segurança (triagem do CodeQL). Corrigidos três achados reais (embora de baixa severidade): o caminho de erro de renderização agora escapa a mensagem de erro antes de chegar ao DOM (um erro do servidor pode refletir entrada do usuário, então é tratado como não confiável — limite XSS), e as gravações de propriedades de perfil/config rejeitam as chaves __proto__ / constructor / prototype (proteções contra poluição de protótipo por precaução — as chaves vêm de specs de campos fixos, não de entrada bruta). A maioria dos alertas restantes são falsos positivos sobre leituras/gravações legítimas do scanner em data/* e sobre rotas que já têm o limitador próprio; foram descartados com justificativa.

  • public/js/router.js escapa err.message com UI.escapeHtml antes de innerHTML; server/lib/routes/content.mjs e server/lib/routes/config.mjs protegem as chaves de protótipo. Sem mudança de comportamento para entrada válida. Testes: tests/security-hardening-v1106.test.mjs (3). Sem novas chaves i18n.

Novo: nenhum.

[1.105.0] — 2026-07-06

Página de uso e custo de IA. Uma nova página Uso de IA (barra lateral, ao lado de Saúde) mostra quantos tokens você gastou em gerações de IA ao vivo — avaliações, relatórios, chats — detalhado por provedor nas últimas 24 horas, 7 dias, 30 dias e todo o período, com um custo estimado em USD. Cada chamada ao vivo anexa um pequeno registro {provider, in, out} a data/llm-usage.jsonl (nada é enviado a lugar nenhum); execuções sem chave (modo manual) não custam nada e não são registradas.

  • Novo módulo de rota (30º) server/lib/routes/usage.mjs — GET /api/usage (agregações somente leitura) + server/lib/llm-usage.mjs (recordUsage normaliza as formas de uso de Anthropic/OpenAI/Gemini e anexa em best-effort; readUsage/aggregate agregam por janela 24h/7d/30d/tudo × provedor) + server/lib/llm-pricing.mjs (uma tabela editável de preços por provedor $/1M tokens — tokens são exatos, dólares são preços de lista aproximados que você pode corrigir; nunca cobrados). O registro é conectado nos pontos de despacho (runActiveProvider + routes/llm.mjs).
  • Nova visão public/js/views/usage.js (#/usage, abas de janela). Testes: tests/usage-routes.test.mjs. 17 novas chaves i18n ×16 (usage.* + nav.usage). Ajuda §6 ampliada no lugar.

Novo: server/lib/routes/usage.mjs; server/lib/llm-usage.mjs; server/lib/llm-pricing.mjs; public/js/views/usage.js.

[1.104.0] — 2026-07-06

Logos de empresa na tabela de varredura (preservando privacidade). Um novo botão em Aparência nas Configurações — Mostrar logos de empresa na tabela de varredura (desativado por padrão) — desenha o logo de cada empresa ao lado do nome em #/scan. O logo é o favicon da empresa obtido do próprio domínio e com proxy no servidor (GET /api/logo), de modo que nenhum serviço de logos de terceiros descobre quais empregadores você vê. Vagas em um portal compartilhado (Greenhouse, Lever, Ashby, …) mostram um selo com uma letra em vez do ícone do portal, e qualquer logo que falhe ao carregar recai no mesmo selo.

  • Novo módulo de rota (29º) server/lib/routes/logos.mjs — GET /api/logo?domain=. Valida o domínio (sem esquema/caminho/loopback), busca /favicon.ico pelo safeGet seguro contra SSRF (um novo modo binary retorna os bytes crus + content-type; fixação de DNS, validação de redirecionamentos e limite de tamanho inalterados), faz sniff de assinatura de imagem para nunca servir uma página HTML de erro como imagem, faz cache de acertos e erros em um LRU em memória e não grava nada em disco.
  • Nova lib cliente public/js/lib/company-logo.js (window.CompanyLogo): desativada por padrão via flag em localStorage; ignora hosts ATS compartilhados em favor de um avatar-letra determinístico; recuo img.onerror seguro para CSP. Testes: tests/logo-routes.test.mjs. 5 novas chaves i18n ×16 (appear.*). Ajuda §2 ampliada no lugar.

Novo: server/lib/routes/logos.mjs; public/js/lib/company-logo.js.

[1.103.0] — 2026-07-06

Configurações: “Ferramentas CLI de IA” — quais estão instaladas. o career-ops é baseado no Claude Code mas funciona com qualquer CLI de agente no padrão aberto de skills. Uma nova aba Ferramentas CLI de IA em Configurações (#/config) mostra quais — Claude Code, Codex, Gemini CLI, OpenCode, GitHub Copilot CLI, Qwen, Antigravity — estão instaladas na máquina que executa o servidor, e seus caminhos. É uma varredura somente leitura do PATH: só verifica se cada binário existe e nunca o executa (sem --version, sem execução), não grava nada e não toca dados do usuário.

  • Novo módulo de rota (28º) server/lib/routes/cli-detect.mjs — GET /api/cli-detect. A detecção resolve o caminho de um binário a partir de uma allowlist fixa de 7 entradas em process.env.PATH (shims .cmd/.exe/.bat no Windows; bit de execução no POSIX); um arquivo hostil no PATH nunca pode ser executado por esta rota.
  • Nova aba “Ferramentas CLI de IA” em public/js/views/config.js (carregamento tardio, com deep-link via #/config?tab=cli). Testes: tests/cli-detect-routes.test.mjs. 8 novas chaves i18n ×16 (cli.* + config.tabCli). Ajuda §2 ampliada no lugar.

Novo: server/lib/routes/cli-detect.mjs.

[1.102.0] — 2026-07-05

“Perguntar ao guia” — um chat fundamentado sobre o guia de ajuda integrado. Nova página Perguntar ao guia 💬 (barra lateral, sob Ajuda): digite uma pergunta como “Como escaneio portais de vagas?” e receba uma resposta extraída apenas do guia de ajuda do app no seu idioma — mostra quais seções usou e nunca lê seu currículo, perfil ou busca de emprego. É sobre como usar o app, não sobre você. Com chave LLM responde ao vivo; sem chave entrega um prompt pronto, já preenchido com as seções de ajuda relevantes.

  • Novo módulo de rota (27º) server/lib/routes/docs-assistant.mjs — POST /api/docs-assistant/ask. Recuperação sem dependências: o guia do seu idioma é dividido em suas seções ## e pontuado por sobreposição de palavras-chave com sua pergunta; as melhores são incluídas e o modelo deve responder a partir delas ou dizer que o guia não cobre (sem recursos/rotas inventados). Cascata de provedores compartilhada, recuo manual, com limite de taxa, sem gravações, não lê dados do usuário.
  • Nova visão public/js/views/docs-assistant.js. Testes: tests/docs-assistant-routes.test.mjs. 14 novas chaves i18n ×16 (docs.* + nav.docsAssistant). Ajuda §1 ampliada no lugar.

Novo: server/lib/routes/docs-assistant.mjs; public/js/views/docs-assistant.js.

[1.101.0] — 2026-07-05

CV Studio: adapte seu currículo + escreva uma carta de apresentação para uma vaga específica, com verificação estilo recrutador. Novo cartão Adaptar a uma vaga em #/cv-studio: cole uma descrição de vaga (e, opcionalmente, um cargo/título-alvo) e o CV Studio produz um currículo adaptado a essa vaga mais uma carta de apresentação correspondente, depois passa ambos por uma verificação antes de entregar — error bloqueia (corrigido antes de você ver), warn aconselha. A mecânica é destilada da prática de coaching de carreira em regras genéricas — o recrutador lê em segundos, então o relevante vai ao topo, o título combina com o cargo da vaga, os resultados trazem números específicos e a carta é um teaser curto com uma única ponte “requisito ↔ seu fato correspondente”. Baseia-se apenas no seu currículo, perfil e two-pager e nunca inventa — sem empresas, cargos ou histórico embutidos.

  • Novo endpoint POST /api/cv-studio/tailor (amplia o módulo cv-studio existente — sem 27º módulo): buildTailorPrompt + verificação genérica TAILOR_INSTRUCTIONS, baseada em bundleProjectContext, cascata de provedores compartilhada, recuo manual sem chave, com limite de taxa, sem gravações. O resultado exporta para Markdown / PDF / DOCX pela barra compartilhada report-export.js.
  • Testes: +3 em tests/cv-studio-routes.test.mjs. 10 novas chaves i18n ×16 (cvs.tailor*). Referência genérica docs/prompts/resume-cover.md. Ajuda §24 ampliada no lugar.

Novo: docs/prompts/resume-cover.md.

[1.100.0] — 2026-07-05

Two-pager: autopreenchimento por IA a partir do seu CV + Pré-visualização + exportar para PDF/DOCX/Markdown. O two-pager (#/two-pager) registra o que você realmente quer da sua próxima vaga, mas antes era preciso redigir cada campo à mão ou copiar um prompt para outra ferramenta. Agora o ✨ assistente de preenchimento por IA roda ao vivo com o provedor configurado: lê apenas seu CV + perfil (via bundleProjectContext, sem inventar nada), redige todos os campos (quem sou / gosto / indispensáveis / detesto / limites / inegociáveis / ambiente-alvo) e preenche o formulário para você revisar, editar e salvar. Sem chave de API, volta ao modal de copiar-o-prompt, como antes. Um novo botão 👁 Pré-visualizar e exportar renderiza o two-pager como documento com uma barra Baixar .md / Salvar como PDF / Salvar como DOCX / Copiar.

  • Exportação .docx sem dependências. Novo server/lib/docx.mjs que gera um .docx Office Open XML mínimo mas válido (um ZIP DEFLATE das quatro partes OOXML, com CRC-32 por entrada) — sem nova dependência (as deps continuam express + js-yaml). Nova rota POST /api/export/docx (server/lib/routes/export.mjs, o 26º módulo de rotas; sem estado, limitado a 200 KB, sem gravações / sem LLM / sem fetch de URL). Integrado ao public/js/lib/report-export.js compartilhado, então o relatório de mercado, o plano de carreira e a orientação profissional também ganham exportação para DOCX.
  • O autopreenchimento ao vivo usa a cascata de provedores compartilhada (runActiveProvider / providerAvailable); o YAML retornado é parseado e ajustado de volta ao formato limitado do two-pager (parseYamlFields + normalizeTwoPager) — chaves desconhecidas descartadas, arrays/strings limitados. Modo manual preservado.
  • Testes: tests/export-routes.test.mjs. 4 novas chaves i18n ×16 (export.saveDocx, twoPager.preview, twoPager.aiFilling, twoPager.aiFilled).

Novo: server/lib/docx.mjs; server/lib/routes/export.mjs.

[1.99.0] — 2026-07-05

Página de saúde dos portais (#/portals). O scanner observa um conjunto de empresas em portals.yml; um slug de ATS pode quebrar silenciosamente e aquele empregador some de todos os scans futuros. A nova página Portals lista cada empresa observada e, ao clicar Check portal health, sonda cada careers_url através do safeGet com DNS fixado (à prova de SSRF) e sinaliza as mortas (um 404 = descartada em silêncio) — somente leitura. Também reforça o relator de bugs da v1.98.0 após a revisão: o buffer de erros agora captura falhas de rede do fetch, e o limpador oculta chaves de provedor sem rótulo.

Novo: server/lib/routes/portals.mjs; public/js/views/portals.js.

[1.98.0] — 2026-07-05

Relator de bugs integrado (paridade com o web web-v0.2.0 do projeto pai). Um botão 🐞 Report a bug na gaveta de notificações reúne um instantâneo de diagnóstico com piso de privacidade — versões, sua tela, navegador, um resumo de verificações do /api/health e os últimos 20 erros de um novo buffer circular do cliente — mais uma impressão digital de deduplicação determinística (co-web-<base36>), permite revisar o Markdown exato e então abre uma issue do GitHub pré-preenchida. Nada é enviado automaticamente; nunca leva seu CV, perfil, respostas, URLs de vagas ou chaves. Novas libs logbuf.js + bug-report.js; 11 chaves i18n ×16; tests/bug-report.test.mjs.

Novo: public/js/lib/logbuf.js; public/js/lib/bug-report.js.

[1.97.1] — 2026-07-05

Endurecimento guiado por revisão e paridade de documentação (continuação da v1.97.0). Uma varredura dos logs de revisão de IA revelou correções reais:

  • fit-score.js (selo de encaixe ◎ do scanner). O salaryFloor() não promove mais uma taxa inferior à anual a um piso anual falso — “at least 500 EUR/day”, “$80/hr”, “6000 monthly” agora retornam null em vez de um fator eliminatório de 500k/80k. A correspondência de países agora é por palavra inteira (\b…\b), de modo que “Germany” não corresponde mais ao adjetivo “German” (nem “Nigeria” dentro de “Nigerian”) nem dispara uma falsa violação de indispensável-em-outro-lugar. +3 testes em tests/fit-score.test.mjs.
  • Paridade de documentação. Cada README localizado agora anuncia 16 idiomas de forma consistente — a contagem/lista da linha de Ajuda (×13) e a prosa da seção de Localização mais a nota “adicione a chave a todos os N arquivos” (×8) ainda estavam nas contagens anteriores à v1.85 (8/9). A contagem de adaptadores da ajuda integrada §17 é corrigida para 46 adaptadores — 41 em inglês + 5 em russo em todos os 16 pacotes.

Nenhuma mudança de comportamento além da heurística do selo de encaixe; nenhuma nova rota, chave ou adição de i18n.

[1.97.0] — 2026-07-05

Fonte de scanner Dassault Systèmes + uma varredura de qualidade em três frentes.

  • Nova fonte de escaneamento — Dassault Systèmes (paridade com o career-ops principal, #1498). server/lib/sources/dassault.mjs + server/lib/portals/adapters/dassault.mjs espelham o provedor de “busca por cartões” Exalead de custo zero em tokens do projeto principal (o feed público por trás de 3ds.com/careers/jobs). É um único endpoint global, então é selecionado por provedor (provider: dassault) ou detectado automaticamente a partir de um host 3ds.com, com o host fixado contra SSRF em www.3ds.com via redirect:'error'. O XML é analisado sem DOM (mapas <Meta> por <Hit>), a cidade/país são extraídas da string de categoria localizada, e as vagas só são mantidas quando sua URL pública está em *.3ds.com. O registro agora traz 46 adaptadores (41 EN + 5 RU); a contagem de ALL_ADAPTERS, as asserções de id ordenado e do conjunto EN de /api/scan/sources passam de 40 → 41. Suíte tests/sources-dassault.test.mjs (10 casos).
  • Correções de robustez portadas do projeto principal. O parser do Avature agora tolera duas variantes de marcação de tenant em produção (article--result com um sufixo de índice de posição + uma âncora de título de JobDetail sem classe, #1541); o Get on Board protege contra um published_at 0/negativo (nada mais de datas espúrias de 1970); o SuccessFactors limita a última página para que ela não ultrapasse MAX_JOBS (#1528).
  • Correções de auditoria do servidor. O safe-fetch não trava mais diante de uma resposta acima do limite — o caminho de limite de tamanho agora resolve a promessa diretamente em vez de esperar por um evento 'end' que um stream destruído nunca emite (corrige as buscas de páginas grandes em /api/pipeline/preview + auto-pipeline). O registro de atividade SSE stream.* voltou a ser alcançável (a verificação de /api/stream/ foi movida acima da guarda geral de “pular GET”).
  • Correções de auditoria da SPA. O alternador de abas de #/stats protege contra uma corrida de renderização assíncrona — o resultado de uma aba lenta não pode mais sobrescrever uma aba mais nova para a qual o usuário já alternou. As confirmações de exclusão do mock interview e do networking agora passam um título + corpo adequados (nada mais de diálogo com corpo vazio).
  • Correções de tradução. Valores de dicionário sem tradução corrigidos — ucraniano config.modes* (Adaptive Framing / Exit Narrative / Location Policy), russo eval.jdLbl (“Job Description”), italiano dash.quick.contactoSub (“referral” → “segnalazione”) — além da localização do texto fixo inglês **16 locales** nos CHANGELOGs de ru/uk/ja/ko/zh-CN/zh-TW.

Novo: server/lib/sources/dassault.mjs; server/lib/portals/adapters/dassault.mjs.

[1.96.0] — 2026-07-04

Orientação de carreira (Epic 27). Uma nova página #/orientation responde à pergunta “quais direções realmente combinam comigo?” — a leitura que você teria de um teste vocacional, mas inferida a partir do seu próprio CV e perfil em vez de um questionário. Clique em Gerar perfil e o modelo devolve seus vetores de carreira com melhor ajuste (quais dos oito arquétipos — Funcionalista, Administrador, Comunicador, Especialista, Analista, Inovador, Gestor, Empreendedor — combinam, com evidências), uma inclinação de tipo profissional, funções recomendadas, pontos fortes profissionais ligados ao seu CV, tendências de estilo de trabalho e recomendações de desenvolvimento. É uma reflexão de IA sobre como o seu CV é lido — não um teste psicométrico: nunca inventa conquistas nem informa pontuações numéricas como se fossem medidas. Exporte-o para Markdown ou PDF; nada é gravado no disco.

  • Nova rota server/lib/routes/orientation.mjs (24.º módulo de rotas) — POST /api/orientation/generate constrói o prompt do perfil a partir de CV+perfil+two-pager+memória via a cascata compartilhada de provedores, com um fallback manual de copiar e colar e sem escrita de arquivos.
  • Reutiliza report-export.js para Markdown/PDF/cópia, dentro do grupo de navegação Desenvolvimento.
  • Testes: tests/orientation-routes.test.mjs (enquadramento de reflexão / sem pontuações fabricadas, modo manual semeado com CV/perfil). 7 novas chaves i18n ×16 idiomas, Ajuda §28 ×16.

Novo: #/orientation; server/lib/routes/orientation.mjs.

[1.95.0] — 2026-07-04

Plano de carreira (Epic 26). Uma nova página #/career-plan transforma o seu CV e o seu perfil em um plano de desenvolvimento concreto e personalizado. Escolha um horizonte (6/12/24 meses) e um foco opcional, e o modelo — lendo o seu CV, o seu perfil, o seu two-pager e a sua nota de memória — redige um retrato do ponto de partida, uma SWOT de forças/crescimento, metas como SMART / OKR / WOOP, trajetórias alternativas, um plano de competências técnicas e comportamentais, um roteiro mês a mês, métodos de acompanhamento do progresso, armadilhas e alavancas de apoio. Planeja adiante a partir do que os seus materiais realmente mostram e nunca inventa fatos sobre o seu histórico. Edite-o em linha, Salve-o na camada de usuário (config/career-plan.md) e exporte-o para Markdown ou PDF.

  • Nova rota server/lib/routes/career-plan.mjs (23.º módulo de rotas) — GET/PUT /api/career-plan (escreve config/career-plan.md) + POST /api/career-plan/generate (cascata compartilhada de provedores, modo manual como fallback, sem fabricação). PATHS.careerPlan.
  • Reutiliza o helper compartilhado report-export.js (v1.94.0) para Markdown/PDF/cópia, e um novo grupo de navegação Crescimento.
  • Testes: tests/career-plan-routes.test.mjs (limitação, ida e volta GET/PUT, prompt semeado com CV/perfil de acordo com o horizonte). 20 novas chaves i18n nos 16 locales, Ajuda §27 nos 16.

Novo: #/career-plan; server/lib/routes/career-plan.mjs; PATHS.careerPlan.

[1.94.0] — 2026-07-04

Estatísticas, reformuladas (Epic 25). A página #/stats agora é uma seção de Estatísticas com três abas, com gráficos reais e muito mais dados. Uma nova aba de Relatório de mercado pede ao modelo uma análise salarial e do mercado de trabalho dos seus cargos-alvo na região e na moeda que você escolher — sumário executivo, salário por nível com percentis P10/P25/P75/P90, principais empregadores, uma tabela de competências em demanda, frequência de benefícios, a divisão presencial/híbrido/remoto, tendências de 12–24 meses e orientação de negociação. Cada número é rotulado como uma estimativa direcional a partir do conhecimento do modelo, nunca apresentado como dados extraídos. Uma nova aba de Meu pipeline plota o seu próprio tracker: distribuição de pontuações, funil de status, principais empresas e cargos, candidaturas ao longo do tempo e taxas de conversão. A visão original de cargo-alvo (vagas/salário por país + tendência de snapshots salvos) passa para uma terceira aba, agora com um seletor de moeda e uma visão geral de publicações por cargo.

  • Exporte qualquer relatório para Markdown ou PDF, ou copie-o — via o helper compartilhado report-export.js (download de blob Markdown; PDF através do runner de PDF em linha existente).
  • Nova rota server/lib/routes/market.mjs (22.º módulo de rotas) — POST /api/stats/market constrói um prompt de análise de mercado a partir do seu CV/perfil (de modo que conhece os seus cargos-alvo), da região e da moeda, executa-o pela cascata compartilhada de provedores e recorre a um prompt para copiar e colar quando não há chave. Sem escritas em disco.
  • Testes: tests/market-routes.test.mjs (limitação de região/moeda, prompt com rótulo de honestidade, modo manual semeado com CV/perfil). 36 novas chaves i18n nos 16 locales, Ajuda §26 nos 16.

Novo: #/stats reformulada em abas; server/lib/routes/market.mjs; public/js/lib/report-export.js.

[1.93.0] — 2026-07-04

Camada de memória (Epic 24). Uma nova página #/memory guarda uma nota curta e editável de “lembre-se disto sobre mim” que o assistente mantém em mente em cada tarefa:

  • Uma nota, em todo lugar — como ela é embutida em bundleProjectContext, a nota alcança automaticamente cada requisição de IA (avaliar, mock interview, networking, CV Studio) em todos os provedores. Escreva-a uma vez; ela orienta tudo.
  • Orientação, não fatos — captura suas preferências e como você gosta de trabalhar (tom, formato, deal-breakers, cadência), nunca novas afirmações factuais sobre a sua experiência — essas continuam vivendo apenas no seu CV, perfil e two-pager. Salva na camada do usuário em config/memory.md, nunca sobrescrita por atualizações.
  • Sugerir a partir dos seus dados — POST /api/memory/suggest garimpa o seu próprio tracker de candidaturas em busca de padrões de comportamento e rascunha tópicos para você revisar e editar. Ele lê o seu tracker; nunca inventa fatos, e não faz nenhuma chamada ao vivo.

Novo: server/lib/routes/memory.mjs (21.º módulo de rotas — GET/PUT /api/memory + POST /api/memory/suggest), public/js/views/memory.js, PATHS.memory, e um bloco config/memory.md adicionado a bundleProjectContext. 11 novas chaves i18n nos 16 locales. Testes: tests/memory-routes.test.mjs.

[1.92.0] — 2026-07-04

CV Studio (Epic 21). Uma nova página #/cv-studio dá ao seu CV três ferramentas honestas e majoritariamente locais:

  • Diagnóstico de currículo — uma pontuação determinística de 0–100 com explicações por verificação (impacto quantificado, verbos fracos, jargões, tamanho, seções essenciais, informações de contato). Puramente no lado do cliente (window.CvDiagnostics) — sem LLM, nada inventado, cada achado explicado para que você decida o que mudar.
  • Máscara de privacidade — oculta dados pessoais (e-mail, telefone, links/handles, endereço e, opcionalmente, seu nome → iniciais) antes de compartilhar seu CV como amostra ou captura de tela. Roda inteiramente no navegador (window.CvPrivacy); relata exatamente o que ocultou e nunca armazena o original.
  • Torne-o humano / correspondência de voz — cole uma linha ou parágrafo rígido e reescreva-o na sua voz, ancorado no servidor em voice-dna.md e writing-samples/. Barreira rígida: pode reordenar, enxugar e revocalizar, mas nunca introduz um fato, uma métrica ou uma conquista que não esteja já no texto. Roda ao vivo através da cascata compartilhada de provedores, ou devolve um prompt para copiar e colar sem chave.

Novo: server/lib/routes/cv-studio.mjs (20.º módulo de rotas — POST /api/cv-studio/humanize), public/js/views/cv-studio.js, public/js/lib/cv-diagnostics.js, public/js/lib/cv-privacy.js, PATHS.voiceDna + PATHS.writingSamplesDir. 29 novas chaves i18n nos 16 locales. Testes: tests/cv-diagnostics.test.mjs, tests/cv-studio-routes.test.mjs. (A galeria de modelos, a exportação para Word e o arquivo de PDF da vaga ficam como trabalho de acompanhamento do CV Studio.)

[1.91.0] — 2026-07-04

Networking e pesquisa profunda de empresas (Epic 16). Uma nova página #/networking transforma uma empresa em um plano acionável para conseguir uma entrevista, ancorado no seu CV, perfil e two-pager:

  • Dossiê da empresa — um resumo enxuto do que a empresa faz, sinais recentes dignos de citação e ganchos de “por que eu encaixo” extraídos da sua trajetória real.
  • Quem contatar — 3–5 personas-alvo (hiring manager, recrutador interno, um IC sênior da equipe, um contato caloroso/de ex-alunos) com uma string de busca do LinkedIn concreta para encontrar cada um. Nunca inventa nomes reais.
  • A via de apresentação mais calorosa — a rota calorosa mais realista para a sua trajetória (empregador/escola/comunidade em comum, um caminho de segundo grau ou uma mensagem direta a frio de alto sinal) e por quê.
  • Rascunhos de contato — mensagens curtas e específicas para as principais personas, ancoradas nos seus pontos de prova reais.
  • Ao vivo ou manual — roda ao vivo através da cascata compartilhada de provedores com qualquer chave, ou devolve um prompt pronto para copiar e colar (fallback honesto, nada inventado). Salvar plano persiste um plano finalizado na camada do usuário (networking/net-{company}-{role}-{date}.md); a página lista, abre e exclui os planos salvos.

Novo: server/lib/routes/networking.mjs (19.º módulo de rotas), public/js/views/networking.js, PATHS.networkingDir. Reutiliza a cascata server/lib/llm-dispatch.mjs da v1.90.0. 24 novas chaves i18n nos 16 locales. Testes: tests/networking-routes.test.mjs.

[1.90.0] — 2026-07-04

Mock Interview 2.0 (Epic 15). Uma nova página #/mock-interview transforma seu CV, perfil, two-pager e banco de histórias em um ensaio de entrevista turno a turno:

  • Prática conversacional — defina um cargo-alvo (+ empresa / JD opcionais) e o entrevistador abre com uma pergunta focada. Cada resposta que você envia recebe uma réplica estruturada: Feedback (pontos fortes + a lacuna STAR+R), uma Pontuação (N/5) e uma Próxima pergunta que sonda a parte mais fraca da sua última resposta. Ancorada no servidor aos seus materiais reais — nunca inventa experiência que você não tem.
  • Consciente do banco de histórias — interview-prep/story-bank.md é embutido no prompt (mesmo nível de confiança que cv.md), de modo que o feedback pode apontá-lo para as suas próprias melhores histórias.
  • Ao vivo ou manual — com uma chave de provedor, o turno roda ao vivo pela cascata compartilhada de provedores (Anthropic → Gemini → OpenAI → Qwen → OpenRouter → GitHub Models); sem chave você obtém um prompt pronto para copiar e colar (fallback honesto, sem respostas inventadas).
  • Sessões salvas — clique em Save transcript para persistir uma entrevista concluída na camada de usuário (interview-prep/mock-{company}-{role}-{date}.md); a página lista, abre e exclui as sessões salvas.

Novo: server/lib/routes/interview.mjs (18.º módulo de rotas), public/js/views/mock-interview.js, server/lib/llm-dispatch.mjs (cascata compartilhada de provedores), PATHS.storyBank, bundleProjectContext({ extraFiles }). 30 novas chaves i18n nos 16 locales. Testes: tests/interview-routes.test.mjs.

[1.89.0] — 2026-07-04

Ajuste candidato-mercado — o two-pager (Epic 14). Uma nova página #/two-pager permite capturar o que você realmente quer da sua próxima vaga, inspirada no “Mnookin two-pager” de Never Search Alone:

  • Construtor guiado — uma narrativa em primeira pessoa “Quem eu sou”, uma nota “Ambiente-alvo” e cinco editores de listas de chips: loves, must-haves, hates, deal-breakers e non-negotiables. Salvo na camada de usuário do projeto pai (config/two-pager.yml) via PUT /api/two-pager — nunca sobrescrito por atualizações do sistema.
  • Assistente de preenchimento com IA (POST /api/two-pager/draft) — monta um prompt Mnookin pronto para rodar com seu CV + perfil embutidos, para você executar em qualquer LLM e colar de volta. Ele só usa seus próprios materiais; nada é inventado.
  • Selo de encaixe-com-o-que-você-quer — cada vaga em #/scan agora exibe uma pontuação de encaixe ◎ N (no lado do cliente, via window.FitScore) que confronta o tipo de trabalho, país, piso salarial e realocação da vaga com o seu two-pager. Honesto por design: quando uma vaga não fornece sinal comparável, nenhum selo é exibido (nunca um número inventado). Violações de deal-breakers pesam mais do que desagrados leves.
  • Alimenta cada avaliação — o two-pager salvo é embutido em bundleProjectContext, de modo que todas as avaliações LLM subsequentes combinam suas preferências declaradas com o encaixe CV-vs-vaga.

Novo: server/lib/routes/two-pager.mjs, public/js/views/two-pager.js, public/js/lib/fit-score.js, PATHS.twoPager. 27 novas chaves i18n em todos os 16 locales. Testes: tests/two-pager-routes.test.mjs, tests/fit-score.test.mjs.

[1.88.0] — 2026-07-04

Polimento do issue #29 — lacunas de i18n no Escaneamento + higiene da API.

  • Localizadas as últimas strings de Escaneamento codificadas (roadmap v1.69.4): as pílulas de resumo por fonte (N novas / M correspondentes), os avisos N novas vagas e o selo reloc agora fluem por t() — 4 novas chaves (scan.pillNew, scan.pillMatching, scan.newOffers, scan.relocBadge) em todos os 16 locales. Usuários que não falam inglês não veem mais texto solto em inglês no fluxo principal de escaneamento.
  • Desabilitado o cabeçalho X-Powered-By (roadmap v1.69.5): app.disable('x-powered-by') em createApp() — o servidor não anuncia mais o Express. (O restante desse épico já havia sido entregue: parentVersion remove seu comentário de release-please, o alternador de tema em modo claro, o fechamento de modais ao mudar de rota e a localização de “Score” (rep.score) nos Relatórios.)

Testes: tests/scan-i18n-gaps.test.mjs + uma asserção de ausência de X-Powered-By em tests/security-headers.test.mjs.

[1.87.0] — 2026-07-04

4 novos provedores de escaneamento sem autenticação (paridade com o career-ops pai v1.16.0). O registro do scanner cresce de 41 → 45 adaptadores (40 EN + 5 RU) — todos públicos, sem autenticação, com host fixado, redirect:'error' (seguro contra SSRF), cada um com um teste isolado para CI:

  • Get on Board (getonbrd) — JSON:API público de todo o portal (tecnologia LATAM/remoto), selecionado por provedor, paginado. server/lib/sources/getonbrd.mjs.
  • Amazon (amazon) — JSON de busca público do amazon.jobs, detectado por host ou provider: amazon, paginado por offset. server/lib/sources/amazon.mjs.
  • Avature (avature) — ATS *.avature.net por inquilino, analisado a partir de HTML, detectado por host ou provider: avature. server/lib/sources/avature.mjs.
  • SAP SuccessFactors (successfactors) — lista de blocos RMK por inquilino (*.successfactors.eu/.com, jobs2web.com), analisada a partir de HTML. server/lib/sources/successfactors.mjs.

Cada um inclui um sources/<slug>.mjs (com meta autodescoberto → menu suspenso #/scan) e um portals/adapters/<slug>.mjs em ALL_ADAPTERS (a regra dos dois registros) + tests/sources-<slug>.test.mjs. A contagem de ALL_ADAPTERS e as asserções de id ordenado e do conjunto EN de /api/scan/sources subiram de 36→40; GET /api/scan/sources agora lista 45.

[1.86.0] — 2026-07-03

Estatísticas por cargos-alvo (#/stats) — estatísticas de vagas e salários de mercado para OS SEUS cargos-alvo. Uma nova página de Análise lê os seus cargos-alvo do perfil (config/profile.yml → não codificados) e as vagas do último escaneamento, e então mostra, por cargo e país:

  • Vagas por país e salário mediano por país (USD) — agregados no cliente (public/js/lib/role-stats.js, reutilizando window.Countries) a partir dos dados esparsos que os scanners já coletam. Salários em qualquer moeda são normalizados para USD por meio de uma tabela FX explicitamente aproximada, com uma ressalva sobre o tamanho da amostra — nunca fabricados.
  • Filtros de cargo e país e gráficos de barras e de tendência com SVG inline feitos à mão (sem novas dependências, seguros para CSP — apenas addEventListener).
  • Salvar instantâneo (POST /api/stats/snapshot) persiste o agregado atual em data/role-stats.jsonl; o gráfico de tendência (GET /api/stats/trend) acompanha a contagem de vagas ao longo do tempo — a visão de “dinâmica”. Híbrido honesto: os instantâneos vêm de dados de escaneamento locais, atualizados sob demanda.
  • Totalmente localizado em todos os 16 locales (26 novas chaves i18n).

Novo: server/lib/routes/stats.mjs (16.º módulo de rotas), public/js/lib/role-stats.js, public/js/views/stats.js, PATHS.roleStats; testes role-stats.test.mjs (7) + stats-routes.test.mjs (5).

[1.85.0] — 2026-07-03

Locales alemão, italiano e turco (paridade de locales com career-ops pai v1.16.0). A interface agora é distribuída em 16 idiomas — de 🇩🇪, it 🇮🇹 e tr 🇹🇷 juntam-se aos 13 existentes.

  • Tradução completa da interface — todas as 730 chaves i18n traduzidas em public/js/lib/locales/i18n-dict.{de,it,tr}.js; o seletor de idioma lista Deutsch / Italiano / Türkçe e a detecção automática do idioma do navegador reconhece de/it/tr (public/js/lib/i18n.js).
  • Guia de ajuda integrado — docs/help/{de,it,tr}.md traduzidos (estrutura completa de 19 H2 / 75 H3), servidos por GET /api/help/:lang.
  • Documentação — README.{de,it,tr}.md e CHANGELOG.{de,it,tr}.md adicionados; a verificação de paridade de locales do CHANGELOG agora cobre 15 locales não EN.
  • Andaime de prompts — server/lib/prompts.mjs (LOCALE_NAMES + SCAFFOLD_STRINGS) localizado para os três novos locales, de modo que a saída do LLM segue o idioma da interface.

Todas as verificações de paridade (i18n-locale-files, i18n-coverage, check-changelog-parity, lang-switcher-rtl) estendidas ao conjunto de 16 locales.

[1.84.0] — 2026-06-30

Cooldown de recandidata­tura + compensação em pipeline.md (paridade com career-ops pai v1.15.0). Duas melhorias no scanner:

  • Cooldown de recandidatura (#1201): o scan EN agora ignora vagas em empresas às quais você se candidatou recentemente, para que os resultados fiquem focados em NOVAS vagas. Configure janelas por empresa em config/profile.yml sob re_apply_windows: (last_apply_date, same_role_days, applied_to: [roles], cross_role_bucket opcional); a correspondência de empresa é insensível a pontuação e baseada em limites de palavra (server/lib/cooldown.mjs). Desativado quando a chave está ausente; o log de varredura exibe Cooldown skipped: N.
  • Compensação em pipeline.md (#1017): as vagas varridas agora persistem seu salário como coluna opcional ao final (url | <salary>) em data/pipeline.md. A URL continua sendo a chave de deduplicação (a coluna | comp é removida na leitura), a célula é sanitizada (sem injeção de linhas/colunas, fórmulas iniciais neutralizadas) e pipelines com apenas URL permanecem retrocompatíveis.

Inclui tests/cooldown.test.mjs + testes de compensação de pipeline. O número de fontes permanece em 41 (ambas são melhorias de lógica de varredura, não novos boards).

[1.83.0] — 2026-06-30

Detector de repostagens / vagas fantasma (paridade com career-ops pai v1.15.0). Um novo painel 🔁 Repostagens / vagas fantasma em #/scan sinaliza clusters empresa+vaga que foram relançados sob URLs diferentes em uma janela móvel de 90 dias — sinal de pipelines obsoletas e vagas fantasma. Sustentado por um comparador difuso de títulos de vaga (server/lib/role-matcher.mjs) e um detector somente leitura (server/lib/detect-reposts.mjs) sobre data/scan-history.tsv, exposto via GET /api/scan/reposts. Além disso: parentVersion em /api/health agora reporta apenas o semver (o comentário # x-release-please-version do release-please é removido). Inclui tests/detect-reposts.test.mjs. O número de fontes permanece em 41 — reposts é uma funcionalidade de análise, não um novo board.

[1.82.0] — 2026-06-30

Fonte de varredura NoDesk (paridade com career-ops v1.15.0). O feed RSS de vagas remotas do NoDesk agora é uma fonte de primeira classe — adicione uma entrada provider: nodesk e ela aparece no menu Source de #/scan (41 adaptadores no total: 36 EN + 5 RU). Host fixado em nodesk.co com redirect:'error' (anti-SSRF); títulos divididos por Role at Company (NoDesk não tem tag de localização, então a localização fica vazia); todas as linhas são remotas. Inclui uma suite CI isolada tests/sources-nodesk.test.mjs; suite de testes unitários completa no verde com 1523.

[1.81.0] — 2026-06-29

Paridade com o career-ops pai — 13 novas fontes de varredura de bolsas de emprego. Porta o último lote de provedores do main do Fighter90/career-ops para o scanner em processo. APIs públicas universais (selecionadas por provedor): Arbeitnow, Himalayas, Jobicy, Landing.jobs, 4 Day Week, The Muse, The Hub, Jobspresso (RSS) e Hacker News “Who is hiring?” (Algolia em dois passos). Bolsas polonesas (detectadas por host ou provider:): JustJoin.it e NoFluffJobs (busca POST). ATS por tenant (autodetectados de careers_url): Pinpoint (<slug>.pinpointhq.com/postings.json) e Rippling (ats.rippling.com/<slug> → api.rippling.com). Cada fonte é fixada por host com redirect:'error' (anti-SSRF) e selecionável no menu Source de #/scan — o registro conta agora com 40 adaptadores de scanner (35 EN + 5 RU). Adiciona 13 suítes de testes CI isoladas por fonte; suite de testes unitários completa no verde com 1513 testes.

[1.80.0] — 2026-06-28

Cinco melhorias de varredura (ideias do job-crawler, reimplementadas). (1) Fonte Teamtailor — sites <slug>.teamtailor.com via o feed público /jobs.rss, autodetectado de careers_url (host fixado + redirect:'error'); o registro agora traz 27 adaptadores. (2) Quarentena de fontes — uma fonte com 404/410 permanente é gravada em data/scan-quarantine.json e ignorada em varreduras posteriores (autocorrigível: nova tentativa após 14 dias). (3) Máx. por fonte — campo opcional em #/scan que limita vagas por board (∞ por padrão). (4) Publicado em — filtro de idade no cliente (24h / 7d / 30d). (5) Buscas salvas + ★ favoritos — nomeie e reutilize conjuntos de filtros e marque vagas, em localStorage com validação defensiva (cache corrompido reinicia limpo); o cache de resultados é reiniciado antes de cada varredura e preenchido ao vivo.

[1.79.0] — 2026-06-28

Fonte de varredura WeWorkRemotely (paridade com career-ops v1.14.0). O feed RSS de vagas remotas do We Work Remotely agora é uma fonte de primeira classe — adicione uma entrada provider: weworkremotely e ela aparece no seletor Source de #/scan (26 adaptadores no total). Host fixado em weworkremotely.com com redirect:'error' (anti-SSRF); títulos divididos por Company: Role. Além disso: as palavras-chave de title_filter agora são aparadas antes da verificação de comprimento (parent #1261).

[1.78.2] — 2026-06-27

Reforço de i18n e UX (correções após v1.78.1). O nome acessível do logo agora é localizado nos 13 idiomas (nav.logoHome). Enter na busca global estando já em #/scan força um re-render para não perder o termo pré-preenchido (guard de mesma rota). health.title agora é traduzido para polonês (Kondycja) e dinamarquês (Systemtilstand) — antes ficava em inglês. Testes 1235 → 1238.

[1.78.1] — 2026-06-27

Correções de UX no Scan. A tabela de resultados de #/scan agora atualiza automaticamente durante a varredura e mais uma vez ao terminar, sem recarregar. A busca global da barra superior mostra a dica Enter e, em uma consulta que não é URL, vai para #/scan com o campo pré-preenchido (antes #/tracker). O logo agora leva ao painel (início).

[1.78.0] — 2026-06-27

Filtro geográfico na página Scan — filtre resultados por país, com bandeiras. Um novo seletor País em #/scan lista cada país detectado nos seus resultados (emoji de bandeira + contagem), para manter só vagas ligadas a um país — junto ao filtro Remote/Hybrid/Onsite, permitindo buscar trabalho ligado a um país e remoto. Suportado por um novo helper countries.js que mapeia a localização em texto livre (nomes de país, aliases e ~100 cidades-chave) para um país ISO + bandeira; a detecção é conservadora e nunca adivinha.

[1.77.0] — 2026-06-27

Dinamarquês (Dansk) adicionado como o 13.º idioma da interface. Tradução completa da UI, do guia de ajuda integrado (19 H2 / 75 H3), README e CHANGELOG. O dinamarquês entra no seletor de idiomas com bandeiras; a maquinaria i18n (montador, auditoria, verificações de paridade, snapshot) agora abrange 13 locales.

[1.76.0] — 2026-06-26

Paridade com career-ops v1.13.0 — seis novas fontes, reforço do scanner e tabela de resultados sem limite.

Adicionado

  • Seis fontes ATS por inquilino — BambooHR, Breezy HR, Comeet, Personio, Recruitee, SolidJobs. Autodetectadas pelo host de careers_url (Comeet exige o api: completo); cada host é fixado com regex ancorado + redirect:'error' (anti-SSRF). Selecionáveis no dropdown Source de #/scan — o registro agora traz 25 adaptadores (20 EN + 5 RU). Adiciona fetchText para o feed XML do Personio.
  • trust_filter — pontuação de confiança opcional (0–100, nível high/medium/low, flags), apenas anota. Linhas abaixo de high recebem um selo ⚠ neutro em #/scan; nada é descartado.
  • Arbeitsagentur remoteMatch + remoteMaxPages — detecção de remoto por config: title, filter (homeoffice=nv_true no servidor + paginação) ou off.

Alterado

  • Sem limite de resultados. MAX_STORED_RESULTS (2000) foi removido — todas as correspondências são armazenadas e a tabela #/scan as pagina (200/pág.).
  • Robustez do filtro de título — siglas curtas (COO, SDR…) casam por limites de palavra; config title_filter malformada não quebra mais o scan. Ambos os scanners.

Testes

  • +32 casos (1190 → 1222): sources-ats-providers, title-filter, arbeitsagentur-remote, trust-validator e um guard scan-result-cap reescrito («sem limite»).

[1.75.2] — 2026-06-19

docs: paridade documental completa para os agregadores do scanner da v1.75.0 em todos os 12 idiomas. Sem mudança de código — alinha a documentação voltada ao usuário com as sete fontes que chegaram na v1.75.0:

  • Guia de ajuda (12 idiomas). §5 ganha um bloco content_filter (gating por palavras-chave de descrição/trecho, irmão de location_filter) e uma nota sobre agregadores; §7 lista as sete novas fontes na varredura de um clique e na enumeração completa do menu suspenso Source; a contagem de adaptadores do §17 é corrigida do obsoleto “11 adapters” para “19 adapters — 14 English + 5 Russian”. Nenhum cabeçalho ##/### foi adicionado, então a estrutura fechada de 19 H2 / 75 H3 permanece inalterada.
  • README (9 idiomas completos). Nova bala “Aggregator boards (v1.75.0)” sob as fontes de varredura, mais o selo de versão atualizado para v1.75.2. (Os README abreviados pl/uk/ar não têm lista por fonte e ficam intencionalmente intocados ali.)
  • Documentação de referência. docs/portals-examples.md ganha uma seção “Aggregator boards” de copiar e colar com blocos de configuração provider: / <provider>: precisos para as sete; docs/PROJECT.md atualizado para 19 adapters; docs/sdd/CONVENTIONS.md documenta a distinção dos dois registros (sources/registry.mjs para o menu suspenso versus portals/registry.mjs para o fetching), a seleção de agregador baseada em provider: encadeada como opts.company, o sanitizador de escrita de varredura (scan-sanitize.mjs) e a contagem de testes da v1.75.1 (1190).
  • QA. Adicionado qa/QA-REGRESSION-PROMPT-v1.75.2-FULL.md — o driver de portão de lançamento de superfície completa, renovado para o ciclo de agregadores de varredura da v1.75.x.

[1.75.1] — 2026-06-19

fix(scan): polimento de robustez nas fontes baseadas em configuração da v1.75.0. Três pequenas correções de endurecimento vindas da revisão pós-lançamento (sem mudança de comportamento para uma varredura saudável):

  • Pausas de paginação cientes de abort. As pausas de cortesia entre páginas do Glints (300 ms) e do Jobstreet/SEEK (200 ms) agora se resolvem imediatamente quando o AbortSignal da varredura dispara, por meio de um novo helper delay(ms, signal) em server/lib/http-json.mjs, de modo que um cliente desconectado não consiga manter uma varredura paginada aberta por uma pausa extra.
  • Erro descritivo para respostas não JSON. O fetchJson agora envolve um corpo 2xx não JSON (p. ex. uma página HTML de manutenção servida com status 200) como non-JSON 2xx response from <url> em vez de expor um SyntaxError cru, de modo que o log de erros por fonte do scanner nomeie o endpoint que se comporta mal.
  • Normalização de escrita de varredura mais forte. O normalizeScanScalar agora colapsa a tabulação vertical, o avanço de página e os separadores Unicode de linha/parágrafo (\v \f U+2028 U+2029) além de \r \n \t — um superconjunto estrito, de modo que nenhum separador de registro/linha que uma planilha ou um visualizador possa respeitar sobreviva em scan-history.tsv.

[1.75.0] — 2026-06-19

feat(scan): porta a paridade com o career-ops pai v1.12.0 — sete novas fontes de vagas, filtragem de conteúdo e correções de segurança/qualidade. A web-ui executa seus próprios scanners em processo (não delega ao scan.mjs do pai), portanto as mudanças de provedor e de varredura da v1.12.0 do pai não se propagam automaticamente — esta versão reimplementa as aplicáveis conforme o contrato de adaptadores da web-ui.

  • Sete novas fontes de scanner. Três agregadores remotos de alcance global — RemoteOK, Remotive, Working Nomads — encaixam no padrão autodescoberto server/lib/sources/*.mjs (selecionados com provider: remoteok / remotive / workingnomads). Quatro agregadores regionais orientados por configuração — careers da IBM, Arbeitsagentur (Agência Federal de Emprego alemã), Glints (Sudeste Asiático), Jobstreet / SEEK — leem um bloco de configuração <provider>: por entrada; o en-scanner agora encaminha a entrada de empresa resolvida até cada fetcher para que possam lê-la. Todas as sete aparecem automaticamente no menu suspenso de fontes de #/scan.
  • content_filter (pai #974). Bloco opcional de portals.yml (listas de palavras-chave positive / negative) que filtra uma vaga pelo texto de sua descrição/trecho — espelha a semântica de location_filter; vagas sem descrição sempre passam. Integrado em ambos os scanners EN e RU.
  • Endurecimento da escrita de varredura (pai #1098). Os metadados de feeds externos agora são sanitizados antes de aterrissar em data/scan-history.tsv e data/pipeline.md: caracteres de controle são colapsados (uma quebra de linha em empresa/título não pode mais injetar uma linha TSV) e um = + - @ inicial é neutralizado contra injeção de fórmulas de planilha.
  • secondaryLocations do Ashby (pai #1073). A fonte Ashby agora dobra o rótulo de região de cada localização secundária mais addressLocality / addressCountry postal na string de localização (deduplicada), de modo que uma vaga elegível para a UE cujo rótulo principal diga, p. ex., “Canada” apareça para o location_filter.
  • Validação da forma do relatório de avaliação (pai #819). Os provedores em processo de /api/evaluate (Anthropic / OpenAI / Qwen / OpenRouter / GitHub Models) agora marcam um relatório A–G / SCORE_SUMMARY malformado como um array warnings não fatal; o caminho de avaliação do Gemini já herda a proteção do gemini-eval.mjs do pai.
  • docs: Antigravity CLI adicionado às listas de assistentes suportados nos 12 READMEs (mapeia para o provedor Gemini).

Herdado de graça do git pull do pai (a web-ui delega a estes): fallback de fontes CJK para PDF em japonês (#1053), fontes PDF compatíveis com ATS (#1074), proteção CJK para LaTeX (#1054), correções de tracker/merge/followup/dashboard e os modos chineses modes/zh (a web-ui lista os modos dinamicamente).


[1.74.3] — 2026-06-18

docs(parent-source): aponta o repositório pai career-ops para o fork Fighter90/career-ops. A web-ui agora referencia o fork do mantenedor como projeto pai em todos os pontos onde é uma fonte real: o padrão CAREER_OPS_REPO do instalador bin/setup.sh, cada link de git clone / “em cima de” / onboarding nos 12 READMEs, e a documentação dos agentes (CLAUDE.md, AGENTS.md, GEMINI.md, .github/copilot-instructions.md, docs/). O crédito ao autor santifer (e o aviso de UI não oficial) permanece inalterado — apenas as URLs de origem/clonagem mudaram. tests/sh-files.test.mjs agora verifica que o instalador clona o fork.


[1.74.2] — 2026-06-17

fix(health): expor GITHUB_MODELS_API_KEY como uma verificação opcional em #/health e em /api/status/providers. O provedor GitHub Models da v1.74.0 era configurável em #/config, mas não tinha linha na página de Saúde e estava ausente da superfície de provedores keysConfigured. Foi adicionada a verificação opcional (com a mesma redação “set / unset (manual mode)” dos outros cinco provedores de avaliação ao vivo) e github (+ seu GITHUB_MODELS_MODEL) a /api/status/providers, de modo que o roteamento de provedor ativo e a página de Saúde agora refletem os seis. O teste de linha de saúde de tests/api.test.mjs foi estendido para os seis provedores.


[1.74.1] — 2026-06-17

docs + test: seção “Instalar um assistente de IA” do README; cobertura completa de ramificações para o conector Gemini. Foi adicionada uma tabela de instalação/login ao README — links de instalação para Claude Code / Gemini CLI / Codex / Qwen Code / OpenCode / GitHub Copilot CLI + o mapeamento de provedor #/config de cada um + “faça login antes de continuar” (espelha o Início Rápido do career-ops.org/docs; esclarece que a web-ui é a alternativa independente, sem necessidade de CLI). O novo tests/gemini-connector.test.mjs (8 casos) cobre cada ramificação de runGemini — sem chave, sucesso, erro de API, conclusão vazia/bloqueada, corpo malformado, timeout, erro de rede, hasGeminiKey — levando server/lib/gemini.mjs a 100% de instruções. Cobertura geral: 96% linhas / 88% ramificações / 96% funções. Suite 1126 → 1134.


[1.74.0] — 2026-06-17

feat(llm): GitHub Models (Copilot) como o 6.º provedor + alinhamento canônico de 6 assistentes. career-ops.org/docs lista seis assistentes de codificação com IA — Claude Code, Gemini CLI, Codex, Qwen Code, OpenCode, GitHub Copilot CLI. A web-ui agora oferece suporte a todos os seis: cinco mapeiam para provedores ativos existentes (Anthropic / Gemini / OpenAI / Qwen / OpenRouter), e o GitHub Copilot CLI ganha um conector dedicado ao GitHub Models — runGitHubModels (OpenAI-compatible; um PAT do GitHub com o escopo models), configurável em #/config (GITHUB_MODELS_API_KEY + GITHUB_MODELS_MODEL) e selecionável via LLM_PROVIDER=github; 6.º na ordem auto. Os pacotes de ajuda e os READMEs agora listam os seis canônicos (Qwen CLI foi renomeado para Qwen Code; Gemini CLI + GitHub Copilot CLI foram adicionados), e o README inclui uma tabela completa de referência de modos e links de adaptadores de portais para career-ops.org/docs, de modo que cada funcionalidade possa ser rastreada até o projeto pai. tests/llm-provider-context.test.mjs estende a matriz de limite de busca para todos os seis provedores (cv.md + profile.yml embutidos + artefato retornado); novas chaves GITHUB_MODELS_* adicionadas a todos os 12 dicionários de idiomas. Suite 1125 → 1126.


[1.73.0] — 2026-06-17

feat(llm): conector Gemini genérico + contexto de CV/perfil verificado em todos os provedores. Adicionado server/lib/gemini.mjs (runGemini) — um cliente Gemini generateContent sem dependências externas que retorna o mesmo formato {markdown, usage, error} que os clientes compatíveis com Anthropic / OpenAI. Correção: /api/mode/:slug e /api/deep anteriormente roteavam seus prompts pelo gemini-eval.mjs, voltado exclusivamente para ofertas, fazendo com que o Gemini Run live retornasse uma avaliação em vez do artefato solicitado (carta de apresentação, contato, resumo). Agora chamam runGemini com bundleProjectContext, de modo que cv.md + config/profile.yml são embutidos inline para o Gemini exatamente como em qualquer outro provedor — cartas e resumos ficam detalhados e personalizados. O novo tests/llm-provider-context.test.mjs simula o limite HTTP de cada provedor e verifica que os cinco (Anthropic / Gemini / OpenAI / Qwen / OpenRouter) embutem cv.md + profile.yml inline e retornam o artefato (matriz mode + deep + evaluate, 9 casos). /api/evaluate mantém seu gemini-eval.mjs ajustado para ofertas. Suite 1116 → 1125.


[1.72.0] — 2026-06-17

feat(modes): Run live agora retorna o artefato final diretamente (contrato de saída de disparo único). Os templates pai modes/<slug>.md foram escritos para sessões interativas do Claude Code — vários (cover, contacto, …) pausam para fazer perguntas de esclarecimento antes de produzir o resultado, o que fazia o Run live da interface web emitir um questionário em vez do artefato. buildModePrompt agora envolve cada modo em um contrato de saída não interativo: realiza a análise (detalhamento da vaga, notas sobre a empresa, palavras-chave ATS, lacunas perfil↔vaga, escolhas de tom/ângulo) silenciosamente, escolhe padrões sensatos de cv.md / config/profile.yml para tudo o que o template normalmente perguntaria, e gera apenas o artefato final — encerrado com um lembrete por modo «output ONLY {the cover letter / outreach message / …}». Assim, clicar em Run live em #/cover agora retorna a própria carta de apresentação; a mesma correção se aplica a todos os modos genéricos (cover, contacto, interview-prep, project, training, followup, patterns) em todos os 12 idiomas (o artefato é redigido no idioma da interface via diretiva de localidade). Suite 1103 → 1116.


[1.71.2] — 2026-06-17

docs(i18n): publica a revisão de consistência da documentação. O bloco “Translations of this guide” de cada README agora lista todos os 11 idiomas irmãos (anteriormente alguns omitiam English/Français ou se vinculavam a si mesmos), com a linha em branco antes da quebra de seção restaurada. O prompt completo de regressão QA é renomeado para a versão atual, e a documentação (CLAUDE.md, CONVENTIONS, LOCALIZATION, PROJECT-CONTEXT) é sincronizada com a versão atual e a contagem de testes (1103). Sem alterações no código ou comportamento — somente documentação, portanto as traduções de ajuda/UI e todos os recursos de 1.70.0–1.71.1 permanecem inalterados.


[1.71.1] — 2026-06-17

fix(i18n): o guia de ajuda integrado agora está completamente traduzido em todos os 12 idiomas. Adicionados docs/help/{pl,uk,ar}.md (cada um contendo a estrutura validada de 19 H2 / 75 H3) para que #/help sirva um pacote nativo em polonês, ucraniano e árabe em vez de recorrer ao inglês — GET /api/help/{pl,uk,ar} agora retornam sua própria localidade. Integrado em todas as verificações de ajuda (help-ui, help.test, help-ru-config-section, canonical-docs-coverage). Também foram concluídas todas as listas de tradução nos 12 idiomas: o bloco «Translations of this guide» do README (9 READMEs), os cabeçalhos «Translations:» dos CHANGELOGs localizados (8 arquivos) e os contadores de documentação desatualizados foram atualizados. Suite 1100 → 1103.


[1.71.0] — 2026-06-16

feat(cover): gere um PDF de carta de apresentação diretamente em #/cover. O modo cover (adicionado na v1.70.0) produz o texto da carta; o resultado agora oferece um botão Generate PDF que o renderiza por meio do pipeline compartilhado de markdown→PDF inline (POST /api/stream/pdf/inline → generate-pdf.mjs), o mesmo caminho que o interview-prep usa. Agora você pode produzir a carta e gerar um PDF sem sair do SPA.

test/docs: endurecimento da revisão da v1.70.0. Adicionada cobertura CI-isolada para o modo cover (lista de permissões + montagem de prompt), o seletor <select> de bandeiras + RTL árabe (dirFor/<html dir>), top.langLabel em cada locale, o cabeamento do PDF de carta de apresentação, e a diretiva de locale de prompts.mjs + scaffolding para fr/pl/uk/ar. Referências obsoletas «todos os 8» → 12 locales atualizadas em docs/sdd/CONVENTIONS.md e no prompt de regressão QA do projeto completo.


[1.70.0] — 2026-06-16

feat(i18n): três novos idiomas de interface — polonês (pl), ucraniano (uk) e árabe (ar, com suporte completo a RTL) — elevando a SPA para 12 idiomas, correspondendo a todos os idiomas do README do projeto pai career-ops. Cada novo idioma inclui um dicionário completo de 697 chaves (public/js/lib/locales/i18n-dict.{pl,uk,ar}.js), validado pelas suites existentes de paridade / cobertura / sem-vazamento-latino / sem-dados-pessoais. O árabe adiciona suporte genuíno da direita para a esquerda: i18n.js define <html dir="rtl"> para idiomas RTL e um bloco [dir="rtl"] com escopo em app.css espelha o chrome (barra lateral, gaveta de notificações, tabelas e citações markdown, espaçamento inline) — os idiomas LTR permanecem byte a byte inalterados. Nova chave top.langLabel (×12) nomeia o seletor para leitores de tela.

feat(ui): o seletor de idioma <select> com ícone de bandeira substitui a fileira de botões que quebrava linha. Com 12 idiomas, a antiga fileira .lang-btn quebrava para três linhas na barra lateral; um <select> nativo (cada opção prefixada com um emoji de bandeira) escala de forma limpa, é compatível com teclado e leitor de tela por padrão, e permanece seguro com CSP (manipulador de mudança via addEventListener, sem JS inline). As bandeiras degradam para letras de região onde a plataforma não possui glifos de bandeira, portanto o rótulo do idioma é sempre o identificador principal.

feat(cover): porta o modo de carta de apresentação do projeto pai (career-ops v1.10.0 + saudação de v1.11.0) para a SPA. Nova página #/cover no grupo de navegação de Candidatura, construída sobre o executor de modos genérico: descrição da vaga + empresa/cargo + uma saudação opcional → uma carta personalizada gerada a partir de cv.md / modes/_profile.md. Adicionado cover à MODE_ALLOWLIST do servidor e um bloco i18n cover.* (×12 idiomas).

chore(compat): rastreamento do projeto pai career-ops v1.11.0. Verificado que o contrato de leitura/escrita está intacto — data/applications.md continua sendo a fonte da verdade em markdown (o índice de rastreamento SQLite do v1.11.0 é um cache derivado), as colunas do rastreador ainda são mapeadas por cabeçalho. parentVersion agora reporta 1.11.0.

fix(i18n): fecha uma lacuna latente onde o francês (adicionado na v1.61.0) estava ausente de server/lib/prompts.mjs em LOCALE_NAMES e SCAFFOLD_STRINGS — chamadas LLM em francês silenciosamente usavam saída em inglês e scaffolding em inglês. fr/pl/uk/ar estão agora todos conectados ao caminho de locale do prompt.

Acompanhamentos conhecidos: o guia de ajuda integrado (docs/help/) faz fallback para inglês em pl/uk/ar (o chrome da interface em si está totalmente localizado); o onboarding interativo de entrevista do projeto pai, a descoberta reversa de ATS e os novos provedores de scan ainda não estão disponíveis na SPA.



career-ops-ui v1.267.1 · page 5/9 · mirror of the project changelog for cvstart.org