Changelog

GitHub

Hver væsentlig ændring, udgivelse for udgivelse. Samme fil findes i repository'et og er oversat til alle 19 sprog.

[1.251.1] — 2026-10-12

Specialiseringsfilteret matcher nu kun rollens DISTINKTIVE ord — anciennitet og generiske jobsubstantiver matcher ikke længere et opslag alene — og remote-qa adskiller form fra sprog, så et drift aldrig rødmarkerer A–G.

Rettet

  • Specialiseringsfilteret fjerner anciennitet og generiske jobsubstantiver fra sin matcher: «Senior PHP Developer» matchede «Senior Java Developer» via den fælles Senior/Developer. Matcheren beholder kun distinktive tokens (PHP, Go, Platform, SRE, Backend…); en rolle uden distinktive tokens («Software Engineer») falder tilbage på hel-sætningsmatchet. Ordgrænser består: «Go» matcher aldrig «Golang» eller «Google».
  • remote-qa adskiller form fra sprog: A–G-flaget bedømmes kun af blok/SCORE_SUMMARY/looping-koder; et report not in <locale>-drift går til sit eget flag og warnings-kolonne (tabellen får den manglende 4. kolonne; koderne gemmes pr. række).
  • Kortværktøjsbjælken er en ægte 50/50 ved 390 px (58/42-opdelingen efterlod søgningen på 124 px og klippede dens pladsholder), og den døde CSS-regel .job-map-job-select er fjernet.
  • CodeQL 552 — den ubrugte OVERLAYS-variabel i design-qa-testen fjernet.

Noter

  • Miles stadig udskudt af ejeren. ta-sprogedriften forbliver en DOKUMENTERET begrænsning i hermes-backend (2–26 % prosa på tværs af kørsler; A–G holder): remote-qa rapporterer den som et forventet fund. Den generiske token-liste er med vilje minimal — at udvide den koster én linje pr. sprog.

[1.251.0] — 2026-10-12

Kortets select filtrerer nu efter SPECIALISERING fra indstillingerne (config/profile.yml → target_roles.primary): vælg «Product Manager» eller «Backend Engineer (Go / PHP)», og kortet beholder kun opslagene, hvis titel bærer rollens egne ord. V1.250.0’s jobliste-locator er fjernet — det var det forkerte værktøj (ejerkorrektion).

Tilføjet

  • Specialiseringsfilter: select’en viser specialiseringerne fra indstillingerne (target_roles.primary); valg beholder kun opslagene, hvis titel bærer en af rollens distingverende tokens (ordgrænser, uden store/små bogstaver — «Go» matcher aldrig «Google»); Reset gendanner alle.
  • V1.250.0’s jobliste-locator er fjernet — erstatningen: specialiseringsfilter, ikke jobliste (ejerkorrektion).

Ændret

  • Two mobile-map height specs: the floor moves 600 -> 540 px (the toolbar takes ~90 px of the viewport).

Noter

  • Miles stadig udskudt af ejeren. matching er bevidst KUN titel med ordene fra indstillingerne: firmaer eller beskrivelser ville trække urelaterede opslag ind i specialiseringen. Et opslag uden for alle konfigurerede roller forbliver synligt under «All».

[1.250.0] — 2026-10-12

Kortsiden bliver arbejdsbar: en joblocator over kortet flyver til ethvert synligt job og åbner dets forhåndsvisning (også på desktop), og en tekstsøgning indsnævrer kortet efter firma eller titel — begge overlever en genindlæsning.

Tilføjet

  • Joblocator: en select over kortet viser de synlige jobs sorteret efter firma+titel; valg flyver til cirklen og åbner forhåndsvisningen — også på desktop.
  • Tekstsøgning: indsnævrer kortet efter firma+titel (case-uafhængig sammenligning; feltet beholder det indtastede), gemmes i map-prefs, Reset rydder.
  • FAB’en dækker ikke attributionen på #/map ved alle bredder.

Rettet

  • To mobilhøjde-specs: gulvet går til 540 px (bjælken tager ~90 px af viewporten).

Noter

  • Miles udskydes af ejeren til næste release. De 4 nye i18n-nøgler kommer i alle 18 ordbøger, og det samlede snapshot gendannes. Locatoren åbner altid forhåndsvisningen (at navigere ville ophæve dens formål); cirklen findes via __job-referencen — IKKE _point, som L.Circle allerede ejer.

[1.249.0] — 2026-10-11

Jobkortet prioriterer nu relevans: en rolig skala fra petroleum til grå fremhæver de bedste job, score- og køretidsfiltre huskes, mobilen får et kort i fuld højde med forhåndsvisning ved tryk, og trackeren deler køretidsfilter og sortering.

[1.248.8] — 2026-10-11

Forælder-paritet: fork og web-ui synkroniseres med upstreams 115-commit-delta — en ny PageUp-kilde, tracker-URL-celler analyseres som markdown-links, Assessment-tilstanden — plus ta/ja-sprogarbejdet: looperende rapporter skæres og navngives, overskriftsskelettet holder A–G stabilt, og skriptandelen læses kun som prosa.

Tilføjet

Rettet

  • Ny PageUp-kilde (105 EN-adaptere / 110 kilder); tracker-URL-celler analyseres som markdown-links (href er dedup-nøglen); Assessment-tilstanden kommer via states.yml.
  • En looperende rapport skæres og navngives (report looping (block B repeated)), overskriftsskelettet ## A) … ## G) for ikke-engelsk.
  • Skriptandelen læser kun prosa (tabeller, SCORE_SUMMARY, kode og URLs udelukket) — en japansk rapport med latinske tabeller flaker ikke længere.
  • /api/evaluate advarer report not in <locale>, og remote-qa udskriver koderne i en kolonne.

-

[1.248.7] — 2026-10-11

Rollen fra rapportens sidehoved læser nu forælderens faktiske konvention — # Evaluation: {Company} — {Role} — i stedet for at antage # <Rolle> — <Firma>, så trackeren ikke længere bærer «Evaluation: » som rolle; en rapport på det forkerte sprog advarer i stedet for at gemme lydløst; og modelsludderet før H1 skæres fra gemte rapporter.

Rettet

  • Den lokaliserede mærkat fjernes først (Evaluation:, Оценка вакансии: og 16 varianter); efter mærkaten Company — Role → rollen er højre side; uden mærkat Role — Company → venstre; delen der navngiver firmaet afgør; rollen er aldrig firmaet eller et mærkatord — fallback er den rensede indlægslinje.
  • cleanup-plan summer N fra linjerne (— N dirty-URL line(s)), tæller ikke filer — en fil med 5 snavsede URL’er gav 1, ikke 5.
  • En rapport på det forkerte sprog advarer: prompten åbner OG lukker med den obligatoriske sproginstruktion (hele rapporten, tabeller inkluderet), og pipelinen validerer den gemte rapports sprog — drift vises som advarslen report not in <locale>.
  • Ingen modelsludder før H1 — rapporten starter ved sin overskriftslinje.

Noter

  • Ikke portet og urørt (verificeret i v1.248.6-regressionen): embed-fetch, indlæggets linjestruktur («Компания : X»), «## Rejected»-deduplisering, domænerods-afvisning før fetch, recon/link-check-ærlighed og cleanup-tilstande. Sprogsvalidering er en advarsel — rapporten (indhold allerede valideret A–G + score) gemmes; operatøren ser driften og kan gentage evalueringen.

[1.248.6] — 2026-10-10

Efterregressions-polering af Telegram-kæden: et rigtigt indlæg bevarer sin linjestruktur (mærkaten «Компания : X» og rullelinjen findes der, hvor de faktisk er), tracker-rollen kommer fra rapportens sidehoved i stedet for en rå indlægslinje, og de operationelle overflader (recon, cleanup-plan, link-check) rapporterer det, de udgiver sig for at rapportere.

