Dziennik zmian
GitHubKażda istotna zmiana, wydanie po wydaniu. Ten sam plik jest dostępny w repozytorium i przetłumaczony na wszystkie 19 języków.
[1.235.0] — 2026-09-16
Parytet z rodzicem — career-ops main @ 68e6b94 (VERSION 1.33.0, 42 commity). Dwie odzwierciedlone poprawki; jedna z nich po cichu gubiła tutaj oferty z MokaHR.
Naprawiono
Druga oferta z tej samej tablicy MokaHR znikała, zamiast zostać dodana. url-key.mjs redukuje URL oferty do klucza porównawczego i bezwarunkowo odrzucał fragment — rozsądne, bo niemal każdy fragment służy tylko prezentacji (#apply, #section-2). MokaHR jest wyjątkiem w naszym własnym rejestrze: jej oferty mają postać …/social-recruitment/{tenant}/{id}#/job/{n}, gdzie każda oferta danego najemcy dzieli tę samą ścieżkę, a identyfikator oferty istnieje wyłącznie we fragmencie. Wszystkie normalizowały się więc do jednego klucza. Zmierzone przed poprawką: wklej do pipeline’u dwie różne oferty z MokaHR, a skończysz z jedną linią — bez błędu, bez ostrzeżenia, bez niczego do zauważenia; filtr świeżości skanera (en-scanner.mjs) czyta ten sam klucz, więc gdy tylko jedna oferta danego najemcy trafiła do historii skanowania, każda kolejna była odrzucana jako „już widziana”. normalizeUrl teraz promuje rozpoznaną trasę #/job/{id} lub #/jobs/{id} na klucz zapytania służący wyłącznie do porównania, zanim fragment zostanie odrzucony — MokaHR zachowuje swoją ustaloną nazwę mokahr_job_id, dzięki czemu wcześniej zapisane klucze pozostają porównywalne, a każdy inny host dostaje wewnętrzny _career_ops_fragment_job_id. Promowany identyfikator jest dopisywany, a nie ustawiany: URL, który już niesie ten parametr, zawiera identyfikator innej oferty, a nadpisanie go scaliłoby dokładnie te dwie rzeczy, które klucz ma za zadanie rozdzielać. Każdy nierozpoznany fragment nadal się zwija, co jest tą połową, która już wcześniej działała poprawnie.
accept-encoding jest teraz przypięty w każdym żądaniu do źródła. Pozostawiony bez ustawienia, Node negocjuje to, co oferuje jego wbudowany undici; od Node ≥ 23 obejmuje to zstd, a odpowiedź zstd z amazon.jobs wraca ucięta dokładnie na 1024 bajtach ze statusem 200 — więc błąd wygląda jak Unterminated string in JSON at position 1024, czyli jak zniekształcone API, a nie usterka transportu. Każde żądanie wysyła teraz gzip, deflate, br. Na naszych środowiskach uruchomieniowych jest to działanie prewencyjne, nie naprawa: Node 18/20/22 — macierz CI oraz serwer (22.22.1) — wysyłają gzip, deflate, co zweryfikowano wprost, a nie jedynie założono, więc nic tutaj nie zostało ucięte; to, co zmienia się dzisiaj, to fakt, że oferowane jest br, którego te wersje domyślnie nie żądają, ale poprawnie dekodują. Wartość domyślna stosowana jest bez rozróżniania wielkości liter, co jest częścią wartą uwagi: nazwy nagłówków nie rozróżniają wielkości liter, a fetch łączy dwa wpisy o tej samej nazwie w jedną wartość rozdzieloną przecinkami, więc wywołujący przekazujący Accept-Encoding: identity inaczej otrzymałby wysłane gzip, deflate, br, identity.
Uwagi
Nagłówki pozostają zwykłym obiektem na granicy fetchImpl, tam gdzie rodzic przekazuje do fetch instancję Headers. To celowa rozbieżność, nie przeoczenie: pomocnicy fetch w web-ui przyjmują wstrzykiwalny fetchImpl, a 45 zestawów testowych źródeł czyta opts.headers['User-Agent'] z tego, co przechwytują — instancja Headers nie ma dostępu przez nawiasy kwadratowe, więc wiernie przeniesione jest zachowanie (nadpisanie bez rozróżniania wielkości liter, wygrywa wywołujący), a nie implementacja. Obiekt wywołującego jest kopiowany, nigdy mutowany, bo kilka źródeł dzieli jedną stałą nagłówków. Towarzysząca poprawka rodzica — stosowanie domyślnego user-agenta bez rozróżniania wielkości liter — to brak portu: web-ui w ogóle nie wstrzykuje domyślnego UA, każde źródło ustawia ten, którego wymaga jego tablica ofert, więc nie ma domyślnej wartości, z którą mógłby się zderzyć User-Agent wywołującego.
Dwa nowe zestawy testów i trzy nowe przypadki utrwalają tę parę: tests/http-accept-encoding.test.mjs (dokładna przypięta wartość, każdy z czterech pomocników fetch oraz nadpisanie przez wywołującego w trzech wariantach wielkości liter — sprawdzające, że przetrwa pojedynczy klucz accept-encoding, którego błąd scalania produkował dwa) oraz tests/parsers-pipeline-hash-route.test.mjs, który testuje widoczny dla użytkownika szew, a nie sam klucz: dwie oferty z MokaHR muszą obie dotrzeć do pipeline’u, ponowne wklejenie tej samej oferty w czterech zapisach musi nadal zwinąć się do jednej linii, a kosmetyczny fragment nie może stać się tożsamością. Wszystkie potwierdzono jako zawodzące przed poprawką. Samo przypięcie żyje w transporcie, a nie tylko w tych helperach: 25 z 92 źródeł wywołuje wstrzyknięty fetchImpl bezpośrednio i w ogóle przez nie nie przechodzi, więc stosuje je makeTimeoutFetch — opakowanie, które oba skanery faktycznie wstrzykują — a to jedyny punkt przejścia wspólny dla wszystkich źródeł. (Rodzic nie potrzebuje odpowiednika: providers/_http.mjs jest jego jedynym transportem.) Strukturalna straż wywraca teraz CI, jeśli nowe źródło wywoła fetch bezpośrednio zamiast użyć przekazanego mu transportu, a przypadek behawioralny przepuszcza greenhouse — jedno z tych 25 — przez opakowanie i dowodzi, że nagłówek trafia na łącze.
Nieportowane, z podanym powodem: liveness-browser.mjs (strażnik ponownego użycia headed-Playwright — web-ui nie steruje przeglądarką z widocznym interfejsem), check-jd-archive.mjs (web-ui nie ma dla niego przekaźnika), test-all.mjs (uprząż testowa rodzica; rozbieżność forka vpFixtureEnv pozostaje nietknięta), web/ (własny frontend rodzica, nieodzwierciedlany), manifesty pluginów oraz SIGNATURES.md (tylko-repozytoryjne). batch/batch-runner.sh (znaki & escapowane przed interpolacją w sed) oraz jd-skill-gap.mjs (rozwiązuje cv.md względem korzenia danych) są przekazywane dalej tylko do odczytu — web-ui wywołuje przez powłokę kopie rodzica, więc oba trafiają tu bez zmiany kodu, a ta z jd-skill-gap czyni przekaźnik /api/jds/:id/skill-gap poprawniejszym: cv.md rozwiązuje się teraz względem korzenia danych, a nie dowolnego katalogu, z którego uruchomiono proces. Rozbieżności forka ponownie zweryfikowane po pobraniu: cyrylicka poprawka \p{L} w providers/telegram-channel.mjs, własny providers/telegram.mjs forka, hermes w web/src/lib/clis.ts. Liczba źródeł niezmieniona na 92 (87 EN + 5 RU), więc pomoc pozostaje nietknięta. 3042 → 3066 testów.
[1.234.0] — 2026-09-15
Parytet z rodzicem — career-ops main @ 56cce8f (VERSION wciąż 1.32.0, 58 commitów po 1.32.0). Jedna odzwierciedlona poprawka w 15 źródłach oraz strażnik, by nie mogła wrócić.
Naprawiono
Jeden źle sformowany identyfikator oferty przestaje czyścić całą stronę. encodeURIComponent rzuca URIError na osamotnionym surogacie UTF-16, a ładunek JSON może go nieść — JSON.parse('"\\uD800"') go zachowuje. Piętnaście źródeł budowało URL każdej oferty z identyfikatora lub sluga kontrolowanego przez hosta wewnątrz pętli parsowania, więc jedna zła oferta przerywała pętlę i traciła wszystkie oferty z tej strony; nic nie było logowane jako błąd źródła, bo wyjątek rozwijał się, zanim catch per-firma zdążył cokolwiek zgłosić. Rodzic naprawił to w providers/_safe-url.mjs (safeEncodeURIComponent → null przy URIError, wszystko inne rzuca dalej) i przepuścił przez niego identyfikator z każdej pętli, odrzucając tylko jedną ofertę przy null. Ten pomocnik to teraz server/lib/sources/_safe-url.mjs, a ta sama zmiana zastosowana jest do trzynastu odzwierciedlonych źródeł — alibaba, arbeitsagentur, bamboohr, feishu-jobs, garena, jibeapply, manfred, meituan, mokahr, phenom, thehub, tkms, vdab — oraz do dwóch źródeł istniejących tylko w web-ui, które nowy strażnik ujawnił przy pierwszym uruchomieniu, jobstreet i trudvsem, mających ten sam kształt pętli i to samo utajone rzucanie wyjątku. Zakres jest celowy: przez pomocnika przechodzą tylko identyfikatory pochodzące z API. Wartości pochodzące z konfiguracji zachowują swoje ścisłe kodowanie i głośno zawodzą — office w garenie (segment portals.yml) zostaje przy rzucającym urlSegment, podczas gdy jej id z API dostaje zwracający null idUrlSegment; corpName w csod oraz slug w 4dayweek, zwalidowany przez SLUG_RE, są dopuszczone po nazwie z podanym powodem.
Zapasowy tytuł w rheinmetall mógł rzucić wyjątek na źle sformowanym href. Gdy karta nie ma nagłówka, tytuł jest odtwarzany ze sluga URL przez decodeURIComponent, który rzuca wyjątek na złej sekwencji procentowej w zescrapowanym href — ten sam kształt „jeden zły wiersz zabija stronę”, tym razem po stronie dekodowania. Teraz dekoduje defensywnie i wraca do surowego sluga.
Rejestr źródeł pomija pliki z prefiksem _. Automatyczne wykrywanie importowało każdy .mjs w server/lib/sources/ poza samym sobą i ostrzegało o każdym pliku bez export const meta — więc pomocnik generował ostrzeżenie już przy starcie. Przyjęto konwencję rodzica: wiodący podkreślnik oznacza nie-źródło; takie pliki nie są ani importowane, ani sygnalizowane ostrzeżeniem. Niezadeklarowany plik bez meta nadal ostrzega, a test wykrywania sprawdza teraz obie połowy (potwierdzony jako czerwony wobec starego filtra). Skrypt budowania witryny sync-assets.mjs liczy pliki adapterów na dysku według tej samej reguły, więc helper nie uruchamia już jego zabezpieczenia przed cichą utratą źródła.
Uwagi
tests/sources-url-encoding-surrogate.test.mjs odzwierciedla zestaw rodzica w trzech częściach: kontrakt pomocnika (para surogatów — zwykłe emoji — nadal się koduje; rzut z własnego toString wartości to błąd wywołującego i propaguje się dalej), zachowanie per-źródło dla wszystkich piętnastu (jeden zły identyfikator + jeden czysty identyfikator → brak rzutu, czysty zachowany, zły odrzucony, każdy przepuszczony przez eksportowany czysty parser źródła lub, dla thehub, przez jego fetcher z fałszywym transportem) oraz strażnik na poziomie źródła: każdy przekonwertowany plik musi importować pomocnika i go wywoływać, żaden plik nie może się do niego odwoływać bez importu, a żaden nieprzejrzany plik nie może budować URL-a oferty gołym encodeURIComponent — nowe źródło o starym kształcie zawodzi CI z numerem winnej linii. Wszystkie piętnaście przypadków per-źródło potwierdzono jako zawodzące przed portem.
Reszta różnic rodzica nie jest portowana, z podanym powodem: batch/batch-runner.sh --cli to flaga tylko dla CLI (web-ui nie wywołuje przez powłokę batch-runnera); invite-match.mjs rozwiązuje teraz set-status.mjs od korzenia kodu — web-ui go nie przekazuje dalej; company-funded.mjs otrzymał tę samą zmianę safe-url wewnętrznie, a kształt jego wyjścia --json, parsowany przez /api/company-funded, jest niezmieniony; test-all.mjs przesunął tylko budżet limitu czasu (rozbieżność forka vpFixtureEnv pozostaje nietknięta); web/ to własny frontend rodzica i nie jest odzwierciedlany; AGENTS.md/SIGNATURES.md są tylko-repozytoryjne. Rozbieżności forka ponownie zweryfikowane po pobraniu: cyrylicka poprawka \p{L} w providers/telegram-channel.mjs, własny providers/telegram.mjs forka, hermes w web/src/lib/clis.ts. Liczba źródeł niezmieniona na 92 (87 EN + 5 RU), więc pomoc pozostaje nietknięta. 3022 → 3042 testów.
[1.233.2] — 2026-09-10
Naprawiono — dwa alerty CodeQL js/remote-property-injection o wysokiej wadze.
Naprawiono
Pętla przenosząca zapisane wartości do process.env iterowała Object.entries(safe) — obiekt zbudowany z ciała żądania — ze strażnikiem przeciw kluczom prototypu w środku. Kod był bezpieczny, bo safe wypełniany jest wyłącznie z KNOWN_KEYS, ale analizator nie przeniesie tego ograniczenia przez dwie pętle. Teraz iteruje stałą tablicę, więc nazwa właściwości jest dowodliwie literałem modułu. Zachowanie identyczne.
Uwagi
Test utrwalający starego strażnika był grepem po tekście źródła. Zastąpiony strukturalnym i behawioralnym, który wysyła __proto__ jako surowy JSON. 3021 → 3022 testów.
[1.233.1] — 2026-09-10
Naprawiono — przewodnik nie opisywał kontrolki dodanej w v1.233.0, a ta sama sekcja wciąż niosła instrukcje nieprawdziwe od 200 wydań.
Naprawiono
DOC-1 — pozycja „Użyj wartości domyślnej (…)” wyraża stan „klucz nieustawiony”; różnica wobec jawnego wyboru tej samej wartości jest niewidoczna i istotna. Trzy punkty w istniejącej liście ### Behavior ×17.
DOC-2 — wiersz tabeli nie nazywał żadnego klucza: w komórce stało (server uses default UA), opisujące HH_USER_AGENT usunięty w v1.19.0, i radziło rejestrację na dev.hh.ru — bezużyteczną od v1.65.0. Wszystkie trzy przestarzałe wzmianki zniknęły; wiersz rozwiązywania problemów przepisano: od lipca 2026 hh.ru zwraca HTTP 451 nierosyjskim IP.
Tabela kluczy wymienia 6 z 45, choć nagłówek obiecuje rejestr. Jedno zdanie ×17 nazywa ją wyborem i wskazuje #/config.
Uwagi
Nowy help-recognized-keys.test.mjs porównuje pierwszą kolumnę tabel kluczy z żywym KNOWN_KEYS. 3018 → 3021 testów; pomoc pozostaje 32 H2 / 122 H3.
[1.233.0] — 2026-09-10
Naprawiono — trzy ustalenia w ścieżce zapisu #/config; CONFIG-3 wywołała sama poprawka z v1.232.1.
Naprawiono
CONFIG-3 — świadomy wybór zgodny z zasianą wartością był odrzucany jako „nietknięty”. initial miesza dwa pochodzenia: zasiew z .env i zasiew z defaultValue, a w drugim przypadku równość jest niejednoznaczna. Naprawione przez zapisanie seededFromFile obok initial.
Usunięcie klucza pokazywało „· 0”, bo serwer zwracał tylko zapisane. Teraz zwraca także removed, a powiadomienie liczy oba.
Listę rozwijaną można było ustawić, ale nie wyczyścić: żadna z 18 nie miała pustej opcji. Każda zaczyna się teraz od „Użyj wartości domyślnej (…)“. Jeden nowy klucz i18n ×17.
Uwagi
Baza testów jednostkowych bez zmian (3018); przeglądarkowe 111 → 116.
[1.232.1] — 2026-09-10
Naprawiono — Zapis na #/config zapisywał pola, których użytkownik nie dotknął.
Naprawiono
CONFIG-2. v1.57.1 zasiewa nieustawiony kontrolkę jej defaultValue, by pole pokazywało to, czego serwer faktycznie używa, natomiast save() pytał dirty tylko dla sekretów i zawsze wysyłał wszystkie pozostałe pola. Wartość wstawiona do POKAZANIA szła więc jako wybór użytkownika: zmiana jednej listy wysyłała 28 kluczy i przypinała 18 nigdy nieotwartych. Zmienia się status ustawienia — z „nieustawione, idź za domyślnym” na „przypięte w .env“.
Uwagi
Porównanie z cfg.values nie wystarcza: nieustawiony select pokazuje swój defaultValue, a zapisana wartość to ''. Teraz porównujemy z tym, czym zasiano każdą kontrolkę. Liczba zapisanych kluczy wróciła do powiadomienia. 105 → 111 testów przeglądarkowych.
[1.232.0] — 2026-09-09
Naprawiono — dwie usterki z przeglądarkowego przebiegu QA; żadna nie pochodzi z v1.231.5.
Naprawiono
PROFILE-1 — #/profile przewijał całą stronę w bok. Wartość była anonimowym <div> wyłącznie ze stylami czcionki, więc overflow-wrap pozostawał normal. URL LinkedIn nie daje CSS żadnego dozwolonego miejsca podziału, zatem szerokość min-content to cały ciąg, a min-width: auto w elementach siatki nie pozwala zejść niżej — karta rozsadziła ścieżkę, wiersz i dokument (23 px realnego przewijania przy 1280 px). Naprawione wspólną klasą .card-value z overflow-wrap: anywhere oraz .card-row > * { min-width: 0 }. anywhere, nie break-word: tylko anywhere liczy się przy obliczaniu min-content.
CONFIG-1 — POST /api/config przyjmował dowolną wartość pola select. {"LLM_PROVIDER":"not-a-provider"} zwracał 200 i trafiał do .env; potem nic nie zawodziło, bo resolver po cichu schodził do wartości zapasowej. LLM_PROVIDERS był już eksportowany z env-config.mjs — walidator po prostu z niego nie korzystał.
Uwagi
Sprawdzany jest tylko LLM_PROVIDER: prawdziwa dziedzina modeli należy do dostawcy i zmienia się między naszymi wydaniami. Wartość już zapisana jest tolerowana, bo formularz odsyła wszystkie pola niebędące sekretami przy każdym zapisie. Dodano też deskryptor OLLAMA_API_KEY. 3013 → 3018 testów.
[1.231.5] — 2026-09-09
Bezpieczeństwo — zamknięto siedem zgłoszeń, w tym krytyczne zdalne wykonanie kodu. Żaden plik źródłowy nie uległ zmianie.
Bezpieczeństwo
Scalone z Dependabota: multer 2.2.0 → 2.3.0 (wysokie — odmowa usługi przez wyciek deskryptorów plików przy przerwaniu) oraz svgo 4.0.2 → 4.1.0 w witrynie (wysokie i średnie — removeScripts przepuszczał wykonywalne odnośniki).
Następnie pięć kolejnych, ujawnionych przez ponowne skanowanie. Każdy dotknięty zakres mieścił się już w istniejącym ^, więc wystarczyła aktualizacja: astro 7.1.0 → 7.3.2 — krytyczne, zdalne wykonanie kodu przez optymalizację obrazów AVIF (naprawione w 7.2.8) oraz obejście autoryzacji (7.2.4); sharp 0.35.3 → 0.35.4 — wysokie, luki libheif; i js-yaml 4.3.1 → 4.3.2 w obu manifestach — wysokie.
Uwagi
„Tylko zależności” nie znaczy tu „bez ryzyka”. js-yaml parsuje każdą konfigurację, multer przyjmuje każde przesłanie, a Astro przeskoczyło wersję pomniejszą. Zweryfikowano: test:ci 3013/3013, zestaw przeglądarkowy 4/4, pełna przebudowa witryny z tymi samymi 86 stronami i 17 kopiami. npm audit: 0 podatności.
[1.231.4] — 2026-09-07
Naprawiono — v1.231.3 naprawiło skutek kliknięcia Doctor, a nie sam moment. Zgłoszone ponownie, z telefonu i z pulpitu.
Naprawiono
withSpinner wciąż przepisywał przycisk w trakcie żądania. v1.231.3 kazało mu zapisywać węzły dzieci i przywracać je w finally — i wracały, ale sygnał zajętości nadal wykonywał replaceChildren z tekstem '⏳ ' + original. Przez cały czas działania doctor.mjs kwadrat 36 px zawierał więc ⏳ 🩺Doctor i stawał się szeroką pigułką łamiącą wiersz; na pulpicie wyglądało to jak zbite ⏳🩺Doctor. Przycisk mający dzieci-elementy nie jest już w ogóle przepisywany: jego sygnałem jest klasa .is-loading, która teraz zamienia ikonę na klepsydrę w CSS, więc geometria nie może się zmienić: 36 px w spoczynku, 36 px w locie, 36 px po.
Uwagi
Lekcja dotyczy asercji, nie kodu. Bramka z v1.231.3 czekała na zniknięcie aria-busy i dopiero wtedy mierzyła — z definicji widziała tylko stan już naprawiony przez finally. Nowe sprawdzenie samo trzyma obietnicę otwartą i pobiera próbkę w połowie lotu. 3012 → 3013 testów.
[1.231.3] — 2026-09-07
Naprawiono — kliknięcie Doctor psuło górny pasek na telefonie. Zgłoszone z telefonu w dniu wydania v1.231.2.
Naprawiono
UI.withSpinner spłaszczał dzieci przycisku, który właśnie ozdabiał. Sygnał zajętości szedł przez textContent: zapisz button.textContent, wpisz '⏳ ' + original, wpisz z powrotem. Przypisanie do textContent zastępuje wszystkie dzieci jednym węzłem tekstowym — a v1.231.2 dopiero co podzieliło każdą akcję górnego paska na .btn-ico i .btn-label, chowając etykietę pod max-width: 900px. Pierwsze dotknięcie Doctor niszczyło więc oba <span> na dobre: reguły mobilne nie miały już czego dopasować, etykieta wracała jako goły tekst, a kwadrat 36 px rozrastał się w pigułkę 🩺Doctor nachodzącą na przełącznik motywu. Nie goiło się samo — tylko przeładowanie strony przywracało znaczniki. Poprawka zapisuje węzły dzieci i przywraca je przez replaceChildren; przyciski czysto tekstowe, czyli większość z 24 miejsc wywołania, zachowują się dokładnie jak wcześniej.
- FIND-3 — pole wyszukiwania zapadło się do 8 px na telefonie 320 px. Ustawiając pasek w jednym wierszu, zostawiłem searchbar jako jedyny element elastyczny, a poprzedni changelog wprost to zapisał: „może skurczyć się do zera”. I skurczył się: 8 px pola przy 320 px, 28 px przy 340 px — jeden znak z dwudziestojednoznakowej podpowiedzi. Klikalne i zapisywalne, ale nieczytelne jako pole. Żaden
min-widthnie pomoże: przy 320 px pasek trzyma 32 px dopełnienia, 40 px menu i 162 px akcji, bez 120 px do oddania. Dlatego poniżej 420 px pole chowa się za lupą i po dotknięciu rozwija na cały pasek: 182 px przy 320 px, 222 px przy 360 px, 252 px przy 390 px, bez przepełnienia na żadnej szerokości. Przycisk zachowuje jedną nazwę dostępną i zgłasza stan przezaria-expanded, a zamiana 🔍/✕ to czysty CSS. Powyżej 420 px nic się nie zmienia. Znalezione przeglądarkowym przebiegiem regresyjnym na żywej kompilacji.
Uwagi
To ta sama klasa usterki co pułapka applyI18n() odnotowana w v1.231.2 — kod przypisujący textContent elementowi, który ma już dzieci-elementy — osiągnięta przez innego wywołującego. Wniosek się uogólnia: podzielenie treści elementu na dzieci <span> zamienia każdego istniejącego pisarza textContent na tym elemencie w utajony błąd.
Zablokowane dwukrotnie: node:vm na prawdziwym withSpinner i kliknięcie w prawdziwej przeglądarce przy 320 px. Oba potwierdzono jako padające na starym kodzie. 3009 → 3012 testów.
[1.231.2] — 2026-09-06
Naprawiono — mobilny górny pasek łamał się na dwa wiersze, serwer działał na starszym projekcie nadrzędnym, a przekierowanie cvstart.ru dawało 404 dla każdej ścieżki, która już nazywała język.
Naprawiono
- Mobilny górny pasek znów mieści się w jednym wierszu, akcje tylko ikonami. Przyciski akcji były wypychane do drugiego wiersza na całą szerokość: telefon pokazywał
[☰ · szukaj]nad[🔔 🌙 Doctor Otwórz Scan]— dwie szerokie pigułki we własnym wierszu. Teraz to kwadraty 36 px (🩺 / ⚡) obok dzwonka i przełącznika motywu, a przy 320 px wszystko mieści się w jednym wierszu. Zmierzone, nie oszacowane na oko: szerokość dokumentu równa się widocznemu obszarowi przy 320, 360, 390 i 430 px oraz w całym paśmie 560–760 px, gdzie wcześniej przyciski nachodziły na pole wyszukiwania. Język nie wpływa już na układ mobilny, bo etykieta jest ukryta, a przycisk to stały kwadrat; powyżej 900 px etykiety wracają bez zmian. - Serwer działał na projekcie nadrzędnym 1.31.0, choć wydanie zbudowano pod 1.32.0.
/api/healthna serwerze produkcyjnym zgłaszałparentVersion: 1.31.0. Zsynchronizowano 95 plików wykonawczych, dwa usunięto. Wykryte przez QA w przeglądarce na powierzchni produkcyjnej. cvstart.rudodawał/ru/do każdej ścieżki, nie patrząc, co już tam było./ru/helpstawało się/ru/ru/help, a/en/help—/ru/en/help; oba 404. Pierwsze to efekt skopiowania adresu z głównej witryny; drugie całkowicie odcinało anglojęzycznego odwiedzającego od wersji angielskiej. Teraz ścieżka nazywająca już jeden z 16 prefiksów przechodzi bez zmian,enjest usuwane (angielski jest w katalogu głównym), reszta nadal dostaje/ru/.
Zmieniono
- 98 nieaktualnych promptów QA przeniesiono do
qa/archive/superseded-prompts/.qa/README.mddokumentuje od v1.137.0, że na górnym poziomie zostaje tylko prompt bieżącego wydania — reguły nie stosowano przez 95 wydań. - Kolejnych pięć promptów opuściło najwyższy poziom — ogłaszały się aktualnymi, nie będąc nimi.
REGRESSION-FINAL.mdnazywał siebie „jedynym autorytatywnym, niezależnym od wersji promptem regresyjnym”, ale jego §§11–15 to pięć zamkniętych rejestrów cykli (v1.55.x → v1.59.7), a deklarowana podstawa pomocy brzmiała 28 H2 / 103 H3 na 16 języków wobec 32 / 122 i 17 dzisiaj: agent QA idący za nim poległby na §9 już w pierwszym kroku.QA-REGRESSION-PROMPT.mdmiał nazwę bez wersji i treść z v1.226.0.QA-REGRESSION-PROMPT-v1.76.0-FULL.mdbył przypięty 155 wydań wstecz,REGRESSION-PROMPT-FINAL.mdzamyka cykl v1.58.52 → v1.59.10, aQA-FULL-REGRESSION.mdpowielał je wszystkie na podstawie v1.131.1. Razem z nimi poszedłPARENT-SYNC-WORKLIST-v1.26.0.md(projekt nadrzędny jest już na 1.32.0), a datowanyUX-AUDIT-2026-07-06.mdprzeniósł się doreports/. Zostały cztery sterowniki, z podstawami odświeżonymi do faktycznych wartości v1.231.2.qa/README.mdnapisano na nowo, tak by opisywał katalog, który istnieje.
Uwagi
- Dwie pułapki specyficzności opisano teraz w
app.css: reguły desktopowe są zadeklarowane niżej niż blokmax-width: 900px, więc przy równej specyficzności wygrywają — mobilnygappo cichu został 24 px (co przelewało 320 px), a ikona pozostała ukryta (puste kwadratowe przyciski). applyI18n()przypisujeel.textContent, więc klucz i18n przeniósł się do wewnętrznego<span>; na przycisku kasowałby ikonę przy każdej zmianie języka.- Pierwszy rsync projektu nadrzędnego przerwał się w połowie na pliku, którego już nie ma lokalnie, i mimo to zgłosił sukces. Wdrożenia nadrzędnego weryfikuje się teraz sumą kontrolną, nigdy kodem wyjścia.
[1.231.1] — 2026-09-06
Poprawiono — przemiatanie liczników z v1.231.0 przepisało nazwę konta we wszystkich odnośnikach.
Naprawiono
- Każdy odnośnik
Fighter90stał sięFighter92. Przemiatanie licznika źródeł w v1.231.0 zamieniało90na92pod strażą granicy cyfry, która poprawnie pomija290i901, ale trafia w90wewnątrzFighter90. 562 odnośniki we wszystkich 17 README, wszystkich 17 pakietach pomocy i lustrach pomocy na stronie, plus 138 w wiki, prowadziły do nieistniejącego konta. Zauważył użytkownik — po brakującym obrazku. - Pięć historycznych odwołań do wydań przesunęło się. Przemiatanie
85 → 87zmieniłov1.85.0wv1.87.0, wymyślając wydanie, którego nigdy nie było.
Uwagi
- Granica cyfry nie wystarcza: chroni liczbę przed sąsiednimi cyframi, a nie przed byciem częścią identyfikatora albo łańcucha wersji. Same liczniki są poprawne: 92 źródła, 87 adapterów EN, 3009 testów.
- Repozytorium nadrzędne nie ucierpiało.
[1.231.0] — 2026-09-05
Dodano — dwa źródła skanowania z nadrzędnego career-ops v1.32.0 (Collage, Telegram ścisły), tryb REST w Gem oraz wadę, którą port wydobył w kodzie samego projektu nadrzędnego.
Dodano
- Dwa nowe źródła, 90 → 92 (87 EN + 5 RU),
ALL_ADAPTERS85 → 87. Oba bez tokenu.- Collage (
provider: collage) — publiczne API stron ofert Collage HR. Segment ścieżki to adres strony, który najemca sam wybrał, a nie slug z nazwy firmy: czytany jest zapi:albo z adresusecure.collage.co/jobs/<adres>i nigdy nie zgadywany — zgadnięty adres oznaczałby skanowanie cudzej tablicy. - Telegram (ścisły) (
provider: telegram-channel) — czyta te same podglądyt.me/s/<kanał>co istniejące źródłotelegram, ale robi odwrotny kompromis: post staje się wierszem tylko wtedy, gdy nazywa pracodawcę I linkuje do strony oferty. Zbiorcze posty, posty z ukrytym pracodawcą i posty wyłącznie kontaktowe są odrzucane. Niskie pokrycie z założenia — powyżej zmierzono 32-77% przechodzących postów — ale każdy wiersz niesie prawdziwego pracodawcę i prawdziwy link. Oba są dostarczane, tak jak w projekcie nadrzędnym.
- Collage (
- Gem zyskał opcjonalny tryb REST obok ścieżki GraphQL (
api: https://api.gem.com/job_board/v0/<board>/job_posts). Nigdy nie jest wyprowadzany z identyfikatora tablicy, a ścieżka GraphQL pozostaje domyślna. Przeniesione z #3783.
Naprawiono
- Filtr lokalizacji w
telegram-channelnie widział cyrylicy i nazywał miasta pracodawcami.LOCATIONISH_REw projekcie nadrzędnym używał\b, granicy wyłącznie ASCII, która nigdy nie zadziała obok cyrylicy: wszystkie rosyjskie warianty były nieosiągalne, aSenior Engineer | Москваzwracał „Москва” jako pracodawcę. To dokładnie ta podmiana pola, której cała polityka atrybucji ma zapobiegać, i uderzała w główną grupę odbiorców dostawcy. Port web-ui używa sprawdzeń Unicode, tych samych, które projekt nadrzędny stosuje stałą niżej wROLE_WORD_RE. Utrwalone testem, który przy formie ASCII zawodzi. Powyżej jeszcze nie poprawione.
Uwagi
- Odzyskiwanie Workday przez fasety w projekcie nadrzędnym (#3851, #3874) nie wymagało portu — web-ui w ogóle nie stronicuje Workday, jeden POST przy
offset: 0. providers/_types.jszmienił się wyłącznie w dokumentacji.- Testy: 2962 → 3009 (+47).
[1.230.0] — 2026-09-05
Zmieniono — trzy poprawki dostawców z nadrzędnego career-ops v1.32.0 oraz jedna wada, którą sam port wydobył na wierzch.
Dodano
- Welcome to the Jungle przyjmuje serwerowe wyrażenie
filtersAlgolii (wttj: { filters: "offices.country_code:FR AND contract_type:full_time" }). Samo słowo kluczowe nie zawęża globalnej tablicy: o tym, któremax_hitswyników wróci, decyduje ranking trafności Algolii, a nie filtry skanera — nasze działają dopiero potem, na tym, co już przyszło, więc wszystko poza limitem jest niewidoczne, choćby pasowało doskonale. Filtr zmniejsza sam zbiór, zamiast go przestawiać, dlatego limit na zapytanie rośnie z 200 do 1000. Przy filtrzequeriesstaje się opcjonalne: puste zapytanie znaczy „wszystko, co przejdzie filtr”. Przeniesione z projektu nadrzędnego #3757.
Naprawiono
- Radancy nie ostrzega już „truncated”, gdy najemca po prostu udostępnia mniej ofert, niż głosi jego własny baner. Projekt nadrzędny zestawił
data-total-resultsz dziewięcioma rzeczywistymi najemcami: pięciu się zgadzało, ale czterej — jeden mały i jeden ogromny — wydali o 10–56% mniej unikalnych ofert, niż ogłaszali, bez ani jednego duplikatu. Baner zawyża to, co indeks wyszukiwania najemcy naprawdę serwuje, więc porównywanie z nim narastającego licznika dawało fałszywy alarm na większości tablic. Ostrzeżenie pojawia się teraz wyłącznie wtedy, gdy przejście zatrzymał nasz własnymax_jobs/max_pages— jedyny przypadek, na który wywołujący może zareagować;totalResultszostaje w komunikacie jako kontekst i nigdy nie decyduje. Przeniesione z #3839. - Radancy omija pamięć podręczną przy każdym żądaniu fragmentu JSON. Warstwa cache przed tą trasą u części najemców odtwarza nieaktualne odpowiedzi: ta sama oferta wraca kilka stron później, a inna nie pojawia się wcale — odtworzone dziewięć razy na dziewięć w górę strumienia. Nagłówki
Cache-Control/Pragmanic nie zmieniły; losowy parametr na żądanie naprawił problem. Musi być unikalny na wywołanie, nigdy wyprowadzony z numeru strony: parametr deterministyczny wciąż dałby pamięci podręcznej stabilny klucz, a więc to samo stabilne, błędne odwzorowanie. Przeniesione z #3839. - Listy biur Greenhouse mają porządek deterministyczny. Greenhouse nie obiecuje kolejności
offices[]między odpowiedziami, a zbiór odtworzony z drzewa/officesidzie w kolejności obchodu. Oba trafiają do polalocationoferty, więc tablica przestawiająca swoje biura przepisywała ten łańcuch — i niezmieniona oferta czytała się jak nowa. Projekt nadrzędny poprawił zbiór (#3839); web-ui miał drugie wystąpienie tej samej wady, którego tam nie ma — awaryjneoffices[0], używane gdy oferta nie niesie własnej lokalizacji — i oba są teraz posortowane.
Uwagi
- Poprawka iCIMS (#3728) nie wymagała portu. Czyta wszystkie wpisy
jobLocationz JSON-LD strony szczegółów, bo część najemców umieszcza wpis w całościUNAVAILABLEprzed prawdziwym adresem. iCIMS w web-ui bierze lokalizację z HTML strony listy i nigdy nie otwiera strony szczegółów. - Zmiana w
_http.mjsnie wymagała portu. WydzielaisRefusedRedirectErrordla drugiego konsumenta, którego web-ui nie ma; zachowanieisRetryableErrorbez zmian. - Deduplikacja uwzględniająca lokalizację (#3751) nie jest odzwierciedlana — mieszka w potoku
scan.mjsnadrzędnego CLI. - Rejestr bez zmian: 90 źródeł (85 EN + 5 RU). Testy: 2956 → 2962 (+6).
[1.229.0] — 2026-09-03
Dodano — cztery źródła skanowania z nadrzędnego career-ops v1.31.0: Built In, Feishu Jobs, Garena i MokaHR.
Dodano
- Cztery nowe źródła, 86 → 90 (85 EN + 5 RU),
ALL_ADAPTERS81 → 85, wszystkie bez tokenów. Built In obejmuje dziewięć rynków amerykańskiej tablicy technologicznej i nie niesie domyślnego zapytania: wpis bezqueries:icategories:nic nie skanuje i mówi o tym wprost, bo wspólne źródło nie może nieść czyichś słów kluczowych; rynek spoza listy jest odrzucany, nigdy po cichu zastępowany tablicą krajową. Feishu Jobs przyjmuje dokładnie dwie formy hosta, a używają one różnych ścieżek do strony oferty. Garena to jedna firma:officekształtuje link, nie listę. MokaHR zwraca zaszyfrowaną odpowiedź (koperta AES-128-CBC z kluczem obok) — to zaciemnienie, nie zabezpieczenie, ale bez odszyfrowania nic się nie odczyta.
Naprawiono
htmlToTextmógł przepuścić do tekstu niedomknięty znacznik otwierający.safe <img src=x onerror=1wychodziło jakosafe <img src=x onerror=1. Teraz po każdym dekodowaniu następuje czyszczenie, a końcowy znacznik traci nawias. Przeniesione z projektu nadrzędnego (#3491).
Uwagi
- Z poprawki Workday nie przeniesiono nic. Ratuje ona dzierżawców, u których backend blokuje paginację na offsecie 2000 — web-ui w ogóle nie paginuje Workday (jeden POST na
offset: 0, 100 wierszy). - Poprawki
verify-cv-factsimerge-trackernie wymagały przeniesienia: web-ui uruchamia te skrypty z checkoutu projektu nadrzędnego. - Testy: 2909 → 2956 (+47).
[1.228.5] — 2026-08-30
Naprawiono — zgłaszana wersja opisywała plik na dysku, a nie uruchomiony kod.
Naprawiono
-
/api/healthodczytywałpackage.jsonprzy każdym żądaniu, więc przestarzały proces zgłaszał wersję, której nie uruchamiał. QA znalazł lokalną instancję odpowiadającąversion: 1.228.4i jednocześnie zwracającą 404 dla/api/ping— trasy dodanej w 1.228.3: uruchomiona przed wdrożeniem, serwowała stary kod i zgłaszała wersję nowego pliku. Dokładnie tak wygląda wdrożenie, które skopiowało pliki i nigdy nie zrestartowało procesu: jedyny ciąg, który sprawdza operator, to ten, który nie może zobaczyć problemu. Ta sama klasa co dowiązanie z v1.228.1, gdzie rsync przerywał transfer i mimo to zgłaszał sukces.Wersja jest teraz przechwytywana przy ładowaniu modułu, więc opisuje uruchomiony kod. Przestarzały proces zgłasza starą wersję — prawdę, widoczną natychmiast.
parentVersionpozostaje odczytywany na żądanie: opisuje checkout projektu nadrzędnego, którego ten proces nie ładuje i który może legalnie zmienić się pod działającym serwerem.
[1.228.4] — 2026-08-30
Naprawiono — nieuwierzytelniona sonda żywotności wykonywała pracę dyskową przy każdym żądaniu.
Naprawiono
GET /api/pingczytał i parsowałpackage.jsonprzy każdym trafieniu. To jedyny punkt osiągalny bez poświadczeń, więc odczyt z dysku plus parsowanie JSON na żądanie to dźwignia odmowy usługi wręczona każdemu — CodeQL oznaczył to jako brak ograniczania częstości. Wersja jest teraz czytana raz przy rejestracji trasy; bez restartu i tak nie może się zmienić, więc handler nie wykonuje żadnego I/O. Ograniczanie częstości ograniczyłoby szkody; usunięcie pracy usuwa dźwignię.- Maskowanie prawdziwego nazwiska właściciela profilu poza loopbackiem jest teraz przypięte testem.
/api/healthjuż zastępował je przezhidden, ale tylko dlatego, że ten wiersz dzieli strażnikahidden ?? valuez korzeniem projektu. Nic tego nie sprawdzało — edycja nadająca wierszowi własną wartość wyciekłaby nazwisko realnej osoby do sieci lokalnej niezauważona.
[1.228.3] — 2026-08-30
Fixed — the docs assistant could not answer in English, Telegram company names arrived truncated, and a monitor had no way to see the service was up.
Fixed
-
The docs assistant answered “no matching help sections were found” in English while the same question worked in Russian. Retrieval was fine; the context builder was not.
buildAskPromptdidif (ctx.length + sec.body.length > MAX_CONTEXT) break— abreak, so one oversized section ended the loop and left the context empty, and the assistant truthfully reported it had nothing. The English §5 had grown to 16 081 bytes against a 14 336-byte budget (partly because v1.228.0 addedtelegram_channelsto it); the Russian §5 was 13 009 and fit. Same ranking in both languages — §5 was first — only the size differed.Two changes: a section past 6 KB is now split at its
###boundaries, sotelegram_channelsis its own retrievable chunk (1 340 bytes) that ranks first in both languages; and an oversized section is skipped or truncated rather than ending the loop. The guide went from 32 chunks to 75. -
A Telegram company label yielded the sentence after it, not the name.
Компания: FinCore Technology (продуктовая разработка, высоконагруженные системы)becameFinCore Technology (продуктовая разработка, высоконагруженны— capped at 60 characters, cut mid-word. Three of 141 rows. The name now ends at the first separator that introduces a description — a spaced dash (soCoca-Colasurvives), a comma, semicolon, pipe or opening parenthesis — and any remaining cap falls on a word boundary. This source attributes a company as fact; a truncated sentence is as wrong as a guessed name, only less obviously so.
Added
GET /api/ping— a liveness probe that leaks nothing.{ ok, version }and no more./api/healthreports absolute paths, the profile owner’s real name and which API keys are set: legitimate for an authenticated operator, never for the public internet. A monitor behind a Basic-auth gate previously had no way to see the service was up at all.
[1.228.2] — 2026-08-30
Fixed — a two-word search in /api/scan-results matched the phrase, not the words, and under-reported badly.
Fixed
-
?q=now matches every term independently instead of the literal phrase. The query was a singleincludes(q)over title + company + location, soпродакт менеджерfound only rows carrying those two words in that exact adjacency — 32 of the 162 that carry both.Менеджер продуктаandМенеджер по развитию продуктаwere invisible to it: the same words, reordered or with filler between them.This is how a narrow match becomes a wrong answer. The Telegram assistant asked for all Продуктовый менеджер reported 9 — faithfully, because 9 was what the endpoint said. The count it quoted was honest; the endpoint’s was not. Word order and the words between are not something a person typing two words intended to pin.
Matching is AND across terms, so widening precision costs nothing: a row must still carry every term.
менеджер разработчикreturns zero rather than the union.
[1.228.1] — 2026-08-29
Fixed — a dangling symlink in the repo that silently truncated deploys.
Fixed
-
.claude/skills/refero-designwas a tracked symlink to a path that has never existed here. It pointed at../../.agents/skills/refero-design, which resolves to.agents/at the repo root; there is no such directory, and the link arrived in the v1.118.0 parity pack from a machine where the surrounding folders nested differently. Anyone cloning the repo has been getting a broken link ever since.It was not inert. rsync aborts on it mid-transfer — a deploy today reported success while the server kept running the previous version, and the mismatch only surfaced because the version was checked afterwards. The parent project’s
node test-all.mjsalso crashes outright when a web-ui checkout sits inside its tree, because its fixture copy walks the working directory and cannot stat the link. Nothing referenced it: the onlyreferomatches in the repo are the Polish word preferowany.
[1.228.0] — 2026-08-29
Dodano — kanały Telegrama jako źródło skanowania oraz stronicowany tryb zapytań w /api/scan-results.
Dodano
- Kanały Telegrama są teraz skanowalnym źródłem. Blok
telegram_channels:wportals.ymlje wymienia; każdy czytany jest z publicznego podgląduhttps://t.me/s/<kanał>. Rejestr: 85 → 86 źródeł (81 EN + 5 RU),ALL_ADAPTERS80 → 81. Telegram nie publikuje RSS, a Bot API nie odczyta kanału, którym bot nie administruje — obie oczywiste drogi są zamknięte. Podgląd/s/to zwykły HTML renderowany po stronie serwera: bez logowania, bez JS, bez ciasteczek. Sprawdzone na 16 kanałach: 15 zwróciło po 20 postów na gołym GET. GET /api/scan-resultszyskał stronicowany tryb zapytań.?q=<tekst>&limit=50[®ion=ru|en][&set=filtered|fresh][&offset=N]zwraca{ total, returned, offset, limit, set, rows }, gdzietotalto liczba PRZED stronicowaniem. Bez parametrów trasa nadal zwraca cały snapshot — tabela#/scanzależy od tego kształtu.
Naprawiono
- Asystent Telegrama odpowiadał z ułamka danych. Jego skill wskazywał już
/api/scan-results, ale trasa umiała zwrócić wyłącznie cały snapshot — około 2 MB — co nie mieści się w kontekście agenta. Na „znajdź wszystkich Product Managerów” podał 9 trafień tam, gdzie snapshot miał setki, i powiedział, że „pracuje na ograniczonym lokalnym indeksie”. To była prawda: widział endpoint, lecz nie mógł go przetworzyć. Ze stronicowaniem to samo pytanie kosztuje 2 KB i zwraca uczciwytotal. Skill też przepisano: kazał streszczać nowe posty, czyli wskazywałfreshzamiastfiltered.
Uwagi
- Post kanału to proza, nie rekord oferty. Brak pól strukturalnych: tytuł z pierwszej treściwej linii, firma/lokalizacja/widełki z jawnych etykiet. Oddzielanie prawdziwych ofert od reklam i przeglądów zostaje przy istniejącym
title_filter— tym samym, dostrojonym już dla innych źródeł. To tropy, nie lista. - Firmy nigdy się nie zgaduje. Bez etykiety wiersz przypisywany jest kanałowi (
@rabotaphp): błędny pracodawca trafia do trackera jako fakt. - Puste parsowanie to błąd, nie „brak ofert”. t.me odpowiada przekierowaniem na kanał prywatny lub nieistniejący; zwrócenie zera wierszy czytałoby się jako spokojny dzień i na zawsze ukryło literówkę w konfiguracji.
jobGeeksrobi dokładnie to (HTTP 302) i celowo nie jest skonfigurowany. - Wykrywanie pracy zdalnej używa uniksowej granicy słowa Unicode zamiast
\b, które obsługuje tylko ASCII — ta sama pułapka, w którą wpadł filtr tytułów w v1.227.3, tu złapana przez test przed wydaniem. - 15 kanałów skonfigurowanych i sprawdzonych na żywo: 299 postów, 15/15 kanałów. 30 nowych testów. Testy: 2865 → 2895.
- The README test counts jumped by hundreds, and no, this release did not add them. The localized READMEs carried unit-test totals frozen at 1856 / 1945 / 1955 / 549 / 419 / 284 / 2527 depending on the file — each stale since a different release, and several contradicting the badge at the top of the same page. They now all read 2895, verified by running the suite rather than by copying a badge. Playwright (70 / 90 / 12 → 101), e2e smoke (20 → 21), route modules (12 / 32 → 37), smoke flows (12 → 22) and the test-file count (218 → 329) were stale in the same way. The
Totalrow also repeated the unit count, so it under-summed the three suites below it; it now reads the real sum (3040).
[1.227.5] — 2026-08-29
Naprawiono — skan regionalny wyczerpywał pamięć serwera, a jeden zestaw Playwright zawodził na własnym demontażu.
Naprawiono
- Skan regionalny zabijał serwer przez OOM.
ru-scannergromadził wszystkie surowe trafienia ze wszystkich zapytań i deduplikował oraz filtrował dopiero na końcu. Lista zapytań celowo składa się z bliskich synonimów (Golang,Go разработчик,Golang разработчик,Senior Go…), więc ta sama oferta wraca raz na zapytanie, a tablica trzymała wielokrotność liczby unikatów — wraz z opisami, które stanowią większość obiektu i które filtry i tak niemal w całości odrzucają. Zmierzone: 742 MB sterty przy rzeczywistym przebiegu 21 zapytań. Serwer ogranicza stertę Node do 490 MB (V8 wylicza limit z 956 MB RAM maszyny), więc skan kładł usługę zFATAL ERROR: Reached heap limit— cztery razy w ciągu dnia. Teraz deduplikacja i filtrowanie odbywają się per zapytanie, co sprowadziło ten sam przebieg do 177 MB, czyli o 76% mniej. Raportowane liczby są niezmienione: sumę unikatów niesieSetłańcuchów URL. net::ERR_SOCKET_NOT_CONNECTEDlosowo psuł CI. Trzy zestawy Playwright wywołująwindow.stop(), by przerwać trwające żądania przed sprawdzeniem, że nie było błędów konsoli. Chromium raportuje ten jeden zamierzony akt pod trzema nazwami zależnie od stanu gniazda:ERR_ABORTEDprzy anulowaniu,ERR_EMPTY_RESPONSEw locie iERR_SOCKET_NOT_CONNECTED, gdy gniazdo już zniknęło. Wspólny filtr znał tylko dwie pierwsze. Ujawniło się to na przeglądzie lokalizacji wtr, aplaywright-formsiplaywright-smokebyły o jedno pechowe uruchomienie od tego samego.
Uwagi
- Dlaczego dopiero teraz. Lista urosła z 14 do 21 zapytań po dodaniu wyszukiwań product managera. Pamięć starej implementacji skalowała się z łączną liczbą trafień, więc +50% zapytań przebiło pułap maszyny.
- Zmiana deduplikacji zachowuje zachowanie i jest to przetestowane, a nie deklarowane.
tests/ru-scanner-dedup-order.test.mjsprzypina niewygodny kierunek — późniejszy duplikat, który NIE przechodzi filtrów, musi wyprzeć wcześniejszy, który przeszedł — i wykonuje 200 losowych sprawdzeń równoważności ze starą implementacją. - Filtr konsoli pozostaje wąski. Benignatywna jest tylko rodzina anulowanych żądań; odmowa połączenia, błąd DNS, reset, każde 5xx i nieprzechwycone wyjątki JS nadal wywracają asercję.
- Dwie hipotezy sprawdzono i odrzucono, zamiast je wysyłać: timeout Caddy (konfiguracja czysta,
flush_interval -1poprawny dla SSE) i domyślny 5-minutowyrequestTimeoutNode (pomniejszona reprodukcja pokazała, że nie przerywa on długiej odpowiedzi strumieniowej). Prawdziwym dowodem byłReached heap limitw dzienniku. Testy: 2860 → 2865.
[1.227.4] — 2026-08-29
Naprawiono — word: / stem: nadal były ignorowane przez content_filter; v1.227.3 naprawiła tylko filtr tytułów.
Naprawiono
content_filternie honorował prefiksów. v1.227.3 nauczyłatitle_filterprefiksówword:/stem:z projektu nadrzędnego, ale zostawiłacontent_filterprzy jego własnym surowymlower.includes(k), więc wpis z prefiksem był tam wciąż dopasowywany jako dosłowny tekst"word:java"— ten sam cichy no-op, jeden filtr dalej.content_filterczyta OPIS oferty, a jego domyślnym trybem zawsze był zwykły podciąg: dlatego goły negatywjavaodrzuca wszystko, co jedynie wspomina „JavaScript”; prefiks jest sposobem na wyłączenie jednego wpisu z tej reguły. PrzeniesionocompileContentKeywordz projektu nadrzędnego: dzieli tę samą maszynerię prefiksów, ale celowo nie kotwiczy krótkich słów kluczowych — filtr tytułów kotwiczy 2–3-literowe skróty, bo „COO” w „Coordinator” zawsze jest błędem, podczas gdy krótki ciąg w akapicie prozy bywa zamierzony (aws,gcp,sql,go).
Uwagi
- Wykryte w przeglądzie AI PR-a v1.227.3, który zauważył, że kod nie pokrywa tego, co twierdzi jego własny komentarz — pisał „
title_filter/content_filter”, a podłączona była tylko ścieżka tytułów. Komentarz rozróżnia to teraz wprost: oba filtry honorują prefiksy, tylko tytułowy kotwiczy skróty. - Również zweryfikowane na podstawie tego przeglądu i niezmienione: przejście reguły 2–3-literowych skrótów z
\bna granicę Unicode zachowuje się identycznie dla ASCII i jest surowsze tylko tam, gdzie powinno —COO_leadicoo1nadal zachowane (podkreślnik i cyfra są znakami słowa w obu wariantach),Coordinatorzachowany, „Директор COO” i „VP «Продукт»” poprawnie odrzucone. Sprawdzono 14 przypadków brzegowych. - Wpisy
content_filterbez prefiksu zachowują dotychczasowe dopasowanie co do bajta, pusty lub brakujący opis nadal przechodzi, a pustyword:/stem:nie dopasowuje niczego zamiast wszystkiego. 6 nowych przypadków wtests/content-filter.test.mjs. Testy: 2852 → 2858.
[1.227.3] — 2026-08-29
Naprawiono — prefiksy word: / stem: w filtrze tytułów były po cichu ignorowane, przez co te linie filtra nic nie robiły.
Naprawiono
- web-ui nie implementował prefiksów
word:/stem:z projektu nadrzędnego.title_filter(icontent_filter) domyślnie dopasowują podciąg bez rozróżniania wielkości liter — dlatego goły negatywinternodrzuca też „International Product Manager” i „Internal Tools Engineer”. Zamiast odwracać ten domyślny tryb — co zepsułoby każdą skonfigurowaną instalację — projekt nadrzędny uczynił precyzję opcjonalną dla pojedynczego wpisu:word:interndopasowuje tylko całe słowo, astem:agentmusi rozpoczynać słowo i może je kontynuować (oddzielając „Agentforce” od „Reagents”). web-ui nie miał żadnego z nich, więc dopasowywał wpis jako dosłowny tekst"word:intern", którego nie ma w żadnym tytule oferty. Linia stawała się cichym no-opem: ten samportals.ymlfiltrował poprawnie przez CLI i wcale tutaj, więc każda wykluczona oferta stażowa i tak trafiała do tabeli#/scan. Przeniesione ztitle-keywords.mjsprojektu nadrzędnego, wraz z granicą słowa świadomą Unicode (\p{L}\p{M}\p{N}_) zamiast\b, które obsługuje tylko ASCII i trafiało w środek słowa w tytułach z diakrytyką lub cyrylicą.
Uwagi
- Znalezione podczas sprawdzania prawdziwego
portals.yml, w którymword:interndodano właśnie po to, by gołyinternprzestał odrzucać „International Product Manager”. W CLI prefiks działał; web-ui po cichu zostawiał wszystkie staże. Teraz zachowanie jest identyczne. - Domyślne zachowanie bez zmian. Słowo kluczowe bez prefiksu zachowuje dotychczasowe dopasowanie: podciąg dla fraz i wszystkiego, co zawiera znaki niebędące literami (
.NET,SAP,L&D), oraz zakotwiczenie na granicach słowa dla 2–3-literowych skrótów. Pustyword:/stem:traktowany jest jak literówka i nie dopasowuje niczego — jako negatyw pusty wzorzec pasowałby do każdego tytułu i unieważnił cały skan przez jeden zbłąkany dwukropek. - Reguła 2–3-literowych skrótów używa teraz tej samej granicy Unicode: wcześniej
\b, przez cocooiword:coorozjeżdżały się na tytułach spoza ASCII — dwa zapisy jednej reguły. - 6 nowych przypadków w
tests/title-filter.test.mjs. Testy: 2846 → 2852.
[1.227.2] — 2026-08-29
Naprawiono — #/config przewijał się w bok na wąskich telefonach.
Naprawiono
- MOBILE-1:
#/configwychodził poza ekran w poziomie przy viewportach ≤ 352 px. Każde pole typu select niosło inline’owymin-width: 300px. Styl inline wygrywa z arkuszem stylów, więc kontrolka nie mogła skurczyć się razem z kontenerem: przy viewporcie 320 px prawa krawędź selecta lądowała na 353 px, strona dostawała poziomy pasek przewijania, a kontrolki wypychało poza prawą krawędź. Dotyczyło wszystkich 18 selectów dostawcy/modelu (cfg-llm-provideri każdycfg-*-model). Terazmin-width: min(300px, 100%)+max-width: 100%, więc wygodne 300 px obowiązuje tylko, gdy jest miejsce. Urządzenia na progu i poniżej: iPhone SE (1. gen., 320 px), starsze Androidy, zewnętrzny ekran Galaxy Fold.
Uwagi
- Dlaczego wszystkie wcześniejsze przebiegi mobilne to przeoczyły. 360 px i 375 px mają dokładnie tyle luzu, by ukryć przepełnienie, a zestawy Playwright działają w oknie 1280 px. Nic w CI nigdy nie zmierzyło viewportu węższego niż 375 px. Nowy
tests/playwright-narrow-viewport.mjsprzechodzi trasy z formularzami przy 320 px i failuje przy każdym poziomym przepełnieniu, wskazując w komunikacie najszerszy element; drugi przypadek przypina, że żaden select#/confignie wychodzi poza viewport. Najpierw sprawdzono, że odtwarza błąd (scrollWidth 353 > clientWidth 320, 18 selectów z prawą krawędzią 353). Playwright: 99 → 101. - Znane i celowo jeszcze bez bramki: 280 px (zewnętrzny ekran Galaxy Fold) nadal przepełnia się o ~5 px, ale z innej przyczyny — długa treść w blokach
<details>karty konfiguracji oraz 256-pikselowy sidebar wobec viewportu 280 px, a nie inline’owymin-width, który naprawia to wydanie. Przelewanie treści przy szerokości, której nie zgłasza żaden popularny telefon, to osobna praca; listaWIDTHSw zestawie jest na to gotowa. - Poprawiono też prompt QA z v1.227.1, który nazywał trasę follow-upu
#/modes/followup. Strony mode rejestrują goły slug (Router.register(cfg.slug)), więc trasa to#/followup, a#/modes/followuppoprawnie zwraca 404. Tylko dokumentacja. - Zestaw jednostkowy bez zmian — 2846 (nowe pokrycie jest na poziomie przeglądarki).
[1.227.1] — 2026-08-29
Naprawiono — rozbicie źródeł w pomocy nie zgadzało się samo ze sobą, a baner GitHuba był drukowany w aplikacji jako surowy znacznik.
Naprawiono
- §17 podawał sumę i rozbicie, które się nie sumowały. Wszystkie pakiety pomocy głosiły „rejestr
server/lib/sources/dostarcza 85 adapterów — 78 angielskich + 5 rosyjskich”. 78 + 5 = 83, a nie 85; w ja/ko dryf sięgał 77 (= 82). Każde nowe źródło podnosiło sumę i zostawiało składnik, więc obie liczby rozjeżdżały się od kilku wydań. Rozbicie to teraz 80 EN + 5 RU we wszystkich 17 lokalizacjach. To więcej niż kosmetyka:docs/help/<lang>.mdto JEDYNY korpus, na którym opiera się „Ask the docs”, więc pytający o liczbę źródeł dostawał dwie sprzeczne liczby z jednego zdania. - To samo zdanie przypinało nieaktualną kotwicę wersji. „Od v1.213.0 rejestr …” przetrwało w 16 lokalizacjach, podczas gdy licznik zmieniał się dwukrotnie (83 w v1.219.0, 85 w v1.226.0). Kotwicę naprawiano już ręcznie w v1.210.1 i po prostu znów odjechała. Została usunięta na rzecz sformułowania bez wersji — sam licznik jest weryfikowany względem żywego rejestru, który nie może się zdezaktualizować.
- Baner dostawców był drukowany jako zescapowany znacznik na górze
#/help. v1.225.0/v1.225.1 zapisały, że jest „usuwany w aplikacji przezUI.md()(brak obsługi obrazów)”. To myli dwie rzeczy:UI.md()escapuje najpierw — escapuje każdy bajt źródła przed jakąkolwiek transformacją markdown, co jest właściwą granicą XSS, ale przeciwieństwem usuwania. Nikt nie usuwał banera, bo nikt nie próbował, i wszystkie 17 lokalizacji otwierało#/help268 znakami dosłownego<p align="center"><img src="https://…. Nowe wspólne wejście (server/lib/help-markdown.mjs::stripGithubOnlyBlocks) odrzuca przy odczycie samodzielne bloki HTML z obrazem — zarówno dlaGET /api/help/:lang, jak i dla korpusu docs-assistant. Pliki zachowują baner, więc GitHub nadal renderuje witrynę. - Kolumna „#” na tablicy kadencji była pusta od v1.117.0. Czytała
entry.appNum, podczas gdyfollowup-cadence.mjszwracanum—appNumnigdy nie istniało w ładunku. Teraz czytane są oba. Wiersz „Next up” z v1.227.0 odziedziczył ten sam błąd i jest poprawiony razem z nim.
Uwagi
- Wszystkie cztery przeszły niezauważone, bo nic ich nie pilnowało. Bramki pomocy (
canonical-docs-coverage,help-ui,help-ru-config-section) liczą NAGŁÓWKI — 32 H2 / 121 H3 — i żaden test nigdy nie czytał liczby wewnątrz akapitu ani nie sprawdzał, co naprawdę serwuje wejście pomocy. Zamykają to dwa nowe zestawy:tests/help-source-counts.test.mjs(deklarowana suma równaSOURCES.length; składniki równe żywemu podziałowi EN/RU i sumujące się do sumy; akapit nie przypina wersji) oraztests/help-banner-strip.test.mjs(baner zostaje na dysku dla GitHuba, nigdy nie przeżywa filtrowania, pierwsza renderowana linia każdego pakietu to jego nagłówek, filtrowanie pozostaje wąskie, a obaj konsumenci przez nie przechodzą). Oba sprawdzono na czerwono względem dokładnie tych błędów przed commitem. Testy: 2837 → 2846. - Bez zmian w rejestrze, skanerze i kontraktach tras; źródeł nadal 85 (80 EN + 5 RU),
ALL_ADAPTERS80.
[1.227.0] — 2026-08-28
Dodano — SEEK Hongkong (JobsDB), filtr tylko wymagających dla follow-upów oraz poufni pracodawcy pokazujący agencję, która ich reprezentowała.
Dodano
- JobsDB Hongkong przez istniejące źródło Jobstreet/SEEK. Hongkong działa pod marką JobsDB, ale stoi na tej samej platformie SEEK za tym samym punktem końcowym v5, więc nie potrzebuje osobnego źródła — wystarczy
hk.jobsdb.comna liście dozwolonych hostów isiteKey: HK-Main. Rejestr bez zmian: 85 źródeł (80 EN + 5 RU),ALL_ADAPTERS80 — to nowy RYNEK na istniejącym adapterze, a nie nowy adapter. - Filtr tylko wymagających na tablicy kadencji (
#/modes/followup). Nowy checkbox zawęża tablicę do tego, co wymaga działania teraz. Termin czyta się zurgencywyliczonej już przez rodzicielskifollowup-cadence.mjs(urgent/overdue), nigdy zstatustrackera — tam sąapplied/responded/interview, co nie dopasowałoby się do niczego. Gdy nic nie jest wymagalne, tablica wskazuje najbliższy zaplanowany follow-up zamiast pustego ekranu. Logika mieszka w czystym modulepublic/js/lib/followup-view.js, lustrze rodzicielskiegofollowup-view.mjs. - Poufni pracodawcy są przypisywani agencji, która ich reprezentowała. Ogłoszenie z ukrytym pracodawcą zapisuje się w trackerze jako
?, a rekruter trafia do kolumnyVia.#/trackerpokazywał gołe?, więc kilka poufnych wierszy było nie do odróżnienia, a resolver logo nie miał czego szukać. Taki wiersz czyta się teraz „Poufny · przez <agencja>”, logo rozwiązuje się po nazwie agencji, a wiersz da się znaleźć po tej nazwie w wyszukiwarce. Wyłącznie prezentacja — kanoniczne polecompanynigdy nie jest nadpisywane rekruterem. Nowy czysty modułpublic/js/lib/company-presentation.js, lustro rodzicielskiegocompany-presentation.mjs.
Naprawiono
- Jobstreet/SEEK wołał wycofany punkt końcowy. Źródło wciąż wskazywało chalice-search v4 (
/api/chalice-search/v4/search), wyłączony przez SEEK; rodzic przeszedł na/api/jobsearch/v5/search, a web-ui nigdy za nim nie poszedł. Teraz każdy wpis Jobstreet/SEEK odpytuje v5. Kształt elementu v5 czytany jest natywnie (URL budowany zid,locations[0].label,advertiser.description,salaryLabel), parametr projekcjisolrFieldsz v4 znika, a wpis, któregoportals.ymlwciąż przypina martwą ścieżkę v4, zachowuje hosta swojego rynku, podczas gdy ścieżka jest przebudowywana na v5 — bez edycji ze strony użytkownika.
Uwagi
- Parytet z career-ops 1.30.0 (HEAD rodzica
8d64f65→6cc46a4; jegoVERSIONwciąż wskazuje 1.30.0 — release-please jest w tyle zamain). Nieprzeniesione, z uzasadnieniem: uzupełnianie lokalizacji z JSON-LD w iCIMS — źródło iCIMS w web-ui nie ma żadnego hakaenrichDate()(tylko strony listy), więc nie ma czego naprawiać; niekrytyczny stderr CLI (#1974) — runner web-ui rozstrzyga porażkę wyłącznie kodem wyjścia i nigdy nie miał tej heurystyki; śledzenie ścieżek Turbopack — web-ui nie ma bundlera; poprawkicv-sync-check— przekazywane tylko do odczytu i fail-soft; sekwencyjny Playwright wscan.mjs, odpowiedzi Block H, zabezpieczenia updater/doctor/update-system, rekurencyjna kontrola składni, dashboard w Go oraz dodane autotestyjd-skill-gap/verify-cv-facts— powierzchnie wyłącznie CLI, w które web-ui nie wchodzi, albo autotesty bez zmiany zachowania. Testy: 2818 → 2837.
[1.226.0] — 2026-08-27
Dodano — dwa wietnamskie źródła ofert: ITviec i CareerViet.
Dodano
- ITviec + CareerViet (Wietnam). Dwie wietnamskie tablice z przypiętym hostem dołączają do skanera przez wpisy
provider: itviec/provider: careerviet: ITviec (itviec.com, tech) i CareerViet (careerviet.vn, szeroki zasięg). Oba to scrapery HTML bez tokenów, z przypięciem hosta (anty-SSRF), tylko-HTTPS, fail-soft per firma i limitami stron. Rejestr ma teraz 85 źródeł (80 EN + 5 RU),ALL_ADAPTERS80 — oba pojawiają się w filtrze Źródło w#/scan.
Uwagi
- Zgodność z career-ops 1.30.0 (parentVersion 1.29.0 → 1.30.0). Nieportowane (tylko CLI/społeczność lub już pokryte): Hired Wall,
/calibrate, clean-markers, paczki szablonów, doctor, pdf/LaTeX oraz CLI eval/tracker/scan, których web-ui nie wywołuje; poprawka_html-to-textiroleFuzzyMatchjuż były; prefikstitle-filter stem:odroczony. Zestaw testów: 2818.
[1.225.1] — 2026-08-27
Naprawiono — baner logotypów dostawców teraz wyświetla się w README i pomocy.
Naprawiono
- Baner z v1.225.0 nie wyświetlał się na GitHub: samodzielny
images/providers.svgmiał nieprawidłowyfont-family(zagnieżdżone cudzysłowy) odrzucany przez GitHub,<img>używał względnegosrc(HTML<img>nie rozwiązuje ścieżek względnych na GitHub), a blok<p>nie miał końcowej pustej linii. Teraz wskazuje na wyrenderowanyimages/providers.pngprzez bezwzględny URL, z separacją pustymi liniami; SVG także poprawiono do prawidłowego XML.
Uwagi
- Tylko dokumentacja; bez zmian kodu ani testów. Witryna cvstart.org i kafelki w aplikacji były już poprawne (wbudowany SVG, nie ten plik). 2784
[1.225.0] — 2026-08-27
Dodano — baner logotypów dostawców w README i przewodniku pomocy.
Dodano
- Baner logotypów dostawców. Pojedynczy samodzielny
images/providers.svg— 18 dostawców LLM, z prawdziwym logo marki (simple-icons, CC0) dla 11 publikujących ikonę i monogramem w kolorze marki dla 7 pozostałych — wieńczy teraz README (×17) i wbudowany przewodnik pomocy. (Aplikacja sama renderuje kafelki z prawdziwym logo; baner renderuje się na GitHub, a bezpieczny dla XSS renderer aplikacji go usuwa.)
Uwagi
- Tylko dokumentacja — bez zmian kodu ani testów; SVG jest wbudowany (bez zasobu zdalnego). Źródła skanowania bez zmian: 83. Zestaw testów: 2784.
[1.224.0] — 2026-08-26
Zmieniono — kafelki dostawców LLM pokazują teraz prawdziwe logotypy marek.
Zmieniono
- Prawdziwe logotypy dostawców. Kafelki dostawcy — pola klucza API w Ustawieniach, wiersze Użycia, chip pulpitu, podsumowanie „Aktywny” w Ustawieniach, wynik ⚡ oceny i baner powitalny — renderują teraz prawdziwe logo marki dla 11 dostawców publikujących ikonę open-source (Anthropic · Gemini · OpenAI · Qwen · OpenRouter · GitHub · DeepSeek · Kimi · MiniMax · Mistral · Ollama; jednościeżkowe SVG z simple-icons, CC0). Siedmiu bez opublikowanej ikony (Hermes · GLM/Z.ai · Grok · Together · Fireworks · BytePlus Ark · Volcengine Ark) zachowuje monogram w kolorze marki. Nadal bezpieczne dla CSP z założenia: ścieżka logo to wbudowana stała statyczna — bez zasobu zdalnego, bez
innerHTML.
Uwagi
- Bez zmian tras ani zachowania; to samo API
ProviderLogo.el(slug).provider-logo.jsurósł (wbudowane ścieżki logo). Źródła skanowania bez zmian: 83. Zestaw testów: 2784.
[1.223.0] — 2026-08-26
Naprawiono — udana ocena ⚡ na żywo była malowana jako błąd; ponadto instalacja coworkera OpenWorker prosto z jego URL GitHub lub .zip.
Naprawiono
- Kolor odznaki wyniku ⚡ oceny. Udana ocena na żywo nie jest już kolorowana jako porażka. Dostawcy in-process (OpenRouter, DeepSeek, …) nie zwracają
codepodprocesu, więc ścisłecode === 0było fałszem i każdy sukces wychodził na czerwono (wciąż pokazując „exit 0”). Kolor podąża teraz za wynikiem — tylko podproces kończący się kodem różnym od 0 maluje go na czerwono; wynik na żywo bez kodu tobadge-ok, a sufiks „· exit N” pojawia się tylko przy prawdziwym kodzie wyjścia.
Zmieniono
- Zainstaluj coworkera OpenWorker z jego URL GitHub / .zip. Dokumentacja coworkera opisuje teraz instalator jednokomendowy (
curl … | bash, idempotentny — używa istniejącego career-ops / web-ui) i trzy ścieżki instalacji w OpenWorker (URL GitHub ·.zip· import pojedynczego pliku) wdocs/integrations/openworker.md, pomocy §32 (×17) i README.
Uwagi
- Zamknięto starą lukę pokrycia: źródło Recruitee ma teraz test end-to-end poprawki cudzysłowowego nawiasu z v1.214.2 (
>w atrybucie znacznika nie może wyciekać do opisu). Źródła skanowania bez zmian: 83. Zestaw testów: 2783.
[1.222.0] — 2026-08-26
Zmieniono — podpowiedzi pól rozszerzonych dostawców (DeepSeek … Volcengine Ark) są teraz zlokalizowane we wszystkich 17 językach.
Zmieniono
- Lokalizacja podpowiedzi pól dostawców. Każdy
config.<slug>Hintdla 11 zgodnych z OpenAI dostawców dodanych w v1.216.0–v1.217.0 (DeepSeek · GLM/Z.ai · Kimi · MiniMax · Mistral · Grok · Together · Fireworks · Ollama · BytePlus Ark · Volcengine Ark) — podpowiedzi klucza API, modelu i bazowego URL w Ustawienia → Klucze API — jest teraz przetłumaczony na wszystkie 17 języków zamiast wracać do angielskiego. URL-e rejestracji, id modeli i znacznik ⚡ oceny na żywo są zachowane dosłownie.
Uwagi
- Bez zmiany zachowania — angielski
hintFallbackwfield-specs.jsnadal chroni brakujący klucz, a nowy test kontraktu sprawdza, że każdyhintKeydeskryptorów pól rozwiązuje się we wszystkich 17 językach. Źródła skanowania bez zmian: 83. Zestaw testów: 2779.
[1.221.0] — 2026-08-26
Bezpieczeństwo — obrona w głąb przeciw DNS-rebinding na ścieżce fetch skanera.
Bezpieczeństwo
- Rdzeń HTTP skanera (
fetchJson/fetchTextwserver/lib/http-json.mjs) rozwiązuje teraz host każdego źródła na prawdziwej ścieżce sieciowej i odmawia połączenia, jeśli rozwiązuje się na adres prywatny, loopback, link-local, CGNAT lub metadanych chmury — zamykając wektor DNS-rebinding. Hosty skanera są już przypięte do domen publicznych, więc to obrona w głąb; ścieżka URL użytkownika miała już silniejsze przypięcie połączenia (safe-fetch.mjs). Strażnik działa tylko na prawdziwym transporciefetch— wstrzyknięty testowyfetchImplnigdy nie jest rozwiązywany.
Uwagi
- Brak zmiany zachowania dla zdrowego skanu. Źródła skanowania bez zmian: 83. Testy: 2775.
[1.220.0] — 2026-08-26
Dodano — skanuj wiele kategorii Get on Board z jednego wpisu.
Dodano
- Wpis
getonbrdmoże teraz ustawićcategories: [programming, operations-management, machine-learning-ai](lub pojedynczecategory:) zamiast tylko kanałuprogramming; oferty są deduplikowane po URL między kategoriami, z limitem 12. Istniejące wpisy pozostają identyczne (domyślnie nadalprogramming).
Uwagi
- Tylko serwer; przypięcie hosta SSRF (www.getonbrd.com) i
redirect:'error'bez zmian, a nieprawidłowy slug kategorii jest odrzucany przed jakimkolwiek żądaniem. Źródła skanowania bez zmian: 83. Testy: 2771.
[1.219.0] — 2026-08-26
Dodano — Torre dołącza do skanera, a każda etykieta dostawcy jest teraz poprawna.
Dodano
- Torre (
provider: torre) — panlatynoamerykański rynek talentów torre.ai, publiczne wyszukiwanie bez uwierzytelniania ze zdalnymi ofertami, których nie ma na Greenhouse/Lever/Ashby; jedno ograniczone żądanie na wpis. Rejestr ma teraz 83 źródła (78 angielskich + 5 rosyjskich). Ponadto monogram aktywnego dostawcy na banerze powitalnym.
Naprawiono
- Skan a16z Speedrun kończył się za wcześnie na tablicy z rotacją (krótką stronę w środku przebiegu traktowano jako ostatnią, skracając do 149 z ~300); teraz ufa
total_pagesz kanału. A baner powitalny ustalał dostawcę z 4-elementowej mapy (pokazując surowy slug dla pozostałych 14) — teraz używa etykiety+monogramu z 18; notka o dostawcach w Ustawieniach zmienia się z 7 na 18.
Uwagi
- Opcja wielu kategorii na wpis w Get on Board nie jest jeszcze podłączona (wymaga refaktoryzacji na poziomie źródła). Testy: 2768.
[1.218.0] — 2026-08-26
Dodano — odznaki dostawców (i poprawne nazwy) wszędzie, gdzie pokazywany jest dostawca.
Dodano
- Monogramy dostawców na plakietce pulpitu, w podsumowaniu „Aktywny” Ustawień i w nagłówku wyniku ⚡ oceny.
Naprawiono
- Przestarzałe etykiety: trzy widoki ustalały nazwę z 5-elementowej mapy (wynik oceny oznaczał każdego dostawcę spoza Anthropic jako „Gemini”); teraz używają
ProviderStatus.label(18). Licznik kluczy pokazywał „/ 7” → 18. Lista slugów podpowiedziLLM_PROVIDERzyskałaark/arkcnwe wszystkich 17 językach.
Uwagi
- Tylko klient, bezpieczne dla CSP. Bez zmian serwera. Źródła skanowania: 82. Testy: 2758.
[1.217.1] — 2026-08-26
Wzmocnienie testów — pokrycie endpointów dla całej listy dostawców.
Dodano
- Sparametryzowany test
run<Provider>sprawdzający endpoint, domyślny model i uwierzytelnianie Bearer dla Kimi, MiniMax, Mistral i Fireworks.
[1.217.0] — 2026-08-26
Dodano — Ark dołącza do listy LLM (18 dostawców). BytePlus Ark i Volcengine Ark — modele Doubao od ByteDance — to teraz dostawcy ⚡ na żywo, przez ten sam rdzeń zgodny z OpenAI i bazowy URL zależny od regionu.
Dodano
- BytePlus Ark (
ARK_API_KEY, międzynarodowy) i Volcengine Ark (ARK_CN_API_KEY, Chiny) — Chat Completions zgodny z OpenAI przezrunOpenAICompatible(). UstawARK_MODEL/ARK_CN_MODEL(nazwę modelu Doubao lub id endpointuep-…);ARK_BASE_URL/ARK_CN_BASE_URLprzełączają region. Oba dołączają do kolejnościauto(na końcu), z monogramem w Ustawieniach i Użyciu. Interfejs webowy obejmuje teraz 18 dostawców na żywo.
Uwagi
- Ta sama ścieżka zaufanej konfiguracji + kontroli schematu http(s) co reszta (nigdy walidator SSRF adresu oferty). Źródła skanowania bez zmian: 82. Testy: 2755.
[1.216.0] — 2026-08-26
Dodano — dziewięciu kolejnych dostawców LLM, każdy z własnym kafelkiem marki. Twoje ⚡ oceny na żywo mogą teraz działać przez DeepSeek, GLM (Z.ai), Kimi (Moonshot), MiniMax, Mistral, Grok (xAI), Together, Fireworks lub w pełni lokalny Ollama — o jeden klucz, każdy oznaczony monogramem obok swojego pola w Ustawieniach.
Dodano
- Dziewięciu dostawców zgodnych z OpenAI. DeepSeek, GLM (Z.ai), Kimi (Moonshot), MiniMax, Mistral, Grok (xAI), Together AI, Fireworks AI oraz Ollama (w pełni lokalny, bez klucza). Ustaw klucz — lub
OLLAMA_BASE_URLdla Ollamy — w Ustawieniach, a dołączy do kolejnościautopo Hermesie; przypnij dowolnego przezLLM_PROVIDER. Together hostuje też Inkling od Thinking Machines (thinkingmachines/Inkling). Interfejs webowy obejmuje teraz 16 dostawców na żywo. - Monogramy dostawców. Bezpieczny dla CSP kafelek z inicjałem w kolorze marki oznacza każdego dostawcę obok jego pola klucza w Ustawieniach i w jego wierszu na stronie Użycie — SVG inline, bez zewnętrznych logo, nic nie opuszcza Twojego urządzenia.
Uwagi
- Bazowe adresy URL dostawców to zaufana konfiguracja przechodząca przez
runOpenAICompatible()z kontrolą schematu http(s) (pętla zwrotna Ollamy jest dozwolona), nigdy przez walidator SSRF adresu oferty. Źródła skanowania bez zmian: 82. Testy: 2752.
[1.215.0] — 2026-08-26
Dodano — prowadź całe poszukiwanie pracy z OpenWorker. Nowy coworker napędza ten pipeline z open-source’owej aplikacji AI-coworker Andrew Ng, a pomoc w aplikacji teraz go obejmuje, więc asystent Zapytaj dokumentację może cię przeprowadzić.
Dodano
- Coworker OpenWorker. Beztokenowy, bezkodowy coworker OpenWorker — Fighter90/career-ops-coworker — prowadzi całe poszukiwanie pracy (skan, ocena, dopasowanie, śledzenie, follow-up) i może uruchomić ten pulpit, wszystko na twoim komputerze. To jednoplikowa persona dostarczana w 17 językach, zweryfikowana jako instalowalna własnym loaderem OpenWorker.
- Pomoc §32 „Run it from OpenWorker” (wszystkie 17 języków) to dokumentuje, aby wbudowany asystent Zapytaj dokumentację i pływający przycisk pomocy odpowiadały na pytania o niego. Podlinkowane też ze stopki landingu, README, wiki i
docs/integrations/openworker.md.
Uwagi
- Tylko dokumentacja + strona — bez zmian kodu aplikacji. Źródła skanowania bez zmian — 82. Zestaw testów: 2742.
[1.214.2] — 2026-08-25
Naprawiono — wspólny potok HTML→tekst (opisy Greenhouse / Recruitee) nie przecieka już atrybutów znacznika do opisu, gdy wartość atrybutu zawiera znak >.
Naprawiono
- Opisy HTML z
>wewnątrz atrybutu są czyszczone poprawnie. Usuwacz znaczników za opisami Greenhouse i Recruitee używał naiwnego dopasowania, które zatrzymywało się na pierwszym>, więc znacznik jak<a title="salary > 100k">zostawiał końcowy tekst atrybutu (100k">) w opisie. Teraz respektuje wartości atrybutów w cudzysłowach (pojedynczych lub podwójnych), usuwa znaczniki przed dekodowaniem encji (żeby zakodowany cudzysłów w atrybucie nie stał się fałszywym separatorem) i nadal zachowuje dosłowne<>w zwykłym tekście.
Uwagi
- Zestaw testów: 2742. Źródła skanowania bez zmian — 82. W tej rundzie nic nowego od rodzica: pozostałe zmiany są przekazywane tylko do odczytu (poprawki follow-up / weekly-digest / rejection-latency / salary-gap nie wymagają zmian w web-ui) lub nie są powierzchniami web-ui (zewnętrzna wtyczka X/Xquik BYO-key, poprawki CLI/verify). Pozycje opcjonalne — opisy szczegółowe SmartRecruiters, pomijanie agregatorów w detect-reposts, prefiksy tytułu
stem:/word:, utwardzenie anty-DNS-rebinding — pozostają w kolejce.
[1.214.1] — 2026-08-25
Naprawiono — opisy Ashby są teraz ograniczane do tej samej długości co Greenhouse i Recruitee, więc filtr treści zachowuje się identycznie na trzech boardach, a jeden board nie może rozdąć pamięci podręcznej skanowania.
Naprawiono
- Opisy Ashby przestrzegają teraz tego samego limitu długości co inne boardy. v1.214.0 podawała treść oferty Ashby do filtra treści, ale — inaczej niż Greenhouse i Recruitee, które przycinają do 4000 znaków — treść Ashby była mapowana wprost bez limitu (niektóre 4× dłuższe). Więc to samo słowo
content_filtermogło pasować na Ashby, a nie na Greenhouse tylko zależnie od pozycji w tekście, a jeden board mógł dodać setki KB do pamięci podręcznej skanowania, którą ładuje#/scan. Ashby jest teraz przycinany do tych samych 4000 znaków (jego tekst jest już czysty, więc jest ucinany, nigdy nie pozbawiany znaczników).
Uwagi
- Zestaw testów: 2738. Źródła skanowania bez zmian — 82.
[1.214.0] — 2026-08-25
Naprawiono — opisy z Greenhouse, Ashby i Recruitee trafiają teraz do filtra treści, więc filtry słów / kraju / wizy naprawdę dopasowują te boardy; a “Associate <starszy tytuł>” (w tym rangi akademickie) nie jest już błędnie klasyfikowane jako entry-level.
Naprawiono
- Filtry treści działają teraz na Greenhouse, Ashby i Recruitee. Te boardy niosą teraz pełny tekst każdej oferty jako jej opis, więc
content_filter(lub filtr słów kraju / wizy) dopasowuje treść oferty zamiast przepuszczać board na ślepo. Ashby i Recruitee dostarczają treść w payloadzie listy za darmo; Greenhouse już to robił. Wszystkie trzy przechodzą przez jeden wspólny potok HTML→tekst. - “Associate Director” / “Associate Professor” jest starszy, nie entry-level. Klasyfikator stażu (używany przez
skip_tiers:) traktował słowo “associate” jako znacznik entry-level nawet wtedy, gdy poprzedza starszy tytuł. Teraz czyta “Associate” — w tym rangi akademickie (Associate Professor, Associate Dean) — jako starszy, zachowując prawdziwe warianty juniorskie (Associate Attorney, Associate Editor) jako entry-level, i wciąż klasyfikuje wiodące “Intern, Associate Dean” jako staż.
Uwagi
- Zestaw testów: 2736. Źródła skanowania bez zmian — 82. W kolejce na później: opcjonalne wzbogacanie opisów SmartRecruiters (żądanie szczegółów na ofertę), pomijanie boardów
aggregator: truew detect-reposts oraz prefiksy tytułu z zakotwiczonym słowemstem:/word:— każde to opcjonalna konfiguracja, a nie zmiana domyślnego zachowania. Utwardzenie przeciw DNS-rebinding wciąż czeka na własne wydanie bezpieczeństwa.
[1.213.0] — 2026-08-22
Dodano — MyCareersFuture, krajowy bank ofert pracy Singapuru, jako źródło skanowania. Naprawiono — oferty Greenhouse niosą teraz pełny tekst, aby filtry treści działały, a zdalne oferty Ashby nie są już ukrywane za lokalizacją tylko-miasto.
Dodano
- MyCareersFuture (Singapur) (mycareersfuture.gov.sg) — nowe beztokenowe źródło skanowania dla krajowego publicznego banku ofert pracy Singapuru (Workforce Singapore). Wybierz je w filtrze Źródło na
#/scanlub dodaj firmę zprovider: mycareersfuturei opcjonalną listąkeywords(w razie braku sięga po docelowe role z Twojego profilu, jak Job Bank). Czyta publiczne API wyszukiwania, przypięte do hosta, bez klucza.
Naprawiono
- Oferty Greenhouse można teraz filtrować po treści. Boardy Greenhouse pobierane są z pełnym ciałem oferty, dekodowanym do zwykłego tekstu jako opis — więc
content_filter(lub filtr słów kraju/wizy) czytający opis rzeczywiście dopasowuje teraz oferty Greenhouse zamiast przepuszczać je na ślepo. - Zdalne oferty Ashby nie są już odrzucane przez filtr miasta. Ashby trzyma model pracy (Remote/Hybrid/Onsite) osobno od miasta biura, więc w pełni zdalna oferta wciąż czytała się jako np. „San Francisco” — a filtr lokalizacji blokujący to miasto ukrywał ofertę, którą mógłbyś przyjąć. „Remote” jest teraz dodawane do lokalizacji, gdy rola jest zdalna, a
workplaceTypewygrywa z nieaktualną flagąisRemote, by nie oznaczyć błędnie hybrydowej oferty zakotwiczonej w biurze.
Uwagi
- Źródła skanowania: 82 (77 angielskich + 5 rosyjskich). Zestaw testów: 2724. Utwardzenie przeciw DNS-rebinding (walidacja rozwiązanego adresu hosta przed połączeniem) czeka na dedykowane wydanie — potrzebuje projektu specyficznego dla web-ui, nie bezpośredniego portu.
[1.212.1] — 2026-08-21
Naprawiono — landing cvstart.org zaniżał liczbę źródeł ofert skanera (pokazywał 80 i pomijał Job Bank (Kanada)); znów zgadza się z 81 w aplikacji, a build strony głośno się wywala, jeśli te liczby się rozjadą.
Naprawiono
- Licznik „Źródła ofert” na landingu znów jest zsynchronizowany z aplikacją. Po v1.212.0 cvstart.org pokazywał 80 tablic i brakowało nowego chipa Job Bank (Kanada), podczas gdy aplikacja, lista rozwijana skanowania i przewodnik pomocy wymieniały 81. Landing buduje listę, ładując żywy rejestr skanera, a jedno źródło nie załadowało się w tym buildzie z powodu sposobu, w jaki wciągało zależność YAML — więc zostało po cichu odrzucone. Job Bank ładuje teraz tę zależność leniwie, tak jak reszta aplikacji podczas skanowania, więc zawsze się pojawia.
- Build strony odmawia teraz opublikowania niezgodnej liczby źródeł. Jeśli rejestr wyliczy mniej źródeł niż istnieje na dysku (sygnatura źródła, które się nie załadowało), build wywala się z czytelnym komunikatem zamiast po cichu opublikować złą liczbę.
Uwagi
- Zachowanie aplikacji bez zmian — skaner zawsze miał wszystkie 81 źródeł; dotknięty był tylko landing. Źródła skanowania: 81 (76 angielskich + 5 rosyjskich) — bez zmian. Zestaw testów: 2687.
[1.212.0] — 2026-08-21
Dodano — Job Bank (Kanada), federalny krajowy portal pracy. Usunięto — EchoJobs (jego feed jest teraz blokowany przez anty-bota). Naprawiono — portale oparte na Consider znów zwracają wyniki, a wielolokalizacyjne oferty Lever nie ukrywają już połowy lokalizacji.
Dodano
- Job Bank (Kanada) (jobbank.gc.ca) — nowe beztokenowe źródło skanowania dla federalnej krajowej służby zatrudnienia Kanady, portalu o dużym wolumenie, którego żaden agregator dobrze nie pokrywa. Wybierz je w filtrze Źródło na
#/scanlub dodaj firmę zprovider: jobbankcai opcjonalną listąkeywords(w razie braku sięga po docelowe role z Twojego profilu). Czyta publiczny feed ATOM, przypięty do hosta, bez klucza.
Usunięto
- EchoJobs — wycofany. Jego publiczny feed jest teraz za ochroną anty-botową i nic nie zwraca, więc trzymanie go tylko marnowało slot skanowania.
Naprawiono
- Portale oparte na Consider znów zwracają wyniki. Consider wymaga teraz anonimowego uścisku dłoni (GET, który zasiewa ciasteczko sesji + token CSRF) przed przyjęciem zapytania; bez tego żądanie było po cichu odrzucane, a portal wyglądał na pusty.
- Wielolokalizacyjne oferty Lever nie ukrywają już połowy lokalizacji. Lever wstawia jedno główne miasto do
location, a resztę doallLocations; czytanie tylko głównego sprawiało, że oferta otwarta w Barcelonie I Montevideo wyglądała jak tylko-Barcelona (i była błędnie odrzucana przez filtr lokalizacji). Teraz oba są scalane.
Uwagi
- Łagodniejsze tempo między stronami (250 ms zamiast 150) na portalach stronicowanych, przez grzeczność wobec jednohostowych stron karier. Źródła skanowania: 81 (76 angielskich + 5 rosyjskich) — bez zmian (Job Bank wchodzi, EchoJobs wychodzi). Zestaw testów: 2685.
[1.211.0] — 2026-08-19
Dodano — Yourator, tajwański tech-portal pracy. Naprawiono — akcentowane encje w tytułach/nazwach firm dekodują się teraz wszędzie, a firma z akcentem w nazwie nie jest już błędnie oznaczana.
Dodano
- Yourator (yourator.co) — nowe beztokenowe źródło skanowania dla tajwańskiego rynku pracy tech i digital. Wybierz je w filtrze Źródło na
#/scanlub dodaj firmę zprovider: yourator. Czyta publiczne API JSON (bez klucza, bez przeglądarki), przechodzi każdą stronę portalu i emituje prawdziwy link pracodawcy (jego własny ATS) z usuniętymi parametrami śledzenia.
Naprawiono
- Akcentowane encje nazwane dekodują się teraz wszędzie. Wspólny dekoder HTML zyskał litery Latin-1 (
é→ é,ç→ ç, …), więc europejski portal piszącyDéveloppeurlubFrançaisnie zostawia już tego literału w tytule, trackerze ani wygenerowanym dokumencie. (Wielkie litery pozostają wielkie —Éto É, nie é — a wyszukiwanie typu&constructor;rozwiązuje się teraz do samego siebie.) - Firma z akcentem w nazwie nie jest już błędnie oznaczana za bycie na własnej domenie. „Işık” składa się teraz do „isik” i pasuje do isik.com.tr; „Société Générale” pasuje do societegenerale.com. Stare sprawdzenie usuwało litery akcentowane zamiast składać je do bazy ASCII.
Uwagi
- Źródła skanowania: 81 (76 angielskich + 5 rosyjskich). Zestaw testów: 2667.
[1.210.1] — 2026-08-19
Naprawiono — tytuły ofert i nazwy firm z Habr Career zawierające „&” lub cudzysłowy nie przychodzą już zniekształcone.
Naprawiono
- Źródło Habr Career dekoduje teraz encje HTML w tytule i nazwie firmy, zanim powędrują dalej. Renderowane po stronie serwera karty przychodzą z encjami („Changellenge >>“, „Demand Forecasting & Inventory Optimization”, „ООО "М-ТЕХ"“), więc niezdekodowane „&” po cichu nie przechodziło twojego własnego filtra tytułu z „&” — dokładnie ten objaw, który poprzednie wydanie zamknęło na pięciu innych portalach — a nazwy firm docierały zniekształcone do trackera i raportów. Dekodowanie encji jest teraz kompletne we wszystkich sześciu dotkniętych źródłach.
Uwagi
- Zestaw testów: 2644.
[1.210.0] — 2026-08-19
Dodano — Senjob, pierwszy afrykański portal pracy skanera (Senegal); dokładniejsze dopasowanie tytułów na kolejnych pięciu portalach.
Dodano
- Senjob (senjob.com) — nowe beztokenowe źródło skanowania dla Senegalu, pierwszy afrykański portal skanera. Wybierz je w filtrze Źródło na
#/scanlub dodaj firmę zprovider: senjob. Czyta publiczną listę zwykłym HTTP (bez klucza, bez przeglądarki), przypina każde żądanie do senjob.com i — parsując HTML — traktuje listę, która nagle nic nie zwraca, jako zepsuty portal (widoczny błąd), a nie kraj bez ofert.
Naprawiono
- Tytuły z „&” nie gubią już ofert na pięciu portalach — na beesite, Cornerstone (csod), Hacker News „Who is hiring”, Phenom i TKMS tytuły przychodzą z encjami HTML, więc zaescape’owany „&” w stanowisku typu “R&D Engineer” nie przechodził twojego własnego słowa kluczowego “r&d” i oferta znikała po cichu (weto “sales & marketing” też nigdy się nie uruchamiało). Teraz tytuły — i lokalizacje Phenom — są dekodowane przed filtrowaniem.
Uwagi
- Źródła skanowania: 80 (75 angielskich + 5 rosyjskich). Zestaw testów: 2643.
[1.209.0] — 2026-08-17
Dodano — pomoc w aplikacji obejmuje teraz zapisywanie wyniku aplikacji, a „Zapytaj dokumentację” może cię tam poprowadzić.
Dodano
- Pomoc Trackera (§11) zyskała sekcję „Zapisz wynik” we wszystkich 17 językach, prowadzącą przez przycisk Wynik: wybierz, co się stało (odrzucono / oferta / zatrudniony / odrzucona / zignorowano / awans do rozmowy), podejrzyj, co zrobi, i zapisz — co odnotowuje wynik, archiwizuje wysłane CV i list motywacyjny oraz synchronizuje Status wiersza za ciebie. Pływający asystent „Zapytaj dokumentację” czyta ten przewodnik, więc teraz kieruje cię do tego przycisku, zamiast tylko sugerować ręczną edycję Statusu.
Uwagi
- Każdy pakiet pomocy to teraz 31 H2 / 119 H3 (było 118); strażniki parzystości podniesiono. Tylko dokumentacja — bez zmian kodu i zachowania. Zestaw: 2625.
[1.208.2] — 2026-08-16
Naprawiono — na telefonie przyciski powiadomień i motywu nie leżą już na polu wyszukiwania.
Naprawiono
- v1.208.1 sprawiła, że przyciski górnego paska nie nachodzą już na nagłówek strony, ale na wąskim — choć nie najwęższym — ekranie, zwłaszcza w językach z dłuższymi etykietami, cały pasek nadal ściskał się w jeden wiersz, więc przyciski 🔔 i 🌙 mogły znaleźć się na polu wyszukiwania. Przyciski akcji (powiadomienia, motyw, Diagnostyka, Otwórz Scan) na telefonie zawsze schodzą teraz do własnego, pełnej szerokości drugiego wiersza, więc pole wyszukiwania jest w pełni widoczne i nic się nie nakłada.
Uwagi
- Na telefonie przyciski akcji paska przechodzą do drugiego wiersza pełnej szerokości, usuwając kruchy pas „niemal pełnego wiersza”, gdzie układ rozdzielał pozostałą ujemną przestrzeń jako nakładanie. Strażnik Playwright odtwarza teraz dokładny wyzwalacz — język z długimi etykietami w pasie 565–640px — i sprawdza, że kontrolki paska nigdy nie dzielą pikseli. Zestaw: 2621.
[1.208.1] — 2026-08-16
Naprawiono — na telefonie przyciski górnego paska nie nachodzą już na stronę.
Naprawiono
- v1.208.0 zawijała przyciski górnego paska (Diagnostyka, Otwórz Scan, powiadomienia, motyw) do drugiego wiersza na wąskich ekranach, ale pasek zachowywał stałą wysokość, więc zawinięty wiersz wychodził poza pasek i nakładał się na nagłówek strony. Teraz pasek rośnie pod swoje wiersze, a treść płynie pod nim.
Uwagi
- Stała
heightpaska stała sięmin-height, więc rośnie z treścią przy każdej szerokości (pulpit bez zmian). Strażnik Playwright sprawdza teraz również, że pasek nie wychodzi na stronę. Zestaw: 2621.
[1.208.0] — 2026-08-16
Naprawiono — aplikacja mieści się teraz na ekranie telefonu: koniec przewijania w bok.
Naprawiono
- Na wąskim ekranie cała aplikacja uciekała w bok — górny pasek, tabele, artykuły pomocy i karty ustawień wychodziły poza prawą krawędź. Teraz każda strona mieści się przy dowolnej szerokości: przyciski górnego paska przechodzą do drugiego wiersza, szerokie tabele i bloki kodu przewijają się we własnej ramce, pomoc układa spis treści nad artykułem, rzędy przycisków/kart zawijają się, a długie ścieżki lub adresy URL łamią się zamiast rozciągać stronę.
Uwagi
- Przyczyną była klasyczna pułapka flex/grid min-width: auto oraz kilka nieopakowanych szerokich elementów; naprawiono przez
min-width: 0na elementach siatki,overflow-wrapna markdownie/nagłówkach, przewijalną tabelę markdown i układanie siatki pomocy w punkcie mobilnym. Strażnik Playwright sprawdza 0 poziomego przepełnienia przy 375 px na głównych trasach.tests/playwright-smoke.mjs. Zestaw: 2621.
[1.207.2] — 2026-08-16
Naprawiono — plany AI i profile orientacji zawodowej nie wyświetlają się już jako surowy zrzut kodu.
Naprawiono
- Niektóre modele zawijają całą odpowiedź w ogrodzenie kodu
markdown …. Gdy tak się działo, plan rozwoju i profil orientacji pokazywały się jako blok o stałej szerokości zamiast dokumentu z nagłówkami i listami. Teraz zawijające ogrodzenie jest usuwane — tylko gdy obejmuje całą odpowiedź i język to jawniemarkdown/md, więc prawdziwa odpowiedź wpython/js/``` bez języka pozostaje nietknięta.
Uwagi
- Obsłużone raz we wspólnym kroku czyszczenia LLM (
cleanLlmMarkdown), więc korzystają wszystkie trasy AI, a wewnętrzne bloki kodu w zawiniętej odpowiedzi przetrwają.tests/llm-output.test.mjs(+3). Zestaw: 2621.
[1.207.1] — 2026-08-16
Naprawiono — strona startowa nie wychodzi już na boki na małych telefonach.
Naprawiono
- Na wąskim telefonie sekcja hero — nagłówek, wiersz wprowadzenia i terminal instalacji — mogła być ucięta przy prawej krawędzi, bo długie polecenie instalacji i kolumny układu nie kurczyły się do ekranu. Teraz mieszczą się przy każdej szerokości; polecenie instalacji przewija się w obrębie własnego terminala.
Uwagi
- Wzmocniono też niestabilny test E2E, który mógł zawieść przez przejściowy 404 zasobu: teraz ignoruje nieszkodliwy szum sieciowy (favicon / połączenie / nieudany zasób) jak sąsiednie testy, wciąż wykrywając prawdziwe błędy skryptów. Zachowanie aplikacji bez zmian. Zestaw: 2618.
[1.207.0] — 2026-08-15
Dodano — zapisuj wynik aplikacji bezpośrednio ze śledzenia.
Dodano
- Każdy wiersz śledzenia zyskuje akcję Wynik: wybierz, co się stało (odrzucono, otrzymano ofertę, zatrudniony, oferta odrzucona, brak odpowiedzi, przeszedł do rozmowy), dodaj opcjonalną notatkę, podejrzyj wynikowy status i zapisz. Zapis archiwizuje wysłane pliki CV i listu motywacyjnego oraz synchronizuje śledzenie do stanu kanonicznego — jedna deterministyczna akcja zamiast ręcznej edycji.
Uwagi
- Nowa
POST /api/outcomepośredniczy w CLI wyników:dryRun:trueto podgląd tylko do odczytu (dopasowuje wiersz, zgłasza stan wynikowy, nic nie zapisuje); prawdziwe wywołanie zapisuje. Bezpieczeństwo zapisu: typ wyniku jest ograniczony do znanego zbioru, a każde pole tekstowe jest odrzucane przy znakach kontrolnych przed wywołaniem (argumenty jako tablica, spawn — bez powłoki).tests/outcome-route.test.mjs. Zestaw: 2618.
[1.206.0] — 2026-08-15
Dokumentacja — wbudowany przewodnik pomocy obejmuje teraz pięć najnowszych funkcji we wszystkich 17 językach.
Dodano
- Wbudowany przewodnik pomocy — oraz asystent „Zapytaj pomoc”, który odpowiada na jego podstawie — dokumentuje teraz pięć niedawno dodanych funkcji: Doktor konfiguracji (Ustawienia — sprawdza CV i profil pod kątem braków i pozostawionych danych przykładowych), Znajdź tablice ATS (Portale — automatycznie znajduje tablicę ofert firmy), sprawdzenie „nadal aktualne?“ (Śledzenie — czy oferta jest wciąż otwarta), podpowiedź „użyć ponownie starego CV?” (CV Studio — sygnalizuje, gdy dopasowane wcześniej CV pasuje do nowej oferty) oraz Dziennik umiejętności (Analityka — zapis wyników samooceny). Pięć nowych podsekcji, przetłumaczonych na wszystkie 17 języków.
Uwagi
- Struktura przewodnika rośnie do 31 H2 / 118 H3, z gwarancją parytetu w każdym języku. Zaktualizowano dokumentację referencyjną:
docs/architecture/API.mdopisuje pięć tras tych funkcji, a liczniki tras/wersji wCLAUDE.mdidocs/sdd/CONVENTIONS.mdsą aktualne (36 modułów tras). Zestaw: 2610.
[1.205.0] — 2026-08-15
Dodano — dziennik umiejętności do zapisu wyników testów/ocen.
Dodano
- Nowy Dziennik umiejętności (Analityka → Dziennik umiejętności) pozwala zapisać samoocenę — firma, platforma, umiejętność, wynik % i opcjonalna notatka — dopisywaną do
data/assessments.tsv, z listą wcześniejszych wpisów (najnowsze na górze). Bez tokenów, deterministycznie; formatem pliku zarządza CLI projektu nadrzędnego.
Uwagi
- Nowa
GET /api/assessments(przekazuje domyślną listę JSONassessment-log.mjs; miękka awaria{available:false}) +POST /api/assessments(jawny zapis: pola przekazane jako argumenty tablicy doassessment-log.mjs add). Bezpieczeństwo zapisu: każde pole tekstowe ze znakiem kontrolnym jest odrzucane (TAB zepsułby kolumnę, nowa linia wstrzyknęłaby wiersz) → 400 przed zapisem; wynik/próg 0–100, długości ograniczone.tests/assessments-route.test.mjs. Zestaw: 2610.
[1.204.0] — 2026-08-15
Dodano — panel „Doktor konfiguracji” w Ustawieniach, który sygnalizuje niekompletne lub przykładowe dane CV/profilu.
Dodano
- Ustawienia → Doktor konfiguracji teraz bez tokenów sprawdza
cv.mdiconfig/profile.ymli wypisuje problemy blokujące (brakujące pliki/pola) oraz ostrzeżenia (pozostałe dane przykładowe/zastępcze, zaszyte metryki) — byś wychwycił niekompletną konfigurację, zanim osłabi skany i dopasowania. Tylko do odczytu; ponowne uruchomienie jednym kliknięciem.
Uwagi
- Nowa tylko-do-odczytu
GET /api/cv-sync-checkprzekazujecv-sync-check.mjsz projektu nadrzędnego, który wypisuje tekst + kod wyjścia (bez--json); trasa lekko parsuje jego stabilne linieERROR:/WARN:do{ok, errors[], warnings[]}— o sukcesie decyduje baner, nie kod wyjścia. Miękka awaria{available:false}w instalacjach samodzielnych.tests/cv-sync-check-route.test.mjs. Zestaw: 2602.
[1.203.0] — 2026-08-15
Dodano — podpowiedź „użyć ponownie wcześniejszego CV?” w CV Studio.
Dodano
- Po otwarciu zapisanej oferty w CV Studio aplikacja porównuje ją teraz z innymi zapisanymi ofertami (deterministyczne nakładanie słów, zero tokenów) i mówi, czy najbliższa jest na tyle podobna, by użyć ponownie tego dopasowanego CV, użyć go z poprawkami albo przygotować nowe — byś nie tworzył od zera dla roli, którą już celowałeś.
Uwagi
- Nowa tylko-do-odczytu
GET /api/jds/:name/reuseprzekazujejd-similarity.mjsz projektu nadrzędnego (nakładanie Jaccarda + strażnik seniority; JSON{decision, score, reason}) raz na każdą wcześniejszą ofertę (fan-out ograniczony do 25, wygrywa najlepsze); miękka awaria{available:false}, gdy brak skryptu lub wcześniejszych ofert.tests/jd-similarity-reuse-route.test.mjs. Zestaw: 2594.
[1.202.0] — 2026-08-15
Dodano — znajdź tablicę ATS firmy z poziomu #/portals i zacznij ją śledzić.
Dodano
- Na #/portals wpisz nazwę firmy, a aplikacja sprawdzi Greenhouse, Ashby i Lever pod kątem jej publicznej tablicy — zero LLM, bez przeglądarki — i pokaże tablice, które istnieją i mają ≥1 ofertę. Jedno kliknięcie dodaje wybraną tablicę do firm śledzonych przez skaner. Sondowanie jest tylko do odczytu; zapis do
portals.ymlnastępuje tylko po kliknięciu Dodaj.
Uwagi
- Nowy
server/lib/discover-ats.mjs(sondowanie sluga o stałym hoście i zweryfikowanym charset przezsafeGetz przypiętym DNS, ≤12 sond/żądanie) +POST /api/portals/discover(tylko odczyt) iPOST /api/portals/track(jawny zapis:withFileLock+ wstawka tekstowa + strażnik ponownego parsowania + atomowa zmiana nazwy; tylko znane hosty ATS, idempotentnie). Ponownie używa rejestru adapterów skanera. i18n ×17.tests/discover-ats-resolver.test.mjs+tests/discover-ats-route.test.mjs. Zestaw: 2588.
[1.201.0] — 2026-08-15
Naprawiono — śledzenie z zlokalizowanymi lub wariantowymi nagłówkami kolumn nie jest już puste.
Naprawiono
- Jeśli Twój
data/applications.mdużywa nieangielskich lub wariantowych nagłówków — hiszpańskieempresa/puesto/estado/fecha/enlacealboposition/stage/link— śledzenie czytało je pod złymi kluczami i pokazywało puste kolumny Firma / Stanowisko / Status / Data / Link. Teraz te nagłówki są mapowane na kanoniczne nazwy pól i śledzenie wyświetla się poprawnie. Śledzenie w pełni angielskie jest przetwarzane jak wcześniej.
Uwagi
- Nowa mapa
HEADER_ALIASESi złożenie normalizujące wparseApplications(server/lib/parsers.mjs); nieznane lub już kanoniczne nagłówki przechodzą bez zmian.tests/tracker-header-aliases.test.mjs. Zestaw: 2563.
[1.200.0] — 2026-08-15
Dodano — sprawdzenie jednym kliknięciem „czy nadal aktualna?” dla ofert w ATS w Twoim śledzeniu.
Dodano
- Na #/tracker aplikacja, której URL to oferta Greenhouse / Lever / Ashby / Workday / SmartRecruiters, ma teraz przycisk „Czy nadal aktualna?“. Jedno kliknięcie odpytuje publiczny JSON samego ATS — zero tokenów, bez przeglądarki — i pokazuje Aktualna / Wygasła / Nieznana, byś wykrył martwe oferty bez otwierania każdej. Zachowawczo z założenia: tylko jednoznaczne 404/410 to Wygasła; niejednoznaczne zostaje Nieznana (nigdy fałszywe Wygasła).
Uwagi
- Nowe
server/lib/liveness-core.mjs+liveness-api.mjsoraz tylko do odczytuGET /api/liveness?url=(bez zapisu, bez LLM). Bezpieczne wobec SSRF: URL przechodzi przezisValidJobUrl, a API ATS jest osiągane tylko przezsafeGet(przypięty DNS), ze stałym hostem i zweryfikowanymi segmentami.tests/liveness-core.test.mjs+tests/liveness-route.test.mjs. Zestaw: 2557.
[1.199.0] — 2026-08-15
Naprawiono — szerokie tabele przewijają się teraz w poziomie zamiast być ucinane.
Naprawiono
- Na stronie Scan (oraz we wszystkich innych tabelach — Śledzenie, Statystyki, Użycie, Pulpit) tabela szersza od okna była ucinana bez paska przewijania, przez co ostatnie kolumny były nieosiągalne. Szerokie tabele pokazują teraz w razie potrzeby poziomy pasek przewijania, więc każda kolumna pozostaje dostępna przy każdej szerokości.
Uwagi
.table-wrapwpublic/css/components.csszmieniono zoverflow: hiddennaoverflow-x: auto(jak istniejący kontener.reports-scroll); zaokrąglona ramka jest zachowana.tests/table-wrap-scroll.test.mjs. Zestaw: 2540.
career-ops-ui v1.267.1 · page 3/10 · mirror of the project changelog for cvstart.org