Rettet

  • Et t.me-indlæg klæber ikke længere sammen i én linje: <br> bliver et linjeskift før tag-fjernelse, og numeriske HTML-entiteter dekodes; firma-mærkat-mønsteret accepterer formen med mellemrum før kolon.
  • Tracker-rollen kommer fra rapportens sidehoved (H1 # <Rolle> — <Firma>); fallback-linjen renses — ingen hashtags, ingen emoji, ≤80 tegn.
  • ## Rejected duplikeres ikke længere: sektionen oprettes én gang; hver afvisning tilføjer sin linje i den.
  • En domænerod afvises før anmodningen — en junk-URL koster ikke længere noget.
  • Recon beregner kontraktsignalet i stedet for at påstå det (honours rejected: tjekker markPipelineRejected i den udrullede kode); mærketælleren udskriver ikke længere «0» to gange.
  • cleanup-plan rapporterer tal pr. kategori (t-role der skal flyttes, dirty-URL-linjer, test-row-linjer) i stedet for én grep -c, der talte sin egen succeslinje.
  • link-check behandler github.com 5xx som uverificeret — bag bot-muren, ikke som ødelagte links.

Noter

  • Ikke portet og urørt (verificeret i v1.248.5-regressionen): selve embed-fetch, pipeline-spring-kontrakten, _setLookup-offline-testene, uk-ordinalaccept, ordboundary i rullefilteret og cleanup-apply-tilstanden. cleanup-plans kategoritælling læser oprydningsscriptets egne output-labels — at omdøbe dem ville knække tællerne lydløst.

[1.248.5] — 2026-10-10

Efterregressions-hærdning: t.me enkeltindlæg-hentninger henter nu selve indlægget teksten (embed-form), et afvist indlæg forlader eval-timerens pulje på serversiden, og ukrainske rapports native bloknummerering accepteres — plus én test, der i hemmelighed brugte det levende netværk, er offline for altid.

Rettet

  • t.me-indlæg bliver endelig evalueret: en enkeltindlægsside serverer kun kanalens sidehoved i ren HTML (~0,2 KB — «View in Telegram» og intet andet), modellen fik en tom beskrivelse, og hver Telegram-indlæg døde ved evaluering. Hentningen omskriver nu t.me/<kanal>/<id> (og feed-formen t.me/s/…) til embed-formen (?embed=1&mode=tme) — samme vært, SSRF-validering uændret — og læser indlægget fra .tgme_widget_message_text (fallback: og:description). Ingen widgettekst → afvisning ved hentningstrinnet (telegram post has no text, rejected: true) før LLM-tokens bruges.
  • Eval-timeren stopper med at betale igen for afviste indlæg (serverside-kontrakt): et afvist indlæg markeres nu i data/pipeline.md — dets linje forlader URL-hegn og lander i en ## Rejected-sektion med en kort begrundelse (idempotent, aldrig duplikeret). Timeren tager nøgne URL’er fra hegnet, så et markeret indlæg springes naturligt over — uden afhængighed af timer-scriptets indre. Recon udskriver pipeline rejected marks: N + honours rejected: yes (server-side) i stedet for at gennemsøge scriptet.
  • Ukrainske rapporter består A–G-validering igen: en uk-model nummererer blokkene efter sit eget alfabets rækkefølge (А Б В Г Д Є Ж), og lookalike-passet talte kun А/В/Е — præcis blokkene C, D, F, G manglede i produktion (2/2 reproduktioner). Validatoren accepterer nu den ukrainske ordinalsekvens, når overskrifterne vises i rækkefølge (samme disciplin som abjad for ar og devanagari for hi), og evalueringsprompten for hver locale kræver nu eksplicit latinske A–G.
  • Røle nøgleords-porten udløses på ord, ikke understrenge: linkedin.com/- og x.com/-rødder kom gennem porten, fordi lead/it levede i sidens UI-tekst. Nøgleord matcher nu på Unicode-ordgrænser, og en domænerod (URL uden sti) afvises før LLM-kaldet.
  • En enhedstest behøver ikke længere det levende netværk: no-hints-testen (tests/auto-pipeline-jd-gate.test.mjs) erstattede HTTP-transporten men udførte stadig en rigtig DNS-opslag — grøn i CI kun fordi runneren havde forbindelse. safe-fetch fik en _setLookup()-hook (selve resolveren kan udskiftes i tests; produktionskoden tilsidesætter den aldrig), og testen løser offline.

Tilføjet

  • cleanup-plan / cleanup-apply workflow-tilstande i deploy.yml: produktionens QA-affaldsoprydning (post-qa-cleanup) kører på serversiden uden SSH fra en bærbar. Loggen indeholder kun tal — ingen filnavne eller linjeforhåndsvisninger, for loggen er offentlig og filnavne indeholder firmanavne. Verify-trinnet springes over for oprydningstilstande.

Noter

  • Ikke porteret: forælderens ordgrænse-lokationskompiler og USPS-statstabel (dokumenteret siden v1.248.1). Kontrakten om at springe afviste indlæg over bor på serversiden (markering i data/pipeline.md), ikke i timer-scriptet — det er uden for repoet og bevidst uændret.

[1.248.4] — 2026-10-10

Rolleopløsningskæden for Telegram-poster: En kyrillisk post med en rigtig vakans giver nu en navngiven rapport i stedet for en afvist unknown-role-fil — og LLM-kaldet fyres kun for poster, der er værd at evaluere.

Rettet

  • Rollekæden virker for kyrilliske poster: Nøgleordslisten fik разработчик/программист/инженер/аналитик/менеджер/руководитель/тимлид/лид/дизайнер/тестировщик/QA/архитектор/специалист/директор/DevOps/SRE (den gamle var kun EN: 0 af 40 rigtige poster fik en rolle), rapportheaderen konsulteres (parseReportHeader — modellen skriver rollen i H1), og postens første meningsfulde linje er den sidste udvej.
  • Identitetsporten flyttede FØR LLM-kaldet: En post uden firma og uden rolle-spor fejler ved fetch-trinnet (rejected: true) — ingen tokens brændt på en evaluering, der alligevel ville være afvist.
  • t.me/s/<kanal>/<id> navngiver ikke længere firmaet „S“ — forhåndsvisningssegmentet springes over; begge linkformer løser til kanalen.
  • Selvetiketter „Компания: X“ i Telegram-poster honoreret (og „…в компании X“ midt i sætningen for besked-værter).

Tilføjet

  • Auto-pipeline-fejl bærer rejected: true i SSE-fejlen — serverens eval-timer bruger flaget til at springe pipeline-posten over i stedet for at gensende den hver 2. time.

Noter

  • Ikke portet denne gang: parentens word-boundary-lokationskompiler og USPS-tabellen (dokumenteret siden v1.248.1).
  • README-„Translations“-blokken genereres nu fra én kanonisk liste, med en paritetstest i CI (17 links pr. fil, egen aldrig linket) — ar/pl/uk fik blokken; |/·-separator-driften er elimineret.

[1.248.3] — 2026-10-10

Fortættelse af regressionsrunden: Eval-timeren kan under ingen omstændigheder længere arkivere navnløst Telegram-skrald som rapport, QA-oprydningen sletter ikke længere rigtige Telegram-opslag, kortets attribution er atter synlig, og dashboard-chips læses ≥ 4.5:1.

Rettet

  • Auto-pipeline validerer FØR gem: En rapport uden 0–5-score eller uden A–G-blokke afslutter kørslen ved evaluate-trinnet (rejected: true i SSE-payload) — ingen rapportfil, ingen tracker-række. De t.me-poster, der passerede længde-porten fra v1.248.2, gav to skralde-rapporter mere; nu afvises navnløse poster med company/role not identifiable.
  • guessCompanyRole opfinder ikke længere et firma fra besked-værter — t.me, telegram.me, vk.com, linkedin.com m.fl. er i EMPTY_DOMAINS: et Telegram-opslag falder tilbage på kanalnavnet, og en navnløs post afvises i stedet for at gemmes som unknown-role.
  • post-qa-cleanup læser først header-scoren: auto-pipeline skærer SCORE_SUMMARY-blokken væk før gem, så den gamle kun-summary-tjek stemplede ethvert gemt Telegram-opslag som skrald — i produktionen har 8 af 41 score i headeren, og --apply ville have slettet dem. Header-scoren (via parseReportHeader) er nu det primære signal; blokken er fallbacken. Dry-run udskriver årsagen pr. fil.
  • Leaflet-attributionen er synlig på #/map — docs-FAB dækkede den (OSM-licensbrud); hjørnet er løftet 96px.
  • Dashboard-chips læses ≥ 4.5:1 — dash-chip-labels og --manual-varianten er flyttet til --foggy-strong (før 4.31:1).

Tilføjet

  • Auto-pipeline-fejl bærer rejected: true i SSE-fejlen — serverens eval-timer bruger flaget til at springe pipeline-posten over i stedet for at prøve igen hver 2. time.

Noter

  • ar/ja-afvigelsen gentog sig ikke ved genkørslen (se v1.248.2).
  • Produktionsoprydningen venter stadig på et eksplicit ja (CAR-61c); med dette fix kan oprydningen ikke længere slette de rigtige Telegram-opslag.

[1.248.2] — 2026-10-10

Regressionsrunde: Eval-timeren forvandler ikke længere pipeline-skrald til „Last evaluation“, SCORE-parsingen overlever rigtige formater, og tracker taler endelig dit sprog.

Rettet

  • Tom-JD-rapporter skrives aldrig mere. Auto-pipelineens JD-gate steg fra 50 til 200 tegn før LLM-kaldet — placeholdersider (example.com/qa-v167-…) ender som SSE-fejl + konsoladvarsel i stedet for en …-t-role-<ts>.md-rapport, som dashboardet viste som „Last evaluation“ (42 sådanne filer i produktionen).
  • SCORE_SUMMARY-parsingen overlever rigtige formater: „4,2/5“, „4.2 / 5“, „4.2“, „SCORE :“ validerer alle; et komma med 1–2 cifre er decimal, med 3 er det tusindtal (den gamle kode læste „4,200“ som 4.2 og passerede 0–5-porten). En fejl logger kun SCORE:-linjen — aldrig rapportindhold (CI-logs er offentlige).

Tilføjet

  • scripts/post-qa-cleanup.mjs: dry-run som standard, --apply med automatiske backups (*.bak-<ts>, rapporter flyttes til qa/cleanup-backup-<ts>/): ZZ-QA-TEST-rækker i trackeren, *-t-role-*-rapporter uden gyldig SCORE og example.com-pipeline-poster.

Noter

  • Ar/ja-driften fra regressionsrunden gentog sig ikke ved genkørslen (begge: lang ✓ + A–G ✓) — ta-posten i language-check og den hærdede SCORE-parser følger som defense-in-depth.
  • Produktionsoprydningen venter på et eksplicit ja fra brugeren: først dry-run-planen, derefter --apply.

[1.248.1] — 2026-10-09

location_filter får parentens always_allow- og block_hard-tiers (CAR-60) — en flernations-lokationsstreng overlever en blokeret-søskende-liste, og en eksplicit hård blokering kan ikke længere reddes.

Rettet

  • always_allow slår block: med block: [romania, poland, croatia] og always_allow: [united kingdom] passerer workables flettede celle „London, United Kingdom · Romania · Poland · Croatia“ — hjemregionen er en mulighed (workable #4806’s forbrugercase, nu i parent-form).
  • block_hard slår always_allow: landeniveau-termer der aldrig må reddes af et always_allow-hit et andet sted i strengen.
  • strict: true tæller nu block_hard som en begrænsende tier; location_filter-afsnittet i docs/help dokumenterer begge tiers ×18.

Noter

  • Bevidst ikke portet denne gang: parentens word-boundary-lokationsnøgleordskompiler og dens USPS-statstabel (web-ui beholder substring-match; tabellen tjener US-centrerede opsætninger — læg under CAR-60 hvis nødvendig). Workable-forbrugertestens midlertidige allow-list-form forbliver som en anden dom ved siden af den nye parent-form.

[1.248.0] — 2026-10-09

Parent-paritet: fem upstream-fixes for udbydere/liveness portet — boards der har flyttet deres API, virker videre, og et lukkebanner på egen linie overses ikke længere.

Rettet

  • Gupy følger API’en til portal.gupy.io og sender de filternavne, API’en faktisk læser (workplaceType/type) — de gamle flertalsnavne blev stiltiende ignoreret; country sendes ikke længere (et konfigureret land tegner en advarsel med postens navn). Fortrolige arbejdsgivere falder på nøjagtig label-match („Confidencial Seguros“ overlever), og max_pages er loftet til 100 — API’en svarer 400 efter offset 10.000, og truncation-advarslen råder nu til at indsnævre nøgleord.
  • Workable beholder alle lande i en flernations-opslag: søskende under samme job-URL foldes i én linje („London, United Kingdom · Romania · Poland · Croatia“) i stedet for at det første land vinder.
  • Liveness: Et banner på egen linie er ikke en del af linien ovenover — „Sign in if you want to apply“ / „Get notified when this position is filled“ under en opslag læses som den lukkeklausul, det er, mens et ægte „until filled“ på tværs af linjer stadig læses aktivt.
  • Radancy læser et søskende-job-location-element i legacy-card-markup (Barclays-familiens layouts lægger lokationen efter </a>) — rækker uden egen lokation forbliver tomme i stedet for at låne naboens.
  • SmartRecruiters-fallback-links beholder den konfigurerede slug — en opslag uden betroet ref syntetiserer sin offentlige URL fra tenant-slugen, aldrig fra visningsnavnet.

Tilføjet

  • No-porter dokumenteret: upstream _http-proxy-fetchImpl-fixen (web-ui har ingen proxy-gren — en port ville omgå DNS-rebinding-vagtens identitetstjek og tilføje en undici-afhængighed, repoet bevidst undgår); upstream verify-ats (+226 linjer) og cv-facts (web-ui implementerer egen ATS-scoring og CV-parsing); parent-dashboardet Go TUI og CLI-scripts; en Teamtailor-import-omstokning (kosmetisk).

Noter

  • Kendt hul som follow-up: parentens always_allow-tier i lokationsfilteret (workables forbrugertest overlever en UK-blok takket være det) findes ikke i web-ui; porten udtrykte samme forbrugerdom gennem en allow-list-test. Registreret som separat ændring.

[1.247.0] — 2026-10-09

Halens af CAR-49…58-design-sweepet er lukket — alle resterende minor/polish-fund plus det mørke kort, som den forrige udgivelse bevidst udsatte.

Rettet

  • Kortet renderer et rigtigt mørkt tema. Zoom/lag/attribution blev mørke i v1.246.0; nu følger fliserne: Mørk tilstand tegner OSM-laget med CSS-inversion (uden leverandørnøgler), og et keyed Carto-dark-preset er tilgængeligt via MAP_TILE_DARK_URL (dets vært er tilladt i CSP img-src). Laget remontères live ved temasift.
  • Gule callouts har mørke varianter (config, batch, hero-advarsel) via token-mekanikken fra v1.246.0 — og en regression blev fanget undervejs: .callout a overdøvede .btn-primary; nu afgrænset til :not(.btn).
  • URL’en på Apply-infokortet knækker ikke længere midt i et ord.
  • CV-headerknapper er ét ikonsystem (tekst; 📁/📄/💾-emoji-mix er væk).
  • Trackerens statusfaner har én kasus — sentence case med lokale nyancer (CJK/ar/hi/ta uden kønsformer).
  • Topbar-ikoner er ét stroke-SVG-sæt — 🔔/🌙/🩺-mixet er væk; temaknappen tegner sol/måne via CSS.
  • Dashboardets Pipeline-kort mister sin lyserøde fremhævning (ring kun hover/focus).
  • Sletning af gemte søgninger ser destruktivt ud (.btn-danger, ikke en neutral ghost).
  • Pipeline-forhåndsvisning har en rigtig tom tilstand (titel + hint + CTA, tracker-mønster).
  • Tid/omkostnings-meta er ét mønster: UI.pageMeta tegner ⏱ + omkostning på én linje under visningstitlen (evaluate/deep/auto/mode-page/orientation).
  • Auto-pipeline mister sin ✨ — appens eneste dekorerede h1 tilbage på den fælles venstre kant.
  • Batch-docs-URL er et inline-link.
  • interview-digest / orientation har designede tomme tilstande (titel + hint + CTA).
  • Career-plan-eksport er deaktiveret uden plan, handlinger på én række.
  • stats: Den duplikerede „Market report“-overskrift er væk, og regions-placeholderen passer (kortere tekst ×18, fast bredde).
  • Config lækker ikke længere absolutte stier — serverens displayPath() viser ~/… eller det bare filnavn.
  • LLM_PROVIDER-hjælpeteksten er tre korte linjer (×18 + pre-line), ikke en 150-tegns mono-væg.
  • PROFILens E-mail-kort holder adressen på én linje (ellipsis; brud kun ≤480px).
  • Health-tekst bryder ikke længere ord („Run buttons“ hele; overflow-wrap anywhere).
  • Inline-kode i help overlever RTL (LTR-isoleret, nowrap, rullebar).
  • Hero-pillen „Live evals“ kolliderer ikke længere i ru/ar (flex-wrap, ikke-skrumpende ikoner).

Tilføjet

  • Mørk-flise-preset (MAP_TILE_DARK_URL + attribution) dokumenteret i koden; CSP-img-src-udvidelsen dækker Carto-værten.

Noter

  • Standarden for mørke fliser er en CSS-inversion af OSM — keyless Carto har lukket sine basemaps bag en API-nøgle (verificeret per request); keyed-presettet er opt-in, ikke standard.

[1.246.0] — 2026-10-09

Alle ti topfund fra CAR-48-senior-design-sweepet er rettet — blockeren og alle syv majors inkluderet.

Rettet

  • Apply mørk: Linket på infokortet er synligt igen. Kortet holdt sin lyse flade i mørk tilstand; linket „Need Playwright? See …“ lå på ≈1.0:1. Temabevidst .callout--info (surface/border/text/link-tokens) løfter det mørke link til ≈7.3:1.
  • RTL vender ikke længere numeriske sammensætninger. Score-piller („1.5 / 5“), rapportbånd („≥ 4.5“, „< 3.5“) og dashboardets „/ 5.0“ får retningsisolation (LTR-spans); ar-ordbogen omformulerer områder i ord, hvor prosa beder om det.
  • CV-markdown forbliver LTR. Tekstområde og forhåndsvisning renderes med dir="ltr" på arabisk; rammen omkring forbliver RTL.
  • Rapporternes DATE-kolonne bryder aldrig mere en ISO-dato (nowrap + tabulære tal).
  • Sidebar slutter over USAGE-HUD’en (scrollport-reserve + fade) — det sidste navigationselement ruller ikke længere under panelet; spejlet for RTL.
  • Mobil scan @390: „Save search“ fuldt synlig — kontrollerækken bryder og komprimerer i stedet for at klippes ved kanten.
  • Kortkontroller følger det mørke tema (zoom, lag, attribution). Fliserne bevidst uændrede: Deres oprindelse er fastlåst server-side af CSP img-src.
  • Chat-FAB’en dækker ikke længere interaktivt indhold — scroll-padding rydder den af vejen (Disable-knapper i Portals, score-pille i Reports, two-pager-input, Leaflet-attribution).
  • Aktivitetsloggen taler UI-sproget: 22 action-slugs lokaliseret ×18 locales (fallback til rå id for ukendte) og filterchips oversat; TARGET-kolonnen bliver — auto-pipeline fylder den.
  • Assessments-formularer får rigtige labels (sentence case, htmlFor/id-binding) i stedet for kun placeholders.

Noter

  • Ikke i denne udgivelse: mørke kortfliser (kræver en CSP-img-src-udvidelse — server-side, bevidst ikke klientside); mørke varianter af de gule callouts (config, batch) — token-mekanikken er klar til opfølgning.

[1.245.0] — 2026-10-09

Tamil (தமிழ்) tilslutter sig som det 18. UI-sprog — det første nye sprog siden bølgen på 17, med fuld nøgleparitet.

Tilføjet

  • Tamil (ta): 1449/1449 nøgler i fuld paritet med en, ingen mistede pladsholdere, hi-stil indic-tech-konventioner (udbydere, modelnavne, stier og kommandoer forbliver latinske). detect() accepterer ta, ta-IN, ta-LK; tamil er LTR (låst af test).
  • Fuldt docs/help/ta.md (33 H2 / 125 H3, kildetællinger verificeret mod det levende register, Hermes-canary-ankre, ordret YAML), plus README.ta.md- og CHANGELOG.ta.md-spejle.
  • Enumerationsgates 17 → 18: LANGS, detect-sonder, i18n-revision, changelog-paritet, RTL-vagt, CI-langs — henter også hi, som tidligere manglede på CI-listen.

Noter

  • cvstart.org-landingssiden forbliver ved 17 sprog for nu — oversættelse er en separat opgave; sitets indholdssync leverer allerede docs/help/ta.md og ta-changeloggen.
  • report-header.js REPORT_LABELS forbliver ved 17 — parsing af tamilske rapporter kommer med tamilske rapportgenerering i parent-repoet.

[1.244.2] — 2026-10-08

Scan-sidens polering: launcher, statuslinje, reposts-panel og filtre er redesignet som en konsistent chrome — og resultattabellen kan ikke længere strækkes af board-data.

Rettet

  • Lønceller viser kun beløbsintervallet. Nogle boards putter hele benefit-teksten i lønefeltet — den synlige celle viser nu kun beløbsdelen og flytter teksten til tooltippen (før: en 6-linjers celle, der strakte hver række).
  • Rækker med tom titel viser virksomheden (og derefter en neutral bindestreg) i stedet for en kæmpe tom celle.
  • Seniority-badget bryder aldrig i sin kolonne med fast bredde.
  • Rækker uden score viser en dæmpet «◎ —» med en tooltip, der forklarer, at two-pager-sammenligningen ikke fandt matchende nøgleord (før: intet, hvilket så ødelagt ud ved siden af scorede rækker).

Tilføjet

  • Chrome-redesign: launcher-kort (justeret kontrolrække, dominerende primærknap), terminal-statuslinje med statuspunkt (inaktiv/kører/færdig/fejl) respekterer reduced-motion, reposts-panelet har en højdetag med sticky-header (et datasæt på 1,560 klynger renderede et 155,000 px-panel), og filterblokken som ensartet responsivt grid med justeret footer.

Noter

  • Alt andet i #/scan er identisk med v1.244.1 — kun chrome-poleringen og de fire rettelser ovenfor er ændret. Tests 5045 → 5068 unit.

[1.244.1] — 2026-10-08

Rettet

  • Scan icons announce real values. The boost/fit/score icons’ accessible names leaked the raw dict templates (“Fit: {band}”, “Boosted by {by}”) — {band}/{by}/{score} are now substituted (band word, booster keyword, numeric score). [HIGH a11y, caught live in the v1.244.0 regression round]
  • Title pipes split correctly. A 4-segment title like «C++ | Rust | Go Developer | Onsite» no longer lifts “Go Developer” out as a “country” — the split demands the segment resolves to a real country (conservative Countries.detectCountry).
  • Meta dates render for every row. daysSince accepted date-only ISO, but the API serves full timestamps for ~83% of dated rows — those rows showed no date segment.

Noter

  • Alt andet i #/scan er identisk med v1.244.0 — kun de tre rettelser ovenfor er ændret.
  • Bevidst ikke gjort: filtertilstand i URL-hashen, tastatur-rækkenavigation og 5 lakhs INR-parsing (eksisterende opfølgninger).

[1.244.0] — 2026-10-08

Scan-resultaterne læses som en liste, ikke en væg: ét opslag = to linjer, signalerne er ikoner, og en scanning på 700 rækker er en pagineret tabel i stedet for en side på 37,000 px.

Rettet

  • Række-anatomi. Hvert opslag renderes som en afgrænset to-linjers række: linje 1 titlen, linje 2 company · location · source · date · work-type. Boost-badge, title-fit-båndet og fit-scoren blev til ikoner med lokaliserede tilgængelige navne og tooltips (skærmlæsere læser «Соответствие: сильное» / “Fit: strong”, ikke en væg af ord); tillids- og relokations-badges foldede sig ind i samme skinne. Senioritet og løn forbliver som hjælpekolonner, der kun vises på desktop.
  • Titel-hygiejne. Et afsluttende | Germany | Remote-segment skæres ud af titlen og ind i meta-linjen — Unicode-bevidst, kun når halen er en ægte work-type-markør, og midtersegmentet er stedsformet (legitime pipes som “C++ | Rust | Go Developer” splittes aldrig).
  • Ikke mere vandret udbredelse. Fast tabel-layout, min-width: 0, titel/meta på én linje afkortet med ellipse med den fulde tekst i tooltippen: nul sideoverflow og nul intern tabel-scroll ved 1440 px og 390 px (den gamle side overflowede med 675 px ved telefonbredde).
  • Paginering. Resultaterne renderes 50 per side (25/50/100/200 kan vælges) — en scanning på 700 rækker er nu ~4,600 px høj i stedet for ~37,000 px, og DOM’en holder ~1,000 noder i stedet for 5,500+.

Tilføjet

  • Layout-kontrakt-tests: den to-linjers række, ikonernes tilgængelige navne (en + ru), pagineringens node-budget og title-fit-antal-/rækkefølge-vogteren kører i browser-suitten — redesignet kan ikke stille regressere.

Noter

  • Tests 5036 → 5045 unit (browser-suitten fik layout-kontrakterne), gennemsnitlig dækning 98.14 % linjer / 89.34 % grene (gulv 96/86).
  • Det, scanneren finder, scoreformlerne og last-scan.json, er urørte — title-fit forbliver en annotering.
  • Ikke i denne udgivelse: URL-hash-filtertilstand og tastaturstyret rækkenavigation (opfølgning); 5 lakhs INR-parsing (pre-existing).

[1.243.2] — 2026-10-08

Rettet

  • Udrulningsbar version skåret som v1.243.2. Git-tagget v1.243.1 blev flyttet efter udgivelsen, og serverens git fetch --tags nægter korrekt at overskrive et eksisterende tag — så v1.243.1 var aldrig udrulningsbar. Dette tag bærer det identiske træ (window-listener-fixet til modalen på basis af v1.243.0) plus denne versionsforøgelse. Intet andet ændrede sig; npm-1.243.1-tarball’en containede allerede fixet.

Noter

  • App-koden er identisk med v1.243.1 — kun den deploybare tag er ny (serverens git fetch --tags afviste den ompointed v1.243.1).
  • Bevidst ikke gjort: gennemtving opdatering af serverens tag (publicerede tags flyttes aldrig).

[1.243.1] — 2026-10-08

Rettet

  • „Registrér udfald“-modalen lukker sig nu faktisk ved navigation. v1.243.0-vogteren lyttede efter hashchange på document, hvor begivenheden aldrig udløses — fixet ankom dødt, og modalen blokerede stadig den næste visning (fanget live i produktionen af v1.243.1-regressionsrunden). Vogteren lytter på window; testen dispatcher også der og er verificeret rød mod den ødelagte kode.

[1.243.0] — 2026-10-08

Browser-laget beskytter dit arbejde og taler dit sprog: ingen redigeringer går tabt uden advarsel, ingen stille fejl, ingen engelsk-rester i et oversat interface, AA-kontrast overalt.

Rettet

  • Ugemte redigeringer overlever re-renders. CV-editoren holder en dirty-buffer og gendanner den ved hver render — Annuller, et sprogskift eller navigation til CV Studio spørger nu i stedet for at kassere; karriereplanen bevarer sin genererede tekst på samme måde. Indlæsningsfejl i Config/CV Studio/career-plan/memory/two-pager viser en fejl og deaktiverer Gem i stedet for stille at overskrive filen med blanks.
  • “Registrér udfald”-modalen overlever ikke længere navigation. At åbne den på #/tracker og klikke på en anden view lod den blokere hele siden (fundet i v1.242.1-to-miljø-regressionen) — den lukker nu ved ruteskift; dens scan-søskne stopper også deres SSE-strømme og frigør lyttere ved navigation.
  • Løn- og nøgleords-parsing læser alle skrifter. Nøgleordschips bruger Unicode-ordgrænser (kyrillisk, c++, .net filtrerer korrekt i stedet for til nul rækker); en delt løn-parser retter $182.9K - $240K, от 100 000 руб, 100 тыс. руб., 50 000 Kč (var 50M USD) og range-semantikken ($100-150K); obligatorisk “Germany or Netherlands” tæller ikke længere som både opfyldt OG overtrådt.
  • Streams sætter sig præcis én gang. En tabt SSE-forbindelse leverede fejlen to gange og kunne efterlade Generér deaktiveret for altid; hver terminaltilstand (done/error/luk/throw, inklusive et dræbt child) sætter én vej og genaktiverer knappen. Auto-pipeline flusher sin sidste bufferede frame i stedet for at kassere den.
  • Privatliv og korrekthed i de små veje. Bug-rapportens krop bærer ikke længere det evaluerede job-URL eller rapport-slugs; CV-privatliv maskerer bare linkedin.com/in/…-links, ALLE-CAPS-navne og ødelægger ikke længere EU-datoer; lande-opløsning tager det længste match og nægter at gætte når to lande nævnes (“Cambridge, MA” ikke længere → UK); filnavne bevarer kyrilliske navne.
  • Router og a11y. Skip-linket 404’er ikke længere til ontent; det aktive nav-element bærer aria-current="page"; én <main>/én <nav>; Escape lukker mobil-draweren (som nu virkelig er ude af tab-rækkefølgen når lukket); scroll-padding-top holder fokus synligt bag sticky-bjælker; den sticky banner dækker ikke længere topbaren.
  • Kontrasten er AA i begge temaer — mørke tema-toasts var hvid-på-hvid (1.10:1): toasts, knapper, bannere og links på --rausch opløses nu gennem temainvariante tokens, bevogtet af beregnede WCAG-kontrakt-tests (≥ 4.5:1).
  • Alt andet fra runden: evaluate viser afskæringsadvarslen; memory/two-pager nægter at Gemme over en fejlet indlæsning; scan ophører ikke længere med at forældreløse sin SSE; scan-resultater klassificerer API-bagte boards fra serverens registry i stedet for en uddateret regex; trackerens “Proceed with Caution” er en advarsel, ikke et rødt badge; statistik folder lokaliserede statusser; søjlediagrammer læses korrekt i RTL; docs-FAB dækker ikke længere indhold på telefoner; GET /app.js svarer 404 i stedet for index-shellen; GET /api/runners lister sine handlinger.

Tilføjet

  • Dansk kommer med i automatisk detektion — en da-DK-browser får nu det danske interface (ordbogen var komplet, detektionen manglede den); zh-Hant* mappes til traditionelt kinesisk. cv-diagnostics — CV-tjeklisten — er fuldt lokaliseret (28 diag.*-nøgler × 17). 26 field-spec-labels tilføjet; 31 døde nøgler fjernet; leverandør-lister påstår ikke længere at Hermes er “sidst i auto-rækkefølgen”; docs-fab/menu-aria-labels er lokaliseret.

Noter

  • Tests 4812 → 5036 unit, browser 118 + nye navigations/kontrast-kontrakter, dækning 98.15 % linjer / 89.34 % grene (gulv 96/86).
  • Ikke i denne udgivelse: #/scan-redesignet (Fase 4 — v1.244.0, spec i udkast); en dedikeret export.docxFailed-nøgle (fejlen genbruger common.error); 5 lakhs INR parser stadig som 5 (pre-existing).

[1.242.1] — 2026-10-08

Rettet

  • Udgivelsesarkivet indeholder igen ingen node_modules-symlinks. Git-tagget v1.242.0 bar et node_modules-symlink i roden og site/node_modules (en blanket git add -A sneg dem forbi ignore-mønstrene med afsluttende skråstreg), hvilket fik server-udrulningens tar-udpakning til at fejle — udrulningen rullede sikkert tilbage, og produktionen forblev på 1.241.1. Begge symlinks er fjernet fra tracking og ignore-mønstrene udvidet; npm-tarballen blev aldrig berørt (npm udelukker node_modules ved pakning).

Noter

  • App-koden er identisk med v1.242.0 — kun pakning. Kildekorrigeringsindholdet ruller til produktion med denne udrulning (v1.242.0 nåede aldrig produktion: server-udrulningen rullede tilbage efter tar-fejlen).
  • Bevidst ikke gjort: om-tagning af v1.242.0 (npm har allerede udgivet 1.242.0; registry-tarballen er ren — npm udelukker node_modules ved pakning).

[1.242.0] — 2026-10-07

Scannerens datalag er igen til at stole på: døde kilder lever igen, et misdannet svar kan ikke længere udgive sig for at være en tom tavle, og et fjendtligt tavle-URL kan ikke længere omdirigere en scanning.

Rettet

  • Døde kilder lever igen. justjoin (API-konvolutten ændrede sig til {data, meta.next.cursor}) læser sit fulde katalog via en cursor-gennemgang med de nye lønfelter; nofluffjobs svarer 400 uden salaryCurrency — forælderens påkrævede forespørgsel sendes, og resultaterne pagineres (pageTo). himalayas og jobicy så kun de ca. 20 nyeste opslag ud af over 100.000 — begge gennemgår nu deres fulde kataloger (offset-/cursor-paginering med sideløfter).
  • En 200 med den forkerte form kaster en fejl på side 1. Ca. 40 kilder læste misdannede svar eller udfordringssvar som “0 opslag”, og scanningen “lykkedes” dermed lydløst. Nye vagter i server/lib/sources/_shape.mjs (requireArray / requireContainer / requireObject) gør fejlen højlydt på tværs af alle familier; en fejl på en senere side bevarer de allerede indsamlede sider; pagineringen stopper på den rå sidelængde, ikke det filtrerede antal.
  • SSRF: delstrengskontroller af leverandører erstattet med parsnede fastlåsninger af den nøjagtige vært. lever (clever.com indeholder lever.co), greenhouse (5 værter + de ældre boards[.eu].greenhouse.io path-slug-værter), ashby, smartrecruiters, workable, gem REST, ibm, arbeitsagentur, hecklerkoch (kun www), workingnomads (http://169.254.169.254 var nået forbi DNS-vagten), remoteok, remotive, rss, successfactors. redirect:'error' overalt; job-URL’er skal være https: på den fastlåste vært (javascript: / data: / værtsfremmede droppes).
  • Én fejlkonfigureret portals-post kan ikke længere afbryde en hel scanning. resolveAdapter opfanger adapter-undtagelser, detectApi pakkes ind pr. firma, kastende adaptere returnerer null; comeet-hentefejl redigerer ?token=, før de når logs eller karantæneposter.
  • Paginering og ferskhed. workday gennemgår tenants ud over 100 opslag (offset-sider, MAX_PAGES); telegram beholder de NYESTE indlæg og paginerer ?before= i stedet for lydløst at beholde de ældste; tencent fortsætter, når Count mangler; taleo parser franske overskriftstabeller; avature stopper på den rå sidelængde; UTC-datostempler (amazon off-by-one øst for UTC, torre, workingnomads, trudvsem); HTML-entiteter afkodet (geekjob, getmatch, hh); mycareersfuture udsender den fulde jobform med 12 felter.
  • Fjern-detektion strammet op. arbeitsagentur, vdab, rippling, teamtailor: kontraktsprocenten (“Verpleegkundige (100%)”, bundesweit) og ordet “distributed” (“Distributed Systems Engineer”) markerer ikke længere on-site-roller som Remote.

Tilføjet

  • tests/adapters-pin-coverage.test.mjs fuldender den værts-fastlåsnings-grendækning, som fastlåsningerne indførte.

Noter

  • Tests 4419 → 4812, browser 118. Gennemsnitlig dækning 98.15 % linje / 89.36 % gren (gategrænse 96 / 86).
  • Ikke med i denne udgivelse: klientfundene fra samme gennemgangsrunde (fase 3 — views, libs, CSS/a11y, i18n); sources/habr.mjs mangler stadig en dedikeret testfil (ratchet-fritagelse).

[1.241.1] — 2026-10-07

Live-vurderinger virker fra ende til anden i alle sprog, jobkortet placerer lange opslag med flere lokationer, og en udrulning dræber ikke længere en kørende scanning.

Rettet

  • Vurderinger ser hele metoden. Kontekstbudgettet (144 KB) skar stadig enden af modes/oferta.md af, når CV og profil var indlejret, så hver live-vurdering missede sine sidste blokke. Budgettet er nu 192 KB og promptens bløde loft 256 KB, defineret ét sted i llm-dispatch.mjs.
  • Rapporter på det valgte sprog. Sprogvejledningen åbner nu prompten og lukker den også, og almindelige ord (rolle, team, design…) skrives på rapportens sprog; kun navne, teknologier og ordrette citater forbliver engelske. Retter hindi- og japanske rapporter, der mest var på engelsk.
  • Langsomme vurderinger ender ikke længere i HTTP 502. Vurderingens timeout er 300 s (tidligere udbyderens standard på 180 s).
  • Hindi-blokbogstaver. En rapport, der staver bogstaverne A–G med devanagari (## ए), ## बी) … ## जी)), genkendes, og SCORE: accepterer lokale cifre (३.८, ٣٫٨, 3.8) og decimalkomma.
  • Jobkort: lange lokationer. En celle som “Berlin Office · Berlin · Germany · Bosnia · …” (over 300 tegn) blev afvist med HTTP 400, og opslaget fik ingen markør. Nu bruges det første rigtige sted (·, ;, |, /, linjeskift; “Remote …”-segmenter, “(HQ)” og “Office” springes over); kun en forespørgsel over 2000 tegn afvises.
  • Udrulning mod den timelige scanning. Udrulningen holder scannings- og autovurderingstimerne tilbage, venter på, at en kørende færdiggør (op til 15 min), genstarter og genoptager altid timerne — også ved rollback.

Tilføjet

  • Jobkort på cvstart.org på alle 17 sprog samt i de engelske og russiske README-filer.
  • Skærmbilleder af kortet på alle sprog — ét pr. sprog (scripts/capture-map-screenshots.mjs), i alle 17 README-filer, på cvstart.org og i et nyt hjælpeafsnit, “Sådan bruger du kortet” (§33, ×17).

Noter

  • Tests 4404 → 4419, browser 118. Fjern-QA (alle ruter, websted, links og live LLM × 17 sprog) grøn i produktion.
  • Ikke med i denne udgivelse: streamede evalueringer — tidsgrænsen på 300 s er stadig en hård grænse (en langsom lokal model kan stadig ramme den), og Hermes-broen kalder fortsat uden streaming.

[1.241.0] — 2026-10-07

Hærdningsudgivelse efter en kodegennemgang med 28 agenter (~190 verificerede fund): sikkerheds-, procesnedbruds- og datatabsklasserne er lukket, plus et jobkort bidraget af @bullitt186.

Tilføjet

  • Jobkort (#/map) — opslag fra pipelinen, den seneste scanning og trackeren på et OpenStreetMap-kort, geokodet via Nominatim med en identificerende User-Agent, en kø på 1 forespørgsel/s, back-off og en cache på disk. Leaflet serveres fra denne server (intet CDN); CSP’en får kun tile-oprindelsen tilføjet i img-src. Bidraget af @bullitt186 (#381).
  • Forespørgselsvagt — serveren afviser en Host, den ikke serverer (DNS-rebinding), samt skrivninger på tværs af websteder og GET-forespørgsler med sideeffekter (/api/stream/*, /api/run/*, /api/geocode). En reverse proxy, der videresender et offentligt navn, opfører det i ALLOWED_HOSTS; udrulningsworkflowet skriver den systemd-drop-in ud fra den offentlige URL.
  • Dækningsport — npm run test:coverage:gate (scripts/coverage-report.mjs) udskriver linje-/grendækning pr. fil og fejler under en stigende baseline.

Rettet

  • En misdannet forespørgsel stopper ikke længere serveren. Express 4 ignorerede afviste asynkrone handlere, så et felt af forkert type i /api/deep, /api/auto-pipeline, /api/career-plan, /api/tracker eller en NUL-byte i /api/stats afsluttede processen; de er nu JSON-400’ere, og enhver anden afvisning bliver til en 500.
  • En afbrudt eller mislykket scanning sletter ikke længere de seneste resultater. last-scan.json bevares, når en scanning stoppes, eller alle kilder fejlede, og en scanning af ét enkelt firma fletter i stedet for at erstatte. Én fejlkonfigureret portals.yml-post afbryder ikke længere hele scanningen.
  • Vurderinger ser hele metoden. Mode-filer blev afskåret ved 16 KB, så oferta.md (92 KB) mistede blokkene C–G; lofterne pr. fil er nu 128 KB for modes og 64 KB for CV’et, og en afskæring rapporteres. Tomme eller afskårne svar fejler i stedet for at skrive en tom rapport.
  • SSRF: redirect-hop kontrolleres igen for private mål, hvert DNS-svar kontrolleres, scanningsfristen dækker body’en, *_BASE_URL-nøgler går kun til leverandørens vært (Hermes/Ollama: loopback eller LAN), pandoc køres med --sandbox.
  • Event-loop-stop: to kvadratiske regulære udtryk (HTML-fjernelse, markdown-sanering) erstattet med lineære scannere.
  • Datatab: sletning af en pipeline-række beholdt de andre rækkers kompensation; $& i en URL ødelagde pipeline.md; gem af mock-interview, networking og deep research overskrev tidligere filer; interviewhistorikken beholdt de første 40 ture i stedet for de sidste.
  • LLM-laget: auto-pipeline og deep research respekterer LLM_PROVIDER og alle udbydere via den fælles dispatch, registrerer forbrug og rapporterer afskæring; Gemini evaluate/test gemmer ikke længere en rapport; OpenAI bruger max_completion_tokens, og en OPENAI_MODEL kun til Codex sendes som gpt-5; jobbeskrivelsen indrammes som upålidelige data.
  • Rapport-, deep- og inline-PDF’er sender --skip-fact-check (CV-faktatjekket blokerede enhver rapport med tal); profilens sideformat tilsidesættes ikke længere.
  • Scannere: karantæne er nøglet på URL (så rettelse af en URL giver nyt forsøg), deduplikering inden for en kørsel på kanonisk URL, tomme listeposter matcher ikke længere alt, atomiske skrivninger, skipped_*-historikrækker er ikke “set”.
  • Proceskontrol: SIGKILL-eskaleringen udløstes aldrig; batchkørsler dræber hele deres procesgruppe ved afbrydelse af forbindelsen.
  • CI og udgivelse: CI kører nu gates for changelog-paritet, workflows og i18n; workflowtilladelser efter mindste privilegium; produktionshemmeligheder kun under production-miljøet; npm-pakken leveres nu med docs/help/.
  • Tests: ingen test rører længere netværket eller det rigtige forælderprojekt (en eksplicit CAREER_OPS_ROOT respekteres altid); kopierede algoritmer erstattet af produktionskoden.

Noter

  • Tests 4056 → 4404, browser 118. Baseline for serverdækning: linje 96,7 %, gren 86,3 % (scripts/coverage-baseline.json).
  • Specifikationer ligger nu i én mappe, docs/sdd/specs/; programplanen er docs/sdd/PLAN.md, matrixen invariant→gate er docs/sdd/TRACEABILITY.md.
  • Note til operatører: bag en reverse proxy sættes ALLOWED_HOSTS=<offentlig vært>; en Ollama/Hermes-base-URL på en offentlig vært afvises nu.

[1.240.0] — 2026-10-06

Forælder-paritet — career-ops main @ 62905981 (VERSION 1.35.0, 177 upstream-commits siden b39931e). Seks nye kilder — 103 → 109 (104 EN + 5 RU) — rettelser spejlet i otte eksisterende udbydere og checkliste-pipelineformatet, bidraget af @bullitt186.

Tilføjet

  • Seks nye kilder — 103 → 109 (104 EN + 5 RU), 98 → 104 EN-adaptere.
    • ADP Workforce Now (workforcenow.adp.com med cid + ccId) — $skip-paginering efter antallet af rækker, der faktisk blev returneret; et svar uden både jobRequisitions og meta kaster en fejl i stedet for at blive læst som en tom tavle; tilvalgt detaljeberigelse (adpWorkforcenow.fetchDetails, standard 25, loft 100).
    • Gupy (employability-portal.gupy.io) — søgeordsgennemgang på tværs af hele tavlen, nyeste først med tidligt stop på since_days; workplaceType læses som den entals pt-BR-streng, så hybridopslag ikke går tabt; fortrolige karrieresider droppes.
    • JazzHR (*.applytojob.com) — kortparser med en reserve på bare ankre, så et delvist redesign stadig giver opslag; opslagslinks uden et eneste parset kort kaster en fejl, mens en reelt tom tavle returnerer [].
    • Startup Jobs (startup.jobs/feeds/jobs) — RSS, én forespørgsel; en misdannet, HTML- eller afkortet body kaster en fejl i stedet for at returnere [] (forælderens rettelse fra gennemgangen efter sammenfletningen, 08fe5d06); CDATA og kommentarer maskeres, før items matches.
    • Taleo (<tenant>.taleo.net, tre.taleo.net afvises) — shell-GET og derefter searchjobs-POST; en shell uden portal-id kaster en fejl som en privat tavle; kolonner matches efter overskrift.
    • UKG Pro / UltiPro (recruiting[N].ultipro.{com,ca}) — Top=50 + Skip, totalCount bruges aldrig som stopbetingelse, sideloft 100 (begrænset til 1500), tilvalgte detaljesider parses med en strengbevidst gennemgang af klammer.

Rettet

  • Pipeline i forælderens checklisteformat — upstream career-ops skriver data/pipeline.md som sektionerne ## Pending / ## Processed med rækker af formen - [ ] url | …, som UI’en læste som 0 afventende og skrev til ved at tilføje en fence for enden af filen, hvor forælderen aldrig kigger. parsePipeline, addPipelineUrl og removePipelineUrl læser og skriver nu den form (deduplikering også mod behandlede rækker; kompensation som et mærket note: comp …-segment); det fencede format er uændret. Bidraget af @bullitt186 (#380).
  • Land foldet ind i lokation — Ashby (primær address.postalAddress), Breezy (country.name) og Recruitee (flad location) tilføjer landet, medmindre navnet allerede indeholder det som et helt ord, så en fjernstilling med Storbritannien som primær og USA som sekundær ikke længere droppes af et lokationsfilter.
  • MokaHR — regionsværten hire-r1.mokahr.com accepteres (allowlisten er præcis app.mokahr.com + hire-r1.mokahr.com), API-POST og jobbets links bruger tavlens egen vært, og en success:false i selve svaret kaster nu en fejl i stedet for at blive læst som en tom tavle.
  • Avature — article--jobs-kort parses (titel fra overskriftsankeret, lokation fra icon-address-span’en).
  • SAP SuccessFactors — en gemt søge-URL af formen /go/<Category>/<id>[/<offset>]/ opløses til tenantens rod; den ramte tidligere …/tile-search-results/, som svarer 200 uden en eneste flise.
  • Deutsche Bahn — db.jobs blanker enhver resultatside, der indeholder et opslag, den ikke kan rendere; gennemgangen sorterer nu efter pubExternalDate_tdt med 1000 pr. side (højst 5 sider), stopper på det rå antal hit-ankre og kaster en fejl ved manglende resultatoverskrift eller uparsede opslagslinks i stedet for at returnere en for kort tavle.
  • HigherEdJobs — en Incapsula-udfordringsside besvaret med HTTP 200 blev tidligere parset som nul items og læst som en tom tavle; nu kaster den en fejl.
  • En test læste det rigtige forældreprojekt på en udviklermaskine — tests/reports-list-cache.test.mjs satte CAREER_OPS_ROOT til en midlertidig mappe uden cv.md/portals.yml, som paths.mjs ignorerer, så lokalt talte den forælderens rapporter (6 i stedet for 3), mens CI, uden forælder ved siden af, bestod.

Noter

  • Tests 3782 → 4056. Nye suiter: sources-adp-workforcenow, sources-gupy, sources-jazzhr, sources-startup-jobs, sources-taleo, sources-ultipro, sources-location-country-fold, sources-deutschebahn-blanked-page, sources-higheredjobs-challenge-page, samt parsers-pipeline-checklist fra #380.
  • Forælder: forket blev bragt op til upstream main (144 → 0 commits bagud), og de fire ADR-0002-afvigelser blev verificeret intakte; upstreams tilbagerulning af det kyrilliske LOCATIONISH_RE kom ikke med.
  • Allerede udgivet i v1.239.0, ikke gentaget: AppliTrack, NEOGOV, Red Rover, SchoolSpring, OCC Mundial, indlejrede Greenhouse-tavler, Workday myworkdaysite.com.
  • Ikke porteret, med begrundelser: trusted-proxy-egress (CAREER_OPS_TRUST_PROXY_EGRESS, _http.mjs / _ip-guard.mjs / _dns-cache.mjs) — web-ui scanner gennem sit eget transportlag http-json.mjs; registret over kolonnerne i scan-history.tsv og sprogbevidst requisitions-deduplikering — web-ui læser position 1–12, som ikke flyttede sig, og deduplikerer på URL; SmartRecruiters requisitionId / language — ingen forbruger i web-ui’s jobform; Gem isoCountry → landenavn — kræver forælderens alfa-3-tabel med 249 poster, udskudt; ændringer kun for CLI’en (tilstande, opdaterer, doctor, PDF/ATS-payload, tracker-scripts, Go-dashboard, Singapore-tilstand).

[1.239.4] — 2026-09-29

Patch fra live-regressionen af v1.239.3.

Rettet

  • Koreanske og traditionelt kinesiske vurderinger meldte et manglende scoreresumé. De rapporter fylder 10–11 tusind tegn, og resuméet kommer sidst, så det faldt uden for grænsen på 8192 output-tokens. Vurderinger (og auto-pipelinen) tillader nu 16384 tokens, og hvis en udbyder alligevel afskærer et svar, siger den første advarsel det i stedet for at opremse manglende blokke.
  • Live-tjekket læste et kort tysk svar som ikke-tysk (3 tyske stopord, ingen engelske). Et listeformet svar kan have få; uden nogen engelske er tre nu nok.
  • Tests 3778 → 3782.

Noter

  • Ruterne til dybdegående research og tilstande beholder grænsen på 8192 tokens: deres svar når den ikke i live-kørslerne.

[1.239.3] — 2026-09-29

Patch fra live-regressionen af v1.239.2.

Rettet

  • Arabiske vurderinger dumpede stadig A–G-tjekket, efter at v1.239.2 havde rettet japansk og hindi. Et maskeret overskriftsskelet (ingen rapporttekst i loggen) viste hvorfor: den arabiske rapport skriver blokbogstavet på arabisk i abjad-rækkefølge, uanset hvad prompten beder om. Tjekket godtager nu أ ب ج د هـ و ز som A–G, når bogstavet står alene nær starten af en overskrift, ligesom det allerede godtog kyrilliske dobbeltgængere; de samme bogstaver inde i et arabisk ord tæller ikke.
  • Live-tjekket udskriver dette maskerede skelet, når A–G-tjekket fejler, så det næste tilfælde kan diagnosticeres fra loggen.
  • Tests 3776 → 3778.

Noter

  • Noten til v1.239.2 sagde, at tjekket ikke ville blive lempet; for arabisk er det nu, fordi tre live-kørsler viste, at prompten alene ikke holder det latinske bogstav.

[1.239.2] — 2026-09-29

Patch fra live-regressionen af v1.239.1.

Rettet

  • En arabisk vurdering oversatte sine blokbogstaver, og en japansk udelod scoreresuméet. v1.239.1 gentog kun sproget i promptens sidste linje. Linjen siger nu også, at det latinske bogstav A–G i hver overskrift og ---SCORE_SUMMARY----blokken (markører og nøgler på engelsk) ikke må oversættes, og beder om sprogets egen skrift.
  • Tests 3775 → 3776.

Noter

  • Rapporttjekket er ikke lempet til at godtage oversatte bogstaver eller markører: prompten holder formatet stabilt.

[1.239.1] — 2026-09-29

Patch fra live-regressionen af v1.239.0.

Rettet

  • Japanske og ukrainske vurderinger kom næsten helt på engelsk. Sproginstruksen stod øverst i prompten, før snesevis af kilobyte engelske projektfiler og jobopslag. Prompten gentager nu sproget i sin sidste linje.
  • Live-tjekket meldte en fejlet scanning, når serveren allerede kørte en (den timelige scanning, gentaget lige efter deployet). At serveren afviser en anden scanning er korrekt; tjekket venter nu og prøver igen, i op til 30 minutter.
  • Tests 3774 → 3775.

Noter

  • Serverens grænse på én scanning ad gangen er ikke lempet: en anden scanning afvises stadig med SCAN_BUSY. Kun tjekket er ændret.

[1.239.0] — 2026-09-29

Paritet med career-ops @ b39931e: fem nye kilder og tre overførte rettelser.

Tilføjet

  • Fem nye kilder (98 → 103; engelske adaptere 93 → 98): AppliTrack (applitrack.com/<distrikt>), NEOGOV (SchoolJobs / GovernmentJobs), Red Rover (jobs.redroverk12.com/org/<id>) og SchoolSpring (<distrikt>.schoolspring.com) til ansættelser på skoler og i den offentlige sektor, plus OCC Mundial, Mexicos største jobside (eksplicit provider: occ med søgeord). Hver er låst til sin vært, kun HTTPS, og afviser omdirigeringer.
  • Tests 3500 → 3774.

Rettet

  • Indlejrede Greenhouse-tavler (job-boards.greenhouse.io/embed/job_board?for=<tavle>) pegede på en tavle ved navn “embed” og fejlede; tavlen hentes nu fra ?for=, og kun på en ægte Greenhouse-vært.
  • Workday-tavler på myworkdaysite.com (/recruiting/<tenant>/<site>) blev ikke genkendt; de scannes nu, med stillingslinks på samme vært.
  • Et rapportnavn med parenteser (042-acme-(berlin)-….md) blev i trackeren skåret af ved første ); hele navnet bevares nu.

Noter

  • Forældreprojektets ændringer, der kun gælder CLI’en, er ikke overført — PDF- og CV-skabeloner, scaffolderen, batch-kørslen, career-profile-importen, ATS-nøgleordsdækning, oversættelser af interviewtilstande, CLI-værten pi: web-ui kører dem ikke.
  • At åbne sådan en rapport fra trackeren kræver stadig, at rapportruten accepterer parenteser i et filnavn; den rute ændres ikke i denne udgivelse.

[1.238.3] — 2026-09-27

Siderne svarer også under en scanning, og logs fra fjern-QA lækker ikke længere produktionsværten.

Rettet

  • Dashboard og rapporter tog sekunder at indlæse og fik timeout under en scanning. /api/reports og /api/dashboard læste og parsede alle rapporter ved hver forespørgsel — omkring 3,7 s på produktionsserveren, mens alle andre forespørgsler ventede; under en scanning ramte sideindlæsninger 30-sekunders timeoutet. Parsede rapporthoveder caches nu pr. fil og fornyes, når filen ændres, så en liste koster ét filtjek pr. rapport (500 rapporter: 430 ms → 3 ms lokalt).
  • Et fund fra fjern-QA kunne skrive en del af produktionsværtens navn i en offentlig log. GitHub maskerer kun en hemmelighed, når hele værdien optræder, og en fejlmeddelelse afkortet til 180 tegn endte midt i værtsnavnet. Fund og hele rapporter redigeres nu, før de afkortes.
  • Hver AI-vurdering blev markeret som fejlformateret. Prompten bad aldrig om ---SCORE_SUMMARY----blokken, som rapporttjekket kræver (forældreprojektets vurderingsscripts beder om den), og en oversat rapport oversatte også ordet “Block”, så tjekket ikke fandt afsnittene. Prompten beder nu om resuméet og blokbogstavet i hver overskrift, tjekket accepterer et oversat ord foran bogstavet, og resuméblokken fjernes, før rapporten vises eller gemmes.

Tilføjet

  • Tests 3488 → 3500.

Noter

  • Scanneren kører stadig inde i serverprocessen; denne udgivelse fjerner den anden store blokering, men flytter ikke scanningen til en worker.

[1.238.2] — 2026-09-27

Rettelse af de 502, som produktionsserveren stadig viste under den timevise scanning.

Rettet

  • Sider og filer returnerede 502 under en scanning. Node lukker en inaktiv keep-alive-forbindelse efter 5 s; Caddy genbruger inaktive forbindelser i op til 2 minutter. Mens en scanning i processen holdt serveren optaget, lukkede Node sockets, som Caddy lige havde sendt en forespørgsel på, og Caddy svarede 502 connection reset by peer (62 gange under én scanning, mens serveren selv var sund). Serveren holder nu inaktive forbindelser i 125 s — længere end proxyen — så proxyen lukker altid først.

Tilføjet

  • deploy.yml → verify viser, hvorfor proxyen svarede 502 (fejltyper, adresser maskeret), 502 pr. minut siden sidste genstart og resultatet af den timevise scanning.
  • release.yml kan oprette et manglende tag, når den startes manuelt, så en udgivelse kan laves, hvor tags ikke kan pushes.
  • Tests 3486 → 3488.

Noter

  • Scanningen kører stadig inde i serverprocessen og kan holde den optaget i sekunder; at flytte den til en worker er ikke en del af denne rettelse.

[1.238.1] — 2026-09-27

Stabilitetsrettelse efter den første live-regression af produktionsserveren: én scanning ad gangen og rettelser på sitet.

Rettet

  • To scanninger på én gang fik serveren til at gå ned. Hvert GET /api/stream/scan kørte hele scanneren i serverprocessen uden beskyttelse; en scanning startet fra UI’et overlappede timeren hver time, og processen døde med JavaScript heap out of memory (to gange, med 502-fejl imens). Nu kører én scanning ad gangen: en anden forespørgsel får en SSE-error med koden SCAN_BUSY, og intet starter. Deploy-workflowet hæver også serverens hukommelsesgrænse (heap_mb, standard 448 MB).
  • /help og /changelog på cvstart.org scrollede sidelæns på telefoner (og ja/zh /changelog også på desktop): lang kode og indholdsfortegnelsen ombrydes nu.
  • Hindi manglede i sitemappets sprogalternativer; sitets i18n-tjek sammenligner nu sitemappet med sprogregistret.
  • Hjælp §19 bad om at tilføje en nøgle til „alle 8“ sprogfiler — der er 17.

Tilføjet

  • Fjern-regression (.github/workflows/remote-qa.yml): hver rute × hvert sprog i den udrullede app (kun læsning), hver side × sprog × telefon/desktop på cvstart.org, hvert link i README’erne og wikien og, på forespørgsel, en rigtig scanning plus live AI-kald på hvert sprog.
  • Server-deploy-workflow (.github/workflows/deploy.yml): recon, deploy (med byte-præcis tilbagerulning) og verify (røgtest og stabilitetsrapport).
  • Tests 3481 → 3486.

Noter

  • Scannerens eget hukommelsesforbrug reduceres ikke i denne udgivelse: beskyttelsen forhindrer to scanninger på én gang, og drop-in’en hæver loftet. Profilering af en rigtig scanning af 98 kilder kræver produktionsnetværket.
  • Timeren career-ops-scan hver time ændres ikke; recon viser nu, hvilke kommandoer den kører.

[1.238.0] — 2026-09-27

Forældre-paritet — career-ops main @ 993085ce (VERSION 1.34.0, 182 commits siden de2224a9). Fire nye kilder, ti spejlede leverandørrettelser, et scanner-bredt SSRF-hul lukket, og et gratis titel-fit-hint på scanresultater.

Tilføjet

  • Fire nye kilder — 94 → 98 (93 EN + 5 RU), 89 → 93 EN-adaptere.
    • Eploy (provider: eploy) — læser lejerens /live-jobs.xml-sitemap på enhver brandet host (kun HTTPS; IP-literaler, localhost, *.local, *.internal og enkeltdels-hosts afvises). Et ikke-sitemap-svar (en login-side) kaster fejl i stedet for at gå igennem som nul job. Detaljesider er opt-in (eploy: { fetchDetails, detailLimit }).
    • HiringRoom (*.hiringroom.com) — JSON-LD /portal/jobs først, med de gamle /jobs-kort som fallback; http://-opslags-URL’er i payloaden ombygges til HTTPS.
    • PeopleSoft Candidate Gateway — genkendes på stien /psc/{site}/EMPLOYEE/HRMS/c/HRS_HRAM_FL.HRS_CG_SEARCH_FL.GBL på enhver brandet host. Den følger selv PeopleSofts same-origin-sessionsredirects (maks. 10 hop, hvert hop re-pinnet til lejerens origin og tjekket mod private adresser), afspiller “load more”-formularen igen, og markerer en delvis gennemgang (peoplesoftIncomplete) frem for at rapportere den som fuldstændig.
    • PrevueAPS (*.prevueaps.ca) — finder site-id’et fra jobsiden og læser derefter JSON-API’et.
  • Titel-fit-hint på #/scan-rækker. Hvert resultat bærer en grov strong / related / weak fit-chip, der sammenligner opslagets titel med målrollerne i config/profile.yml (target_roles.primary + arketypenavne). Det er et gratis nøgleords-estimat: det filtrerer, omsorterer eller ændrer aldrig antal, og tooltippet siger det. Beregnes, når resultater serveres, så en profilrettelse ses ved næste opdatering. Oversat ×17. Spejler forælderens #3261.

Rettet

  • Sikkerhed — DNS-rebinding-vagten kørte aldrig på et rigtigt scan. http-json.mjs tjekkede kun de opløste adresser, når den fik den bare globale fetch, men begge scannere injicerer makeTimeoutFetch(), så hvert scan sprang det over. En kilde, der pegede på et hostnavn, der opløstes til 10.x eller 127.0.0.1, blev hentet. Vagten kører nu inde i selve makeTimeoutFetch, kapløbet mod scan-timeouten, så en gået-i-stå resolver ikke kan hænge et scan. Fundet i gennemgangen af denne udgivelse.
  • Sikkerhed — IPv6-adresser, der indlejrer en IPv4-adresse, blev ikke behandlet som private. http://[::ffff:127.0.0.1]/ (som URL-parseren omskriver til [::ffff:7f00:1]) slap igennem isValidJobUrl. Både den prikkede og den hexadecimale form af ::ffff:a.b.c.d / ::a.b.c.d klassificeres nu ud fra den indlejrede adresse. Forælderens _ip-guard.mjs.
  • Rippling flyttet til v2-board-API’et (ats.rippling.com/api/v2/board/<slug>/jobs), med paginering (standard 10 sider, maks. 50), en host-lås på joblinks, og slug-validering. En indsat API-URL giver nu sin rigtige slug i stedet for api.
  • Recruitee — multi-lokations-tilbud lister nu hvert sted (A · B), (Sample)-demo-opslag og titelløse rækker droppes, og et tilbud beholdes, hvis en af dets to URL’er er gyldig.
  • Pinpoint — udsåede demo-opslag (den fordoblede demo-video) droppes.
  • Telegram-kanaler — en første linje med flere | læses ikke længere som Title | Company, og flere rolleord genkendes. Forkens Cyrillic-bevidste LOCATIONISH_RE er urørt (ADR-0002).
  • Workday — en første-sides 422/401/403 sonderes én gang; Workdays vedligeholdelsesside eller outage-redirect markerer boardet dødt (karantæne i streng tilstand). CXS- og detalje-forespørgslerne nægter nu redirects.
  • BambooHR — en omdirigeret /careers/list triageres via det offentlige embed-feed: tomt betyder et levende board uden opslag, alt andet er et dødt board.
  • Heckler & Koch / Rheinmetall — et bart heckler-koch.com / rheinmetall.com omskrives til www., så no-redirect-transporten stadig når frem. Ashby nægter redirects. beesite pacer sider med den annullerbare delay().
  • Titelfiltre folder accenter på begge sider (EN- og RU-scannerne), så Développeur fanges af en developpeur-negativ.
  • Cooldown-firmamatch forstår ikke-latinske navne og selskabsformer (CJK/koreanske markører, tyrkisk prikket İ). CJK-navne kollapsede før til en tom nøgle og matchede aldrig.
  • location_filter.strict: true fejler lukket ved en tom lokation, når en tillad- eller blokliste er sat.
  • Liveness — nye public-API-tjek for Greenhouse-embeds (gh_jid), Arbeitsagentur og We Work Remotely; SmartRecruiters afgør nu ud fra opslagets active-flag.
  • PeopleSoft — en relativ “load more”-formularhandling opløses ved siden af søgesiden, ikke ved origin-roden.

Noter

  • Test 3210 → 3481. Nye suiter: sources-eploy, sources-hiringroom, sources-peoplesoft, sources-prevueaps, title-fit, fetch-timeout-dns-guard, cooldown-company-match-unicode, liveness-api-more-rungs, ru-scanner-title-accent-fold.
  • Ikke porteret, med begrundelser: location-filter Unicode-ordgrænser (web-ui’s filter er substring-baseret, så der er ingen grænse at rette — en bevidst fuld portering af forælderens location-filter er fremtidigt arbejde); samme-titel-requisition-dedup (web-ui dedupliserer kun på URL); aggregator-repost-advarsler, blacklist-domæneomfang, uverificerede-nul-kvitteringer og scan-runs.tsv-migrering (web-ui har ingen af disse flader); Workday facet-split og trunkeringstags (web-ui henter én side pr. board); BambooHR enrichDate (intet dato-berigelses-hook); forælderens _http.mjs sleep-refaktorering på tværs af ~20 udbydere (web-ui bruger allerede en delt annullerbar delay); updater, doctor, PDF, tracker/merge-tracker, validate-profile, discover-new-companies, web/ Next.js-appen, GitHub-bots — kun CLI eller relæet.
  • Bevidst holdt anderledes end forælderen: Heckler & Koch / Rheinmetall forbliver kun-HTTPS (ingen http→https-opgradering); et dødt Workday-board i et normalt scan returnerer stadig [] frem for at fejle scanet.

[1.237.1] — 2026-09-22

Patch fra et eksternt QA-gennemløb af v1.237.0. Jobstreet-rettelsen blev bekræftet udefra for første gang: på AU-, NZ-, HK- og MY-værterne returnerer den gamle /id/job/<id>-form en ren 404, og den nye /job/<id> når en ægte Cloudflare-beskyttet rute; på id.jobstreet.com gælder det modsatte. De mistede links var ægte. Der blev fundet to defekter, begge i det, v1.237.0 selv tilføjede.

Rettet

  • Bogens link-label var lokaliseret, men dets mål var det ikke. Alle 17 SPA-lokaliseringer og alle 17 cvstart.org-lokaliseringer pegede footer-linket til Agentic Coding Design Patterns på den engelske udgave, mens den ene oversatte label — russisk, «Паттерны агентного кодинга» — lovede en russisk bog. En ny data-i18n-href-applier (samme form som data-i18n-title, begrænset til absolutte https://-værdier) og en footer.patternsUrl-nøgle sender ru til den russiske udgave og enhver anden lokalisering til den engelske. Regressionstesten påstår invarianten i begge retninger: en oversat titel indebærer en lokaliseret URL.
  • SEEK migrerer værter, og transporten nægter redirects. www.seek.com.au → au.seek.com og www.seek.co.nz → nz.seek.com: detaljesiderne giver allerede 301, og begge værtspar leverer v5-søge-API’et med 200 i dag. Fordi http-json.mjs sætter redirect:'error' (et SSRF-forsvar, det er værd at beholde), ville den dag, API-stien begynder at redirecte en AU/NZ-post på den gamle vært, fejle — og med kun www.-værterne på allowlisten kunne ingen migrere. au.seek.com og nz.seek.com er nu i ALLOWED_JOBSTREET_HOSTS; de gamle værter forbliver, så eksisterende konfiguration og allerede byggede links fortsat virker. Look-alikes (au.seek.com.evil.com, au-seek.com) afvises stadig.
  • Wiki: rækken Agentic Practices i Home-dokumentationskortet var den eneste af tolv, der ikke escapede | inde i [[…|…]], så GitHub afskar cellen — dødt link, skjult beskrivelse. Ét tegn.

Noter

  • Antal uændret på 94 kilder (89 EN + 5 RU), 89 adaptere. Test 3201 → 3210 (+5 footer-link-lokalisering, +4 SEEK-værter).
  • Ikke lukkelig udefra, noteret snarere end hævdet: Oracle Cloud (Akamai blokerede begge REST-prober), Personio-fastgørelsen og appendWorkType (kræver en portals.yml-post, og UI’et har ingen sletning for én af dem), og liveness-strengtilfældene (ingen kontrollerbar side; 40 live-prober gav 12 live, 28 uafklarede, 0 falsk udløbne).
  • Hjælp ×17 lister nu begge værtsformer for AU-Main og NZ-Main. Overskriftsstruktur uændret på 32 H2 / 122 H3.

[1.237.0] — 2026-09-21

Forælder-paritet — career-ops main @ 93c4302b (VERSION 1.33.0, 75 commits hentet fra career-ops-hq/main). Ingen nye kilder denne gang: fire spejlede rettelser, og to af dem mistede opslag her, i stilhed.

Rettet

Jobstreet / SEEK — hvert australsk, newzealandsk, singaporeansk, malaysisk og Hongkong-opslag pegede på en død side. parseJobstreetItem byggede detalje-URL’en som ${baseUrl}/id/job/${id} betingelsesløst. /id/-segmentet er ikke en sti — det er det indonesiske lokale præfiks, og det findes kun på de indonesiske værter. Enhver anden SEEK-platform-vært svarer 404 på /id/job/<id>. web-ui havde allerede tilføjet www.seek.com.au, www.seek.co.nz, sg.jobstreet.com, my.jobstreet.com og hk.jobsdb.com til ALLOWED_JOBSTREET_HOSTS, så scanningen returnerede disse opslag uden videre — hvert eneste pegende på en 404. Stien er nu nøglet på værten: ID_LOCALE_HOSTS (id.jobstreet.com, www.jobstreet.co.id, jobstreet.co.id) beholder /id/job/, alt andet får /job/, og en ikke-parsebar oprindelse falder nu igennem til den fælles sti i stedet for at kaste en fejl. To af vores egne test havde indkodet fejlen — de påstod hk.jobsdb.com/id/job/… og www.jobstreet.com/id/job/… — og blev rettet. Oracle Cloud — en kort side midt i listen afsluttede gennemgangen og droppede resten af boardet. Stopbetingelsen var listLen === 0 || listLen < PAGE_SIZE, men ORC leverer færre rækker end grænsen midt i en liste, fordi visse rækker filtreres server-side. Målt opstrøms hos American Express: TotalJobsCount 454, sider på 200 / 199 / 54 — de 199 blev læst som slutningen, og de sidste 54 opslag, 12% af boardet, blev aldrig hentet. Nu afslutter en tom side altid gennemgangen; når tenanten rapporterer et samlet antal, fortsætter pagineringen, indtil offset + PAGE_SIZE >= total; kun en tenant uden et samlet antal at holde op imod afsluttes på en kort side. Dette følger den bredere konvention om, at et API »kan returnere færre resultater end det anmodede antal … selv når det ikke er ved slutningen af samlingen« (Google AIP-158). hasMore ignoreres fortsat bevidst — nogle tenants returnerer hasMore:false på hver eneste side af et board med 7000 job. Nu hvor korte sider ikke længere afslutter gennemgangen, er MAX_PAGES det eneste bagstop mod en tenant, der rapporterer et falsk samlet antal, så det er dækket af sin egen test. Liveness — "This role is closed" blev ikke genkendt, og en falsk udløbsstatus er permanent. Mønsteret var /this job (listing )?is closed/i, som overser de lige så almindelige formuleringer med role og position; på ét board opstrøms blev 111 af 111 usikre opslag målt med "role". Udvidet til /this (?:job|role|position)(?: listing)? is closed\b(?!-)/i. Den afsluttende \b(?!-) er en vagt mod sammensatte tillægsord: \b alene afviser closedown, men matcher stadig ægte prosa som “This role is closed-loop control of the platform”, og det er lookahead’en, der stopper det. Liveness — job expired ligger nu i et blødt lag, der ikke kan overtrumfe en synlig Apply-knap. HARD_EXPIRED_PATTERNS tjekkes før apply-kontrol-testen, så alt, der er placeret der, vinder over et aktivt opslag. /\bjob expired\b/i udløses fejlagtigt af fire ægte live-sideformer — en karruselpost under "Similar jobs", en filterknap "Hide job expired", en FAQ i bunden, og closed-loop-prosaen nævnt ovenfor — fordi klassifikatoren modtager hele sidens tekst. Mønsteret ligger nu i SOFT_EXPIRED_PATTERNS, tjekket efter apply-kontrollen og før heuristikken for opslagssider, og returnerer expired_body_soft; et rent "JOB EXPIRED"-banner uden apply-kontrol udløber stadig. Denne rækkefølge betyder noget, fordi en falsk expired skrives til scan-historikken som skipped_expired og derefter dedup-filtrerer et ægte job ud af hver senere scanning, på ubestemt tid, medmindre scan_history.recheck_after_days er sat.

Tilføjet

Personio — en eksplicit personio: <slug> fastgør tenanten. Mange virksomheder indlejrer deres Personio-board som en iframe på en brandet karriereside, så careers_url peger på virksomhedens eget domæne, mens feedet ligger på <slug>.jobs.personio.de; uden en fastgørelse løser disse boards sig til intet. Slug’en er tegnbegrænset af en forankret tilladelsesliste (/^[a-z0-9][a-z0-9-]{0,62}$/i), og den resulterende URL routes stadig gennem den eksisterende new URL()-parsing, HTTPS-tjek og PERSONIO_HOST_RE-værtsspærre — fastgørelsen er aldrig en vej til at nå en anden vært. En slug, der bærer ., /, @, :, .., mellemrum, en indledende -, eller overskrider DNS-labelgrænsen på 63 tegn, falder igennem til dagens api/careers_url-adfærd. I modsætning til forælderen er web-ui’s værts-regex versalfølsom, så fastgørelsen normaliseres gennem new URL() — AcmeGroup resolves til acmegroup.jobs.personio.de i stedet for at opbygge en vært, som dens egen tilladelsesliste derefter ville afvise. Jobstreet — tilvalgt appendWorkType tilføjer opslagets arbejdstyper som suffiks til titlen, f.eks. Strategy Consultant [Part time], så titelfiltre og triage kan se ansættelsestypen allerede ved scanningstidspunktet. Slået fra som standard; en manglende eller tom workTypes er en no-op.

Noter

Kilde- og adapterantal er uændret: 94 kilder (89 EN + 5 RU), 89 EN-adaptere. Denne udgivelse flytter kun testantallet, 3164 → 3201 (+13 jobstreet, +7 Oracle Cloud, +9 liveness, +8 Personio). Forælderen slettede providers/telegram.mjs, og konsoliderede på telegram-channel. web-ui registrerer begge som brugervendte kilder, så sletningen følges ikke: den ville sænke registret fra 94 til 93 og stiltiende ødelægge det for enhver, der har telegram konfigureret. Genovervejes kun som en bevidst, annonceret fjernelse. jd-skill-gap.mjs fik en ikke-sammentrukket overskriftsform for "what we are looking for" og en strip af fed-markører. web-ui relayer dette script i stedet for at spejle det, så rettelsen ankommer sammen med den udrullede forælder og kræver ingen ændring her. Ikke porteret, med begrundelser: lib/latex-escape.mjs, browser-extract.mjs, openai-eval.mjs, update-system.mjs og scaffolderen (web-ui hverken spejler eller kalder ud til dem); Go-dashboardets TUI og web/-konfigurationsformularen (separate flader); doctor.mjs og analyze-patterns.mjs (skrivebeskyttede relæer, hvis fail-soft-adfærd absorberer ændringen). Forkets kyrilliske \p{L}-afvigelse i providers/telegram-channel.mjs overlevede upstream-sammenfletningen intakt og blev verificeret byte-for-byte mod en kopi fra før sammenfletningen.

[1.236.0] — 2026-09-18

Forælder-paritet — career-ops main @ 6a9c84c (VERSION 1.33.0, 128 commits). To nye kilder, og tre spejlede rettelser — to af dem mistede opslag her, i stilhed.

Tilføjet

To scanner-kilder, 92 → 94 (89 EN + 5 RU). Python.org Jobs (pythonorg) læser boardets offentlige feed; arbejdsgiverattribution er obligatorisk, så en række, hvis titel ikke navngiver nogen arbejdsgiver, droppes i stedet for at blive udfyldt bagudrettet med portalindgangens navn. Generalist World (generalist-world) skraber boardets kort og fejler højlydt ved markup, den ikke kan parse — en kortform, der har ændret sig, kaster en fejl i stedet for at blive læst som et tomt board, hvilket er den fejltilstand, der gør en skrabet kilde utroværdig. Begge optræder i #/scans Kilde-filter, begge er vært-fastgjort (forankret regex, kun HTTPS), og begge er drevet ende-til-ende af testpakker med falsk transport (43 og 36 tilfælde).

Rettet

En Workday-stilling åben i flere byer blev droppet af et lokationsfilter. Workdays liste-endpoint besvarer et opslag med flere lokationer med et antal, hvor hvert andet opslag bærer et sted: "53 Locations". Det er ikke en lokation, og buildLocationFilter matcher ved understreng uden hensyn til store/små bogstaver — så en stilling åben i Austin og 52 andre byer matchede ingen allow: [austin]-post og blev kasseret, mens den samme stilling opført enkeltvis slap igennem. Målt opstrøms på tværs af tre tenants: 53 af 291 opslag var pladsholdere, så dette er standardtilfældet, ikke et randtilfælde. Opslagets reelle steder findes kun i CXS-detalje-dokumentet, så hver pladsholder koster nu én ekstra GET mod det, med et loft på 200 pr. post — over loftet forbliver pladsholderen synlig i stedet for at blive forfalsket, fordi et uafklaret opslag aldrig må læses som et afklaret. En fejlet eller stedløs detalje efterlader opslaget præcis, som listen returnerede det: en synlig "53 Locations" er ærlig om det, der ikke kunne afklares, hvorimod en tømt lokation stiltiende ville bestå ethvert filter. Den samme GET bærer også startDate, så et beriget opslag dateres præcist i stedet for via liste-endpointets relative prosa ("Posted 30+ Days Ago" → undefined); alt, der ikke er en ren YYYY-MM-DD, lades urørt i stedet for at blive kørt gennem Date.parse, hvis ikke-ISO-fallback er implementeringsafhængig. Et angivet niveau kollapser ikke længere to rekvisitioner til ét genopslag. "Insurance Specialist II" er arbejdsgiverens egen udtalelse om, at denne rekvisition ikke er søskende med den anden — et andet lønbånd, omfang og rekvisitionsnummer under én grundtitel. Tokenizeren kunne ikke se det: w.length > 3 dropper hvert romertal op til VIII og hvert enkeltciffer, så "Insurance Specialist" og "Insurance Specialist II" blev tokeniseret identisk, scorede et perfekt Jaccard-forhold, og genopslagsdetektoren markerede den anden som en genudbydelse af den første. web-ui’s role-matcher.mjs havde slet ingen niveauhåndtering, så dette bringer forælderens hele mekanisme med: niveauer udtrækkes med romerske og arabiske tal foldet til ét tal ("Nurse II" og "Nurse 2" er samme udtalelse — og det par adskilte sig forkert før), to angivne niveauer skal stemme overens, og et niveau kun på den ene side behandles som en løs omskrivning medmindre hver titel også bærer et ord, den anden mangler, hvilket er to uoverensstemmelser snarere end en udsmykning. Et Avature-board fastgjort til et filter gennemgik alligevel hele det globale board. Avatures søge-UI genererer uigennemsigtige facet-parametre (?42386=[812132] er et landefilter), og en operatør, der fastgør et indsnævret board i portals.yml, forventer, at scanningen gennemgår det. resolveSearch genopbyggede URL’en som ${origin}${path} og droppede forespørgselsstrengen fuldstændigt — så hver forespørgsel, inklusive den første, gennemgik tenantens hele board: flere sider, flere forespørgsler og opslag, som operatøren bevidst havde filtreret fra. Facetter følger nu med i hver pagineret forespørgsel, med vores egen jobOffset anvendt sidst, så en tilfældig facet med samme navn aldrig kan kapre pagineringen.

Sikkerhed

devalue 5.8.1 → 5.9.2 (transitivt via astro), som lukker den ene åbne Dependabot-advarsel — et lammelsesangreb ved fejlformet input. Kun en site-afhængighed; ingen runtime-kode ændret.

Noter

Ikke porteret, hver med sin begrundelse. Forælderen gav lever en timeout på 30 sek. og manfred 25 sek. mod dens fælles standard på 10 sek. — en ikke-portering: web-ui’s scan-transport tillader allerede 60 sek. (DEFAULT_SCAN_TIMEOUT_MS), så begge boards har mere spillerum her, end rettelsen giver der. iCIMS’ fordoblede careers--præfiks kan heller ikke opstå her: web-ui tager tenant-origin direkte fra api/careers_url og konstruerer aldrig en vært ud fra et tenant-navn; dens nye fallback-vært-gennemgang er en funktion til forælderens løsere konfiguration, ikke en fejlrettelse. deutschebahn og manfred fik retry-ved-forbigående-afbrydelse, hvilket web-ui’s loft på 60 sek. gør langt mindre presserende — noteret snarere end porteret, så en fremtidig timeout ved lang gennemgang har et kendt første sted at prøve. Alt andet i de 128 commits’ delta er CLI, verifier, dashboard eller web/ (forælderens eget frontend): liveness-browser, check-jd-archive, verify-ats/verify-portals/verify-cv-facts, update-system, set-status, audit-portals, discover-ats, scaffolder, test-all, plugin-manifester. Forkets afvigelser genbekræftet efter pull’et: den kyrilliske \p{L}-rettelse i providers/telegram-channel.mjs, forkets egen providers/telegram.mjs, hermes i web/src/lib/clis.ts. Upstream career-ops-hq/main er fuldt flettet (0 commits mangler). 3066 → 3164 test; hjælpen angiver nu 94 adaptere (89 EN + 5 RU) i alle 17 bundler, og overskriftsstrukturen er uændret på 32 H2 / 122 H3.

[1.235.0] — 2026-09-16

Forælder-paritet — career-ops main @ 68e6b94 (VERSION 1.33.0, 42 commits). To spejlede rettelser; den ene mistede MokaHR-opslag her, i stilhed.

Rettet

Et andet job fra samme MokaHR-board forsvandt i stedet for at blive tilføjet. url-key.mjs reducerer en opslags-URL til en sammenligningsnøgle, og den droppede fragmentet betingelsesløst — rimeligt nok, siden næsten hvert fragment kun er præsentation (#apply, #section-2). MokaHR er undtagelsen i vores eget register: dens opslag er …/social-recruitment/{tenant}/{id}#/job/{n}, hvor hvert job hos en tenant deler stien, og opslags-id’et findes kun i fragmentet. Så de blev alle normaliseret til én nøgle. Målt før rettelsen: indsæt to forskellige MokaHR-job i pipelinen, og du ender med én linje — ingen fejl, ingen advarsel, intet at bemærke; scannerens friskhedsfilter (en-scanner.mjs) læser samme nøgle, så så snart ét job fra den tenant var i scan-historikken, blev alle de andre kasseret som »allerede set«. normalizeUrl løfter nu en genkendt #/job/{id}- eller #/jobs/{id}-rute op i en ren sammenligningsnøgle i forespørgslen, før fragmentet droppes — MokaHR beholder sit etablerede navn mokahr_job_id, så tidligere skrevne nøgler forbliver sammenlignelige, mens enhver anden vært får et internt _career_ops_fragment_job_id. Det løftede id bliver tilføjet, ikke sat: en URL, der allerede bærer den parameter, bærer et andet opslags id, og at overskrive den ville lægge sammen præcis det, nøglen findes for at holde adskilt. Ethvert ikke-genkendt fragment kollapser stadig, hvilket er den halvdel, der allerede var korrekt. accept-encoding er nu fastlåst på hver kilde-forespørgsel. Uspecificeret forhandler Node, hvad dens undici-build tilbyder; fra Node ≥ 23 inkluderer det zstd, og amazon.jobs’ zstd-svar kommer tilbage afkortet ved præcis 1024 byte med status 200 — så fejlen læses som Unterminated string in JSON at position 1024, som et misdannet API snarere end en transportfejl. Hver forespørgsel sender nu gzip, deflate, br. På vores runtimes er dette forebyggende, ikke en reparation: Node 18/20/22 — CI-matrixen og serveren (22.22.1) — sender gzip, deflate, verificeret direkte frem for antaget, så intet blev afkortet her; det, der ændrer sig i dag, er, at br bliver tilbudt, hvilket de versioner ikke anmoder om som standard, men afkoder korrekt. Standarden anvendes uden hensyn til store/små bogstaver, hvilket er den del, der er værd at gennemgå: header-navne skelner ikke mellem store og små bogstaver, og fetch sammenføjer to enslydende felter til én kommasepareret værdi, så en kaldende part, der sender Accept-Encoding: identity, ellers ville have fået sendt gzip, deflate, br, identity.

Noter

Headers forbliver et almindeligt objekt ved fetchImpl-grænsen, hvor forælderen giver fetch en Headers-instans. Det er en bevidst afvigelse, ikke en forglemmelse: web-ui’s fetch-hjælpefunktioner tager en injicerbar fetchImpl, og 45 kilde-testpakker læser opts.headers['User-Agent'] af det, de opfanger — en Headers-instans har ingen adgang med klammer, så den tro portering er af adfærden (tilsidesættelse uden hensyn til store/små bogstaver, kaldende part vinder) snarere end af implementeringen. Den kaldende parts objekt kopieres, aldrig muteres, da flere kilder deler én header-konstant. Forælderens ledsagende rettelse — at anvende en standard-user-agent uden hensyn til store/små bogstaver — er en ikke-portering: web-ui injicerer slet ingen standard-UA, hver kilde sætter den, dens board kræver, så der er ingen standard for en kaldende parts User-Agent at kollidere med. To nye testpakker og tre nye tilfælde fastlåser parret: tests/http-accept-encoding.test.mjs (den præcise fastlåste værdi, hver af de fire fetch-hjælpefunktioner, og en tilsidesættelse fra kaldende part under tre stavemåder med store/små bogstaver — der bekræfter, at én enkelt accept-encoding-nøgle overlever, hvilket er, hvad sammenfletningsfejlen producerede to af) og tests/parsers-pipeline-hash-route.test.mjs, som arbejder med den brugersynlige sømlinje snarere end nøglen: to MokaHR-job skal begge nå pipelinen, en gen-indsættelse af det samme under fire stavemåder skal stadig kollapse til én linje, og et kosmetisk fragment må ikke blive til en identitet. Alle blev bekræftet fejlende først. Selve fastlåsningen bor i transporten, ikke kun i de hjælpere: 25 af de 92 kilder kalder den indsprøjtede fetchImpl direkte og passerer dem aldrig, så makeTimeoutFetch — den wrapper begge scannere faktisk indsprøjter — anvender den, og det er det ene gennemgangspunkt alle kilder deler. (Forælderen har ikke brug for en pendant: providers/_http.mjs er dens eneste transport.) En strukturel vagt fælder nu CI, hvis en ny kilde kalder fetch direkte i stedet for at bruge den transport, den fik rakt, og et adfærdstilfælde kører greenhouse — en af de 25 — gennem wrapperen og beviser, at headeren når ud på ledningen. Ikke porteret, med begrundelsen: liveness-browser.mjs (genbrugsvagt for headed Playwright — web-ui kører ikke en headed browser), check-jd-archive.mjs (ingen web-ui-relæ), test-all.mjs (forælderens eget testrammeværk; forkets egen vpFixtureEnv-afvigelse er intakt), web/ (forælderens eget frontend, spejles ikke), plugin-manifester og SIGNATURES.md (kun repository). batch/batch-runner.sh (og-tegn escaped før sed-interpolation) og jd-skill-gap.mjs (løser cv.md op mod dataroden) er relæet skrivebeskyttet — web-ui shell’er ud til forælderens egne kopier, så begge lander uden kodeændring her, og jd-skill-gap-ændringen gør /api/jds/:id/skill-gap-relæet mere korrekt: cv.md løses nu op fra dataroden i stedet for hvilken som helst mappe, processen blev startet fra. Forkets afvigelser genbekræftet efter pull’et: den kyrilliske \p{L}-rettelse i providers/telegram-channel.mjs, forkets egen providers/telegram.mjs, hermes i web/src/lib/clis.ts. Antallet af kilder er uændret på 92 (87 EN + 5 RU), så hjælpen er urørt. 3042 → 3066 test.

[1.234.0] — 2026-09-15

Forælder-paritet — career-ops main @ 56cce8f (VERSION stadig 1.32.0, 58 commits forbi 1.32.0). Én spejlet rettelse på tværs af 15 kilder, plus en vagt, så den ikke kan komme tilbage.

Rettet

Ét enkelt fejlformet job-id tømmer ikke længere hele siden. encodeURIComponent kaster URIError ved en enlig UTF-16-surrogat, og et JSON-payload kan bære én — JSON.parse('"\\uD800"') bevarer den. Femten kilder byggede hvert opslags URL ud fra et vært-styret id eller slug inde i parse-løkken, så ét dårligt opslag afbrød løkken og mistede alle job på den side; intet blev logget som en kilde-fejl, fordi undtagelsen rullede tilbage, før virksomhedens egen catch havde noget at rapportere. Forælderen rettede det i providers/_safe-url.mjs (safeEncodeURIComponent → null ved URIError, kaster alt andet videre) og lod hver løkkes id gå igennem den, så kun det ene opslag droppes ved null. Den hjælpefunktion er nu server/lib/sources/_safe-url.mjs, og samme ændring er anvendt på de tretten spejlede kilder — alibaba, arbeitsagentur, bamboohr, feishu-jobs, garena, jibeapply, manfred, meituan, mokahr, phenom, thehub, tkms, vdab — og på to kilder, der kun findes i web-ui, og som den nye vagt afslørede ved sin første kørsel, jobstreet og trudvsem, som havde samme løkkeform og samme latente kast. Omfanget er bevidst: kun API-hentede id’er går gennem hjælpefunktionen. Konfigurationsafledte værdier beholder deres strenge encode og fejler højlydt — garenas office (et portals.yml-segment) bliver på den kastende urlSegment, mens dens API-id får en null-returnerende idUrlSegment; csods corpName og 4dayweeks SLUG_RE-validerede slug er navngivet på en tilladelsesliste med begrundelsen. rheinmetalls titel-fallback kunne kaste en fejl ved en fejlformet href. Når et kort ikke har nogen overskrift, genopbygges titlen fra URL-sluggen via decodeURIComponent, som kaster en fejl ved en ugyldig procent-sekvens i det skrabede href — samme mønster, hvor én dårlig række dræber hele siden, blot på afkodningssiden. Den afkoder nu defensivt og falder tilbage til den rå slug. Kilderegistret springer filer med _-præfiks over. Auto-opdagelsen importerede hver .mjs-fil i server/lib/sources/ undtagen sig selv og advarede om alt uden export const meta — så hjælpefunktionen udløste en advarsel ved opstart. Forælderens konvention er nu overtaget: et indledende underscore betyder ikke en kilde; sådanne filer bliver hverken importeret eller udløser en advarsel. En ikke-deklareret fil uden meta udløser stadig en advarsel, og opdagelsestesten bekræfter nu begge halvdele (bekræftet rød mod det gamle filter). Sitets build-script sync-assets.mjs tæller adapterfiler på disken efter samme regel, så hjælperen ikke længere udløser dets vagt mod stille frafald.

Noter

tests/sources-url-encoding-surrogate.test.mjs spejler forælderens testpakke i tre dele: hjælpefunktionens kontrakt (et parret surrogat — en almindelig emoji — encoder stadig; et kast fra værdiens egen toString er den kaldendes egen fejl og forplanter sig), pr.-kilde-adfærd for alle femten (ét dårligt id + ét rent id → intet kast, det rene bevares, det dårlige droppes, hver drevet gennem kildens eksporterede rene parser eller, for thehub, dens fetcher med en falsk transport), og en kilde-niveau-vagt: hver konverteret fil skal både importere hjælpefunktionen og kalde den, ingen fil må referere til den uden at importere den, og ingen ikke-gennemgået fil må bygge en job-URL med et bart encodeURIComponent — en ny kilde med den gamle form fejler i CI med linjenummeret på den pågældende linje. Alle femten pr.-kilde-tilfælde blev bekræftet fejlende før porteringen. Alt andet i forælderens delta er ikke porteret, med begrundelsen: batch/batch-runner.sh --cli er et rent CLI-flag (web-ui shell’er ikke ud til batch-runneren); invite-match.mjs finder nu set-status.mjs fra kodens rod — web-ui relayer den ikke; company-funded.mjs fik den samme safe-url-ændring internt, og dens --json-outputform, som /api/company-funded parser, er uændret; test-all.mjs flyttede kun et timeout-budget (forkets egen vpFixtureEnv-afvigelse er intakt); web/ er forælderens eget frontend og spejles ikke; AGENTS.md/SIGNATURES.md er kun repository. Forkets afvigelser genbekræftet efter pull’et: den kyrilliske \p{L}-rettelse i providers/telegram-channel.mjs, forkets egen providers/telegram.mjs, hermes i web/src/lib/clis.ts. Antallet af kilder er uændret på 92 (87 EN + 5 RU), så hjælpen er urørt. 3022 → 3042 test.

[1.233.2] — 2026-09-10

Rettet — to CodeQL-advarsler js/remote-property-injection af høj alvorlighed.

Rettet

Løkken, der kopierer gemte værdier til process.env, gik gennem Object.entries(safe) — et objekt bygget af request-body’en — med en eksplicit vagt mod prototype-nøgler indeni. Koden var sikker, da safe kun fyldes fra KNOWN_KEYS, men analysatoren kan ikke følge den begrænsning på tværs af to løkker. Nu går den direkte gennem det konstante array, så egenskabsnavnet beviseligt er et modul-literal. Adfærden er identisk.

Noter

Testen, der fastholdt den gamle vagt, var et grep i kildeteksten. Erstattet af en strukturel og en adfærdstest, der sender __proto__ som rå JSON. 3021 → 3022 test.

[1.233.1] — 2026-09-10

Rettet — vejledningen beskrev ikke det element, v1.233.0 tilføjede, og samme afsnit bar stadig instruktioner, der har været forkerte i 200 udgivelser.

Rettet

DOC-1 — posten »Brug standardværdien (…)« udtrykker tilstanden »nøglen er ikke sat«; forskellen fra at vælge samme værdi udtrykkeligt er usynlig og betydningsfuld. Tre punkter i den eksisterende ### Behavior-liste ×17. DOC-2 — en tabelrække nævnte slet ingen nøgle: cellen indeholdt (server uses default UA), som beskrev HH_USER_AGENT, fjernet i v1.19.0, og rådede til registrering på dev.hh.ru — nytteløst siden v1.65.0. Alle tre forældede omtaler er væk; fejlfindingsrækken er omskrevet: siden juli 2026 svarer hh.ru HTTP 451 til ikke-russiske IP’er. Nøgletabellen viser 6 af 45, mens overskriften lover et register. Én sætning ×17 kalder den et udvalg og henviser til #/config.

Noter

Den nye help-recognized-keys.test.mjs holder første kolonne i nøgletabellerne op mod den levende KNOWN_KEYS. 3018 → 3021 test; hjælpen bliver på 32 H2 / 122 H3.

[1.233.0] — 2026-09-10

Rettet — tre fund i gemmestien for #/config; CONFIG-3 blev forårsaget af rettelsen i v1.232.1 selv.

Rettet

CONFIG-3 — et bevidst valg, der tilfældigvis svarede til den forudfyldte værdi, blev kasseret som »ikke rørt«. initial blander to ophav: forudfyldt fra .env og forudfyldt fra defaultValue, hvor lighed er flertydig. Rettet ved at notere seededFromFile ved siden af initial. Fjernelse af en nøgle meldte »· 0«, fordi serveren kun returnerede det skrevne. Nu svarer den også med removed, og beskeden tæller begge. En rulleliste kunne sættes, men aldrig ryddes: ingen af de 18 havde en tom mulighed. Hver begynder nu med »Brug standardværdien (…)«. Én ny i18n-nøgle ×17.

Noter

Unit-baseline uændret (3018); browser 111 → 116.

[1.232.1] — 2026-09-10

Rettet — Gem på #/config skrev felter, brugeren aldrig rørte.

Rettet

CONFIG-2. v1.57.1 forudfylder et uindstillet felt med dets defaultValue, så feltet viser det, serveren rent faktisk bruger, mens save() kun spurgte dirty for hemmeligheder og altid sendte alle øvrige felter. Værdien lagt der til VISNING rejste dermed som brugerens valg: én ændret rulleliste sendte 28 nøgler og fastlåste 18, ingen havde åbnet. Det, der ændrer sig, er hver indstillings status — fra »ikke sat, følg projektets standard« til »låst i .env«.

Noter

At sammenligne med cfg.values er ikke nok: et uindstillet select viser sin defaultValue, mens den gemte værdi er ''. Nu sammenlignes der med det, hvert felt blev fyldt med. Antallet af skrevne nøgler er tilbage i beskeden. 105 → 111 browsertest.

[1.232.0] — 2026-09-09

Rettet — to defekter fra en browser-QA-gennemgang; ingen af dem stammer fra v1.231.5.

Rettet

PROFILE-1 — #/profile rullede hele siden sidelæns. Værdien var et anonymt <div> med kun inline skriftstile, så dens beregnede overflow-wrap forblev normal. En LinkedIn-URL giver CSS intet lovligt brudpunkt, så min-content-bredden er hele strengen, og min-width: auto på gitterelementer nægter at krympe under den — kortet sprængte sit spor, rækken og dokumentet (23 px reel rulning ved 1280 px). Rettet med en fælles .card-value-klasse med overflow-wrap: anywhere plus .card-row > * { min-width: 0 }. anywhere, ikke break-word: kun anywhere tælles med i min-content. CONFIG-1 — POST /api/config accepterede enhver værdi i et select-felt. {"LLM_PROVIDER":"not-a-provider"} gav 200 og blev skrevet i .env; derefter fejlede intet, for resolveren faldt stille tilbage. LLM_PROVIDERS blev allerede eksporteret fra env-config.mjs — validatoren slog bare aldrig op i den.

Noter

Kun LLM_PROVIDER valideres: modellernes reelle domæne tilhører leverandøren og ændrer sig mellem vores udgivelser. En allerede gemt værdi tolereres, da formularen sender alle ikke-hemmelige felter ved hver gemning. Deskriptoren for OLLAMA_API_KEY er også tilføjet. 3013 → 3018 test.

[1.231.5] — 2026-09-09

Sikkerhed — syv rådgivninger lukket, én af dem en kritisk fjernkørsel af kode. Ingen kildefil blev ændret.

Sikkerhed

Flettet fra Dependabot: multer 2.2.0 → 2.3.0 (høj — lammelsesangreb via lækkede fildeskriptorer ved afbrydelse) og svgo 4.0.2 → 4.1.0 på sitet (høj og middel — removeScripts slap eksekverbare links igennem). Derefter fem mere, som den genskanning fletningerne udløste, bragte frem. Hvert berørt interval var allerede dækket af det eksisterende ^, så der skulle en opdatering til, ikke en manifestændring: astro 7.1.0 → 7.3.2 — kritisk, fjernkørsel af kode via AVIF-billedoptimering (rettet i 7.2.8) samt en autorisationsomgåelse (7.2.4); sharp 0.35.3 → 0.35.4 — høj, libheif-sårbarheder; og js-yaml 4.3.1 → 4.3.2 i begge manifester — høj.

Noter

»Kun afhængigheder« er ikke det samme som »uden risiko« her. js-yaml parser hver konfiguration, appen læser, multer modtager hver upload, og Astro rykkede en minor-version. Verificeret: test:ci 3013/3013, browser-suiten 4/4, og en fuld genopbygning af sitet med de samme 86 sider og alle 17 spejle. npm audit: 0 sårbarheder.


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