체인지로그

GitHub

릴리스별로 정리된 모든 주요 변경 사항입니다. 저장소에 실린 동일한 파일이며, 19개 언어 전체로 번역되어 있습니다.

[1.255.0] — 2026-10-24

베트남어(Tiếng Việt)가 19번째 UI 로캘로 합류합니다 — EN과 완전한 동등성을 갖춘 1525키 사전, vi/vi-VN 감지, 전체 도움말 번들, README·CHANGELOG 미러, cvstart.org 랜딩 통합, 그리고 언어 전환기의 🇻🇳입니다.

추가

  • 베트남어(vi) — 1525/1525키, en과 완전한 동등성; detect()는 vi와 vi-VN을 받습니다; 베트남어는 LTR(RTL_LANGS에 넣지 않음). ’Pipeline’은 ’Pipeline’으로 남습니다 — 표준 기술 차용어로 화이트리스트 등재.
  • docs/help/vi.md 전체 (33 H2 / 125 H3), README.vi.md·CHANGELOG.vi.md 미러, 그리고 prompts.mjs의 베트남어 스캐폴드 문자열(LOCALE_NAMES + SCAFFOLD_STRINGS)까지 — 베트남어 LLM 출력이 기본으로 동작합니다.
  • cvstart.org 랜딩의 베트남어 — site/src/i18n/vi.json, 사이트맵 로캘 항목, dashboard-vi.png 스크린샷; 언어 전환기에 🇻🇳 추가(19개 위치).
  • 열거 게이트 18 → 19 — LANGS, detect 프룹, i18n 감사, 체인지로그 패리티, README 번역 블록, 로캘 스윕 — 그리고 우선-빨강 tests/i18n-vi-locale.test.mjs(139줄).

참고

  • cvstart.org 랜딩에 vi 추가 — ta 선례에서의 의도된 이탈(해당 릴리스는 랜딩을 의도적으로 17로 유지); 릴리스 스펙에 문서화.
  • vi는 라틴 문자이므로 no-latin-leaks 게이트가 적용되지 않습니다(비-라틴 로캘을 보호); 라틴 기술 어휘가 표준입니다.
  • 테스트 바닥: 5634 → 5642 (1개 건너뜀 = 옵트인 레이아웃-캡처 브라우저 테스트, 변경 없음).

[1.254.0] — 2026-10-24

최대 모델 리뷰 라운드의 강화 릴리스: 스캐너 스냅샷이 더 이상 행을 잃지 않고, LLM 레이어의 11가지 불변 위반이 수정되었으며, SPA must-fix 23건이 착지하고, Paylocity ATS가 스캐너에 합류합니다 — 레지스트리는 이제 116 어댑터와 함께 121 소스(EN 115 + RU 5)를 제공합니다.

추가

  • Paylocity ATS (상위 #5687): 테넌트별 recruiting.paylocity.com 보드, 죽은 보드 302 → JobNotFound를 404로 매핑해 검역이 항목을 은퇴시키고, max_jobs 상한과 잘림 플래그. 레지스트리: 121 소스 = 116 EN + 5 RU · 116 어댑터; 카운트 게이트 재생성.

수정

  • 스캐너 스냅샷 안전성 (R-12): 아무것도 시도하지 않는 스캔은 이제 스냅샷을 KEEP(nothing scanned)하고, 전체 교체 시 실패한 소스의 이전 행을 — 엔트리별 스탬프로 — 현재 필터를 재통과해 filtered에만 착지시킵니다.
  • LLM 레이어 11 불변: deep/mode 프롬프트를 열고 닫는 언어 디렉티브; Gemini 서브프로세스 --lang 전달, 비영종료 → 502, stderr 미노출, 300 s, usage 기록; URL을 실은 manual fallback; /api/mode의 truncation 노출; 클라이언트가 spend tier를 더 이상 바꿀 수 없음; 클라이언트 단절이 진행 중인 프로바이더 호출을 어보트; 반복-헤딩 커터가 더 이상 유효한 리포트를 파괴하지 않음; score/legitimacy 추출기와 밸리데이터 정합; uk 시퀀스와 아랍 와-앤타이트 false-accept 강화.
  • 수정 자체에 대한 Opus 5-5 리뷰 라운드 (필수 8건): 커터의 다중-문자 등록, 더 넓은 헤딩 터미네이터, Gemini 서브프로세스 어보트 배선, 엔트리-스탬프 캐리오버 속성, 캐리 행의 현재 필터 재통과, 서로 다른 문자 수 기준 레벨.
  • SPA must-fix 23건: sourcing 뷰(단일-페이지 페이저 append, pipeline 행 키보드, saved-search 필터 복원, 소스 select 리셋, config 기본-되돌림, 리스너 누수, SSE 터미널 시 close, 스캐너 러너 teardown, 나체 fetch, 실패가 빈 것처럼 보이는 가족, 윈도 충돌, 포커스 보존)와 어시스트 뷰(죽은 help 딥-링크, help 리스너 누수, two-pager 블랭크-오버라이트 재무장, 유료 실행 single-flight, 조용한 스트림 끝, 영원한 스피너 오류 경로, 실패 필터의 고스트 행, docs-fab 중복 + 언어).

참고

  • 전 라운드가 Opus 5-5의 최대 강도로 리뷰되었습니다 — 머지 전 포트(21 발견, 13 수정)와 수정 자체의 사후 리뷰(필수 8건, 모두 여기에 적-녹 테스트와 함께).
  • 테스트 플로어: 5262 → 5634(소스, 스캐너, LLM 레이어, SPA에 걸쳐 372개 신규 스펙).

[1.253.1] — 2026-10-24

최대 모델 리뷰의 2건의 HIGH 보안 발견이 수정되었습니다: IPv6 리터럴 URL이 더 이상 스캐너의 SSRF 가드를 우회하지 않으며, CV 마크다운 이스케이프 정규식도 더 이상 이차적으로 백트래킹하지 않습니다.

수정

  • IPv6 리터럴이 SSRF 가드를 우회 (http-json.mjs): 대괄호 IPv6 리터럴이 dns.lookup을 던지게 해 가드가 실피-오픈했습니다. 이제 대괄호를 제거하고 isIP로 직접 분류 — DNS 없이 fail-open 없음.
  • CV 마크다운 이스케이프의 ReDoS (security.mjs): 패턴이 이차적으로 백트래킹 — < + ~100k 공백이 ~16초 걸렸으나 이제 평평한 유한 클래스로 ~1ms. 이전에 이스케이프되던 것은 모두 계속 됩니다.

참고

  • 두 수정 모두 적색→녹색 회귀 테스트를 동반 (IPv6 신규 3케이스 + 시간 한정 ReDoS; 총 5511 테스트, +7).
  • 스캐너 소스 파일은 영향 없음 — 가드는 두 스캐너가 지나는 공유 트랜스포트에 있습니다.

[1.253.0] — 2026-10-24

10개의 새 채용 소스가 스캐너에 합류합니다 — Atlassian, BWI, Computrabajo, Dover, Google, Kalibrr, Magneto365, Platsbanken, Tech in Asia, Zoho Recruit — 레지스트리는 이제 115개 어댑터와 함께 120개 소스(EN 115 + RU 5)를 제공하며, 역할 매처는 짧은 대문자 코드만 다른 직함을 더 이상 같은 공고로 묶지 않습니다.

추가

  • 10개 소스를 상위 1.38.0에서 포팅, 각각 fetch-walk 어댑터와 CI 고립 스위트(가짜 fetchImpl, 네트워크 없음): Atlassian(단일 무인증 JSON 피드, iCIMS URL, https+icims.com allowlist), BWI(JSON-LD ItemList, JSON.parse 우선), Computrabajo(LATAM, 엔티티 디코드, 스페인어 «remoto»=remote), Dover(테넌트별 DRF 페이지네이션, Remote (International) 렌더, UUID 검증 보드), Google Careers(구문별 첫 페이지, 카드 고용주 우선, 쿼리 간 dedup), Kalibrr(SEA 애그리게이터, 피드 id가 행 id), Magneto365(LATAM, 고정 페이지 간 페이싱), Platsbanken(스웨덴 JobTech API, 키워드별 윈도), Tech in Asia(사이트 빌드에서 Algolia 키 발견), Zoho Recruit(히든-인풋 보드, 제한적 detail enrichment, ISO-4217 전용 통화 파싱).
  • 레지스트리 카운트: 120 소스 = 115 EN + 5 RU · 115 어댑터; 5개 카운트 게이트를 라이브 레지스트리에서 재생성; #/scan 드롭다운 폴백, cvstart.org 소스 링크, help §17 ×18이 따라갑니다.

수정

  • 역할 매처 (#5688 포트): 짧은 대문자 코드만 다른 직함(«HR BP» vs «HR GP», «AWS» vs «GCP», 혼합 스크립트 포함)을 더 이상 퍼지 매치로 같은 공고로 묶지 않습니다; 코드는 노이즈 단어를 제외하고 원시 직함에서 읽히며, 가드는 Jaccard 비율 바로 앞에 놓입니다.
  • 포트들이 최대 강도의 Opus 5-5 리뷰를 통과했습니다 (21개 발견): 마크업 드리프트 시 조용히 빈 보드 대신 throw (google/bwi), 사전 중단된 스캔은 [] 대신 throw, LATAM 스크래퍼의 decode-then-strip 순서 (strip-then-decode XSS 형태), atlassian 행 URL의 https+allowlist, 포트를 거부하는 호스트 단정, 후반 페이지 parse를 try 안으로 (부분 유지), 테스트 정직성(예산 정확히 카운트, 강제 계약을 진실하게 고정). 13개 발견 수정; [spec] 꼬리는 별도 추적.

참고

  • 다섯 RU 소스는 web-ui 전용으로 남습니다(업스트림 어댑터 없음 — 의도적); 모든 EN 소스는 어댑터를 갖습니다.
  • 커버리지 래칫: 6개 대형 포트가 ≥95 % branch로 상향(신규 27 케이스); 방어적 데드 코드 잔여는 파일별 문서화.
  • 새 소스는 portals.yml에서 provider: <slug>로 선택 — 기존 구성에는 변화 없음.

[1.252.1] — 2026-10-17

위키 릴리스 배너는 이제 수동 스윕이 아닌 스크립트로 검증됩니다 — v1.252.0 회귀는 수동으로만 잡았습니다 — 그리고 로케일 디렉티브는 프로필의 language.output과 채용 공고 언어를 명시적으로 재정의합니다.

추가

  • scripts/wiki-banner-check.mjs — 회귀가 요구한 게이트: 위키 클론의 모든 Home*.md를 읽고 배너를 package.json 및 레지스트리의 라이브 카운터(포털 레지스트리의 scanner adapters — 배너의 낡은 109이 아닌 105; server/lib/routes/의 route modules; CHANGELOG 집합의 UI locales)와 비교합니다. 배너 정규식은 단어가 아닌 형태로 언어 독립적입니다: 현지화된 Home 페이지는 라벨과 카운터를 번역하며(«Текущий релиз», «Aktuel udgivelse», «адаптеров сканера», «enhedstests») 그 수치는 EN 페이지(5245)보다 더 밀렸습니다(5177). --tests N은 방금 실행된 test:ci가 출력한 수를 받고, --check-only는 오프라인 사용을 위해 암시적 클론을 금지합니다. 오프라인 픽스처 테스트는 tests/wiki-banner-check.test.mjs.

수정

  • 위키 Home ×18 배너가 다시 동기화됩니다 (이 릴리스와 함께 푸시): v1.252.0 스윕은 배지와 링크만 바꾸었고 배너 줄은 바꾸지 않았으며, 이를 알리는 기계적 장치도 없었습니다. 위의 게이트가 이를 릴리스 차단 검사로 만듭니다.
  • 로케일 디렉티브가 언어 우선순위를 확정합니다 (buildLocaleDirective): «This UI locale overrides the profile’s language.output setting and the job posting’s own language». 부모 자체의 규칙 6은 language.output으로 쓰라고 요구합니다 — 우선순위 문장이 없으면 모델은 두 모순된 지시를 로케일마다 일관성 없게 해소했고, 그것이 v1.252.0 언어 열의 흩어짐이었습니다. tests/locale-directive-language-output.test.mjs가 디렉티브 텍스트(비-EN 17개 로케일 + 빈 EN)로 고정합니다.

참고

  • ta evaluate 형태 관찰 (§3, 주시): v1.252.0의 첫 라이브 실행이 Block G와 SCORE_SUMMARY 없는 48 336자 evaluate를 만들었습니다 — 루프 형태이지 언어 형태가 아닙니다(CAR-70은 언어). 다음 릴리스에서 반복되면 CAR-70과 별개의 Linear 이슈로 갑니다.
  • FIX-PROMPT에 따라: 부모는 읽기 전용으로 두고, 재정의는 전적으로 UI 디렉티브에 삽니다.

[1.252.0] — 2026-10-17

상위 포크가 career-ops-hq/career-ops와 동기화되었습니다 — 업스트림 264커밋, 상위 1.36.0 → 1.37.0 — 포크의 두 분기 모두 지켜졌으며, 배포가 실행 중인 상위를 해당 베이스로 다시 고정합니다.

추가

  • 베트남(vi) 마켓 모드 업스트림 추가(modes/vi/, tuyen-dung / ung-tuyen): BHXH/BHYT/BHTN, thử việc, lương tháng 13, trợ cấp thôi việc — 상위 모드 테이블의 21번째 시장.
  • Tech in Asia 보드 공급자(업스트림): techinasia.com 채용 UI 자체가 쿼리하는 공개 Algolia job_postings 인덱스를 읽습니다 — SEA 스타트업 보드, 샘플링 시 약 300개 라이브 공고 중 273개가 인도네시아. 키는 실행마다 사이트 빌드에서 새로 발견되고, 고용주 자체 지원 링크가 보드 페이지를 이기며, 급여는 첨부하지 않습니다(인덱스의 급여 필드는 돈이 아닌 플래그).
  • Block G 게시 적법성 신호 문서 8개 추가(modes/oferta-signals/08–17): 국가 복지 용어 불일치, 제3자 플랫폼 위치 태그 불일치, 에이전시 라이선싱, 이민 요구 과잉, 관할 금지 콘텐츠, pay-transparency 범위 폭, 최저임금 변호사 질문, AI 스크리닝 공개, 기간제 계약 공개, relocation 구매력.

변경

  • 베이스와 함께 오는 상위 측 강화: story-provenance 검사가 단위·문장 단위로 작동하고 user-cannot-confirm 수치를 협상·ATS·인터뷰 출력에서 배제; CV fact-gate가 모든 렌더러에서 실행되고 재표현·구조화된 주장을 읽음; LaTeX가 쓰기 전에 스테일 추출 슬롯 거부; follow-ups가 꺼져 있으면 launchd 스윕 생략; update-system이 로컬 편집 스캔을 argv 한도 내로 유지.
  • 포크의 분기들이 병합에서 살아남았습니다: providers/telegram.mjs(포크 전용 파서, ADR-0001)와 telegram-channel.mjs의 Unicode lookaround LOCATIONISH_RE(ADR-0002). 보드 문서는 이제 업스트림의 개선된 telegram-channel 행, 포크 전용 telegram 행, Tech in Asia, 그리고 20 → 100으로 올라간 Tencent의 기본 max_pages를 나열합니다.

참고

  • 이 릴리스에는 SPA 동작 변경이 없습니다: 문서 트레인 + 상위 재고정입니다. 배포는 이제 상위 1.37.0에서 실행; 표준 상태 테이블은 상위 델타의 영향을 받지 않아 트래커 상태는 이전과 동일하게 렌더링됩니다.
  • 업스트림 병합에서 두 충돌이 해결되었습니다: docs/SUPPORTED_JOB_BOARDS.md(두 telegram 행 모두 유지)와 test-all.mjs(업스트림의 walkTree 기반 copyDirSync가 포크의 .git 중첩 체크아웃 수동 가드를 대체; 임포트 목록은 합집합).

[1.251.1] — 2026-10-12

전문 분야 필터가 이제 역할의 고유 단어만 매칭합니다 — 연령과 일반 직무 명사는 더 이상 스스로 채용을 매칭하지 않으며 — remote-qa는 언어와 형태를 분리해 드리프트가 A–G를 빨간색으로 표시하지 않습니다.

수정

  • 전문 분야 필터가 고유 토큰만 남깁니다: «Senior PHP Developer»가 공유된 Senior/Developer 때문에 «Senior Java Developer»와 일치했습니다. 매처는 고유 토큰(PHP, Go, Platform, SRE, Backend…)만 유지하고, 고유 토큰이 없는 역할(«Software Engineer»)은 전체 문구 일치로 폴백합니다. 단어 경계는 유지: «Go»는 절대 «Golang»이나 «Google»과 일치하지 않습니다.
  • remote-qa가 형태와 언어를 분리: A–G 플래그는 블록/SCORE_SUMMARY/looping 코드로만 판정; report not in <locale> 드리프트는 자체 플래그와 warnings 열로 이동(표에 누락됐던 4번째 열 추가, 코드는 행별 저장).
  • 지도 툴바가 390px에서 진짜 50/50(58/42 분할이 검색창을 124px로 남기고 자리표시자를 잘랐고), 죽은 .job-map-job-select CSS 규칙 제거.
  • CodeQL 552 — design-qa 테스트의 미사용 OVERLAYS 변수 제거.

참고

  • 마일은 여전히 소유자가 연기. ta 언어 드리프트는 hermes 백엔드의 문서화된 제한으로 유지(실행 간 산문 2–26%; A–G 유지): remote-qa는 이를 예상 finding으로 보고합니다. 일반 토큰 목록은 의도적으로 최소 — 확장은 언어당 한 줄.

[1.251.0] — 2026-10-12

지도의 select가 이제 설정의 전문 분야로 필터링합니다(config/profile.yml → target_roles.primary): «Product Manager»나 «Backend Engineer (Go / PHP)»를 고르면 해당 역할의 단어를 제목에 가진 공고만 남습니다. v1.250.0의 채용 목록 로케이터는 제거됩니다 — 잘못된 도구였습니다(소유자 수정).

추가

  • 전문 분야 필터: select가 설정의 전문 분야(target_roles.primary)를 나열; 하나를 고르면 제목에 그 역할의 고유 토큰을 가진 공고만 남습니다(단어 경계, 대소문자 무시 — «Go»는 «Google»과 일치 안 함); Reset이 전체로 돌립니다.
  • v1.250.0의 채용 목록 로케이터 제거 — 대체: 전문 분야 필터, 채용 목록 아님(소유자 수정).

변경

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

참고

  • 마일은 여전히 소유자가 연기. 매칭은 의도적으로 제목 전용(설정의 단어 사용): 회사명이나 설명까지 매칭하면 무관한 공고가 전문 분야에 끌려들 것. 구성된 모든 역할 밖의 공고는 «모든 전문 분야»에서 계속 보입니다.

[1.250.0] — 2026-10-12

지도 페이지가 실용적으로 바뀝니다: 지도 위의 채용 로케이터가 보이는 채용으로 이동하여 피크를 열고(데스크톱 포함), 텍스트 검색이 회사나 직무로 지도를 좁힙니다 — 둘 다 새로고침에도 유지됩니다.

추가

  • 채용 로케이터: 지도 위 select가 보이는(필터 통과) 채용을 회사+직무순으로 나열; 선택하면 원으로 날아가 피크를 엽니다 — 데스크톱에서도.
  • 텍스트 검색: 회사+직무로 지도를 좁히고 map-prefs에 저장, Reset이 지웁니다.
  • FAB가 #/map의 속성 표기를 가리지 않습니다(모든 너비).

수정

  • 두 모바일 지도 높이 스펙: 하한이 540px로 (툴바가 뷰포트의 ~90px를 차지).

참고

  • 마일은 소유자가 다음 릴리스로 연기. 새 i18n 키 4개가 18개 사전에 들어가고 조립 스냅샷이 재생성됩니다. 로케이터는 항상 피크를 엽니다(이동하면 목적이 사라짐); 원은 __job 역참조로 찾습니다 — L.Circle가 소유한 _point가 아닙니다.

[1.249.0] — 2026-10-11

채용 지도는 이제 관련성을 우선합니다. 차분한 청록색→회색 단계가 가장 적합한 공고를 강조하고, 점수·통근 필터가 저장되며, 모바일은 전체 높이 지도와 탭 미리보기를 사용하고, 트래커도 통근 필터와 정렬을 공유합니다.

[1.248.8] — 2026-10-11

부모 패리티: 포크와 web-ui가 업스트림의 115커밋 델타와 동기화됩니다 — 새로운 PageUp 소스, 트래커 URL 셀을 마크다운 링크로 파싱, Assessment 상태 — 그리고 ta/ja 언어 작업: 루핑 보고서는 잘리고 이름이 붙고, 헤딩 스켈레톤이 A–G를 안정적으로 유지하며, 스크립트 비율은 산문만 읽습니다.

추가

수정

  • 새 PageUp 소스 (EN 어댑터 105 / 소스 110); 트래커 URL 셀을 마크다운 링크로 파싱(href가 중복 제거 키); Assessment 상태는 states.yml로 전달됩니다.
  • 루핑 보고서는 잘리고 이름이 붙습니다(report looping (block B repeated)), 비영어용 헤딩 스켈레톤 ## A) … ## G).
  • 스크립트 비율은 산문만 (표, SCORE_SUMMARY, 코드, URL 제외) — 라틴 표가 있는 일본어 보고서가 더 이상 흔들리지 않습니다.
  • /api/evaluate가 report not in <locale> 경고를 추가하고 remote-qa는 코드를 열로 출력합니다.

참고

  • 미포트(문서화): scan-ats-full 인프라(fetchListing/listingIdentity/_connection-scope — web-ui에는 역방향-ATS 스캔이 없음), liveness 만료-이력 기록기(web-ui는 scan-history를 쓰지 않음; 작성기가 생기면 순수 플래너를 포트), coverage-check/discover/story-bank/pdf –ats/text mode/domain_filter(CLI 전용), dedup-tracker req-id 수정(web-ui에는 dedup-tracker가 없음), README.vi.md(web-ui의 로케일 세트는 자체 것). 부모 포크는 ADR-0001/0002를 방어: telegram.mjs 생존, Unicode LOCATIONISH_RE 유지(업스트림이 ASCII \b로 되돌림).

[1.248.7] — 2026-10-11

보고서 헤더의 역할은 이제 # <역할> — <회사>를 가정하는 대신 부모의 실제 관례인 # Evaluation: {회사} — {역할}을 읽어서 트래커가 «Evaluation: <회사>»를 역할로 담지 않습니다; 잘못된 언어의 보고서는 조용히 저장되는 대신 경고하고, H1 이전의 모델 잡담은 저장된 보고서에서 잘려나갑니다.

수정

  • 현지화된 레이블을 먼저 제거(Evaluation:, Оценка вакансии: 등 16개 변형); 레이블 뒤 Company — Role → 역할은 오른쪽; 레이블 없으면 Role — Company → 왼쪽; 회사를 이름으로 하는 부분이 결정; 역할은 회사와 같거나 레이블 단어일 수 없음 — 정리된 게시물 줄이 폴백.
  • cleanup-plan은 줄의 N을 합산(— N dirty-URL line(s)), 파일을 세지 않음 — 더러운 URL 5개인 파일은 1이 아니라 5.
  • 잘못된 언어의 보고서는 경고: 프롬프트가 언어 지시로 열리고 닫히며(전체 보고서, 표 포함), 파이프라인이 저장된 보고서의 언어를 검사 — 드리프트는 report not in <locale> 경고로 나타납니다.
  • H1 전 모델 잡담 없음 — 보고서는 헤더 줄에서 시작합니다.

참고

  • 포트 안 함·수정 없음(v1.248.6 회귀에서 검증): embed-fetch, 게시물 줄 구조(«Компания : X»), «## Rejected» 중복 제거, fetch 전 도메인 루트 거부, recon/link-check 정직성, cleanup 모드. 언어 검증은 경고입니다 — (내용 A–G + 점수가 검증된) 보고서는 저장되며, 운영자가 드리프트를 보고 재평가할 수 있습니다.

[1.248.6] — 2026-10-10

회귀 후 텔레그램 체인 마감: 실제 게시물은 줄 구조를 유지하고(«Компания : X» 레이블과 역할 줄이 실제 있는 곳에서 발견됨), 트래커 역할은 원시 게시물 줄이 아닌 보고서 헤더에서 오며, 운영 표면(recon, cleanup-plan, link-check)은 주장하는 것을 보고합니다.

수정

  • t.me 게시물이 한 줄로 붙지 않습니다: 태그 제거 전에 <br>가 줄바꿈이 되고 숫자 HTML 엔티티가 디코딩됩니다; 회사 레이블 패턴은 콜론 앞에 공백이 있는 형태도 받습니다.
  • 트래커 역할은 보고서 헤더에서 옵니다 (H1 # <역할> — <회사>); 폴백 줄은 해시태그·이모지 없이 80자 이하로 정리됩니다.
  • ## Rejected가 더 이상 중복되지 않습니다: 섹션은 한 번 만들어지고 각 거부는 그 안에 줄을 추가합니다.
  • 도메인 루트는 요청 전에 거부됩니다 — 쓰레기 URL은 아무 비용도 들지 않습니다.
  • Recon은 계약 신호를 계산합니다 (배포된 코드에서 markPipelineRejected 확인); 마크 카운트가 0을 두 번 출력하지 않습니다.
  • cleanup-plan은 카테고리별 숫자를 보고합니다 (이동할 t-role, dirty-URL 줄, test-row 줄) — 성공 줄을 세던 단일 grep -c 대신.
  • link-check은 github.com 5xx를 미확인으로 처리합니다 — 봇 월 뒤로, 깨진 링크가 아닙니다.

참고

  • 포트 안 함·수정 없음(v1.248.5 회귀에서 검증): embed-fetch 자체, 파이프라인 스킵 계약, _setLookup 오프라인 테스트, uk 서수 허용, 역할 필터의 단어 경계, cleanup-apply 모드. cleanup-plan의 카테고리별 집계는 정리 스크립트 자신의 출력 레이블을 읽습니다 — 레이블 이름 변경은 카운터를 조용히 깨뜨립니다.

[1.248.5] — 2026-10-10

회귀 후 강화: t.me 단일 게시물 항목이 이제 게시물 본문 자체를 가져오고(embed 형식), 거부된 항목은 서버 측에서 평가 타이머 풀을 떠나며, 우크라이나어 보고서의 고유 블록 번호 매기기가 수용됩니다 — 그리고 몰래 라이브 네트워크를 사용하던 하나의 테스트가 영구히 오프라인이 됩니다.

수정

  • t.me 항목이 드디어 평가됩니다: 단일 게시물 페이지는 일반 HTML로 채널 헤더만 제공합니다(~0.2KB — «View in Telegram»뿐), 모델은 빈 설명을 받았고 모든 텔레그램 항목이 평가에서 죽었습니다. 이제 페치가 t.me/<채널>/<id>(및 t.me/s/… 피드 형식)를 embed 형식(?embed=1&mode=tme)으로 재작성합니다 — 동일 호스트, SSRF 검증 변경 없음 — 그리고 .tgme_widget_message_text에서 게시물을 읽습니다(폴백: og:description). 위젯 텍스트가 없으면 → LLM 토큰을 소비하기 전에 페치 단계에서 거부됩니다(telegram post has no text, rejected: true).
  • 평가 타이머가 거부된 항목에 대해 다시 지불하는 것을 멈춥니다(서버 측 계약): 거부된 항목은 이제 data/pipeline.md에 표시됩니다 — 그 줄은 URL 펜스를 떠나 짧은 이유와 함께 ## Rejected 섹션에 들어갑니다(멱등적, 절대 중복 없음). 타이머는 펜스에서 베어 URL을 가져오므로 표시된 항목은 자연스럽게 건너뜁니다 — 타이머 스크립트 내부에 의존하지 않습니다. Recon은 스크립트를 검색하는 대신 pipeline rejected marks: N + honours rejected: yes (server-side)를 출력합니다.
  • 우크라이나어 보고서가 A–G 검증을 다시 통과합니다: uk 모델은 자체 알파벳 순서(А Б В Г Д Є Ж)로 블록 번호를 매기고, lookalike 패스는 А/В/Е만 계산했습니다 — 정확히 블록 C, D, F, G가 프로덕션에서 누락되었습니다(2/2 재현). 유효성 검사기는 이제 제목이 순서대로 나타날 때 우크라이나어 서수 시퀀스를 수용합니다(ar의 abjad, hi의 데바나가리와 동일한 규율), 그리고 모든 로케일에 대한 평가 프롬프트는 이제 라틴 A–G를 명시적으로 요구합니다.
  • 역할 키워드 게이트가 하위 문자열이 아닌 단어로 작동합니다: linkedin.com/과 x.com/ 루트는 lead/it가 페이지의 무관한 UI 텍스트 안에 살아 있었기 때문에 게이트를 통과했습니다. 키워드는 이제 유니코드 단어 경계에서 일치하고, 도메인 루트(경로 없는 URL)는 LLM 호출 전에 거부됩니다.
  • 단위 테스트가 더 이상 라이브 네트워크를 필요로 하지 않습니다: no-hints 테스트(tests/auto-pipeline-jd-gate.test.mjs)는 HTTP 전송을 스텁했지만 여전히 실제 DNS 조회를 수행했습니다 — 러너에 연결성이 있었기 때문에 CI에서만 녹색이었습니다. safe-fetch에 _setLookup() 훅이 생겼습니다(테스트에서 리졸버 자체를 교체 가능; 프로덕션 코드는 절대 재정의하지 않음), 테스트는 오프라인에서 해석합니다.

추가

  • deploy.yml의 cleanup-plan / cleanup-apply 워크플로 모드: 프로덕션 QA 정크 정리(post-qa-cleanup)가 노트북에서 SSH 없이 서버 측에서 실행됩니다. 로그는 숫자만 담습니다 — 파일 이름이나 줄 미리보기 없음, 로그가 공개되고 파일 이름에 회사 이름이 포함되기 때문입니다. Verify 단계는 정리 모드에서 건너뜁니다.

참고

  • 포트되지 않음: 부모의 단어 경계 기반 위치 컴파일러와 USPS 주 테이블(v1.248.1부터 문서화됨). 거부된 항목 건너뛰기 계약은 타이머 스크립트가 아닌 서버(data/pipeline.md 마킹)에 있습니다 — 그 스크립트는 저장소 밖에 있으며 의도적으로 수정하지 않습니다.

[1.248.4] — 2026-10-10

회귀 라운드의 연장: 평가 타이머가 어떤 경우에도 이름 없는 Telegram 쓰레기를 보고서로 보관할 수 없게 됐고, QA 정리가 진짜 Telegram 채용공고를 삭제하지 않으며, 지도 저작권 표기가 다시 보이고, 대시보드 칩이 ≥ 4.5:1로 읽힙니다.

수정

  • 역할 해결 체인이 키릴 문자 게시물에서 작동합니다: 키워드 목록에 разработчик/программист/инженер/аналитик/менеджер/руководитель/тимлид/лид/дизайнер/тестировщик/QA/архитектор/специалист/директор/DevOps/SRE가 추가되었고(이전 목록은 EN 전용: 실제 게시물 40개 중 0개가 역할을 얻었습니다), 보고서 헤더를 참조하며(parseReportHeader — 모델이 H1에 역할을 씁니다), 게시물의 첫 의미 있는 줄이 마지막 수단입니다.
  • 신원 게이트가 LLM 호출 전으로 이동했습니다: 회사도 역할 단서도 없는 항목은 fetch 단계에서 실패합니다(rejected: true) — 어차피 거부될 평가에 토큰을 낭비하지 않습니다.
  • t.me/s/<channel>/<id>가 회사를 「S」라고 부르지 않습니다 — 미리보기 세그먼트는 건너뛰며, 두 링크 형식 모두 채널로 해석됩니다.
  • Telegram 게시물의 「Компания: X」 자기 라벨이 존중됩니다(메신저 호스트의 문장 중간 「…в компании X」도).

추가

  • auto-pipeline 실패는 SSE 오류에 rejected: true를 실습니다 — 서버 측 평가 타이머는 이 플래그로 pipeline 항목을 건너뛰고 2시간마다 재시도를 하지 않습니다.

참고

  • 미포팅: 부모의 word-boundary 위치 컴파일러와 USPS 테이블(v1.248.1부터 문서화).
  • README의 「Translations」 블록은 단일 정준 목록에서 생성되며 CI에 패리티 테스트가 추가됐습니다(파일당 17개 링크, 자신은 비링크) — ar/pl/uk가 블록을 얻었고 |/· 구분자 드리프트가 해소됐습니다.

[1.248.3] — 2026-10-10

회귀 라운드의 연장: 평가 타이머가 어떤 경우에도 이름 없는 Telegram 쓰레기를 보고서로 보관할 수 없게 됐고, QA 정리가 진짜 Telegram 채용공고를 삭제하지 않으며, 지도 저작권 표기가 다시 보이고, 대시보드 칩이 ≥ 4.5:1로 읽힙니다.

수정

  • auto-pipeline이 저장 전에 검증합니다: 0–5 점수가 없거나 A–G 블록이 빠진 보고서는 evaluate 단계에서 실행이 끝납니다(SSE 페이로드에 rejected: true) — 보고서 파일도 트래커 행도 없습니다. v1.248.2 길이 게이트를 통과하던 t.me 항목들이 그 이후 두 건의 쓰레기를 더 냈지만, 이제 이름 없는 항목은 company/role not identifiable로 거부됩니다.
  • guessCompanyRole이 메신저 호스트에서 회사를 지어내지 않습니다 — t.me·telegram.me·vk.com·linkedin.com 등이 EMPTY_DOMAINS입니다: Telegram 게시물은 채널 이름으로 폴백하고, 이름 없는 항목은 unknown-role로 보관되지 않고 거부됩니다.
  • post-qa-cleanup이 헤더 점수를 먼저 읽습니다: auto-pipeline은 저장 전에 SCORE_SUMMARY 블록을 잘라내므로, 예전의 summary 전용 검사는 저장된 모든 Telegram 공고를 쓰레기로 판정했습니다 — 본선의 41개 중 8개가 헤더에 점수가 있었고 --apply는 그것들을 삭제할 뻔했습니다. 헤더 점수(parseReportHeader 경유)가 이제 1차 신호이고 블록은 폴백입니다. dry-run은 파일별 사유를 인쇄합니다.
  • #/map에서 Leaflet 저작권 표기가 보입니다 — docs FAB가 가렸던 것(OSM 라이선스 위반); 코너가 96px 올라갔습니다.
  • 대시보드 칩이 ≥ 4.5:1 — dash-chip 라벨과 --manual 변형이 --foggy-strong으로(이전 4.31:1).

추가

  • auto-pipeline 실패는 SSE 오류에 rejected: true를 실습니다 — 서버 측 평가 타이머는 이 플래그로 pipeline 항목을 건너뛰고 2시간마다 재시도하지 않습니다.

참고

  • ar/ja 드리프트는 재실행에서 재현되지 않았습니다(v1.248.2 참조).
  • 본 정리는 사용자의 명시적 「예」를 기다립니다(CAR-61c); 이 수정으로 정리가 진짜 Telegram 채용공고를 삭제할 수 없게 됐습니다.

[1.248.2] — 2026-10-10

회귀 라운드: 평가 타이머가 파이프라인 쓰레기를 더 이상 「Last evaluation」으로 만들지 않고, SCORE 파싱이 실제 형식을 견디며, 트래커가 마침내 당신의 언어로 말합니다.

수정

  • 빈 JD 보고서는 더 이상 작성되지 않습니다. auto-pipeline의 JD 게이트가 LLM 호출 전 50 → 200자로 올랐습니다 — 플레이스홀더 페이지(example.com/qa-v167-…)는 …-t-role-<ts>.md 보고서 대신 SSE 오류 + 콘솔 경고로 끝나며, 대시보드가 「Last evaluation」으로 표시하던 것(본선에 42개 파일)을 막습니다.
  • SCORE_SUMMARY 파싱이 실제 형식을 견딥니다: 「4,2/5」「4.2 / 5」「4.2」「SCORE :」 모두 유효. 쉼표 뒤 1–2자리는 소수, 3자리는 천 단위(이전 코드는 「4,200」을 4.2로 읽어 0–5 게이트를 통과했습니다). 실패 시 보고서 내용이 아니라 SCORE: 줄만 로그에 남습니다(CI 로그는 공개).
  • 트래커 상태가 번역됩니다: 스테이지 탭과 상태 배지가 18개 로케일에서 현지화된 라벨을 표시; 데이터·필터·URL의 canonical 값은 그대로입니다.
  • 정직한 ETA: 「⏱ ~30s」가 evaluate/advisor/시장 보고서에서 「~2–4분」이 되었고(실제 범위 86–285초), evaluate 부제목은 A–G를 읽습니다.
  • 접근성: config의 API-keys 카운터와 pipeline 카운터가 이제 4.5:1을 넘습니다(이전 4.31:1); 빈 값을 가진 패싯 칩이 접근 가능한 이름 없이 렌더링되지 않습니다.
  • UI 폴리시: 저장 검색의 Delete는 선택된 경우에만 파괴적으로 보이고(그 외 disabled), 프로필 EMAIL 카드는 1440px에서 잘리지 않으며, live-evals 필에 아이콘/텍스트 간격이 생겼고(RTL 포함), docs FAB가 Leaflet 속성을 가리지 않고, help의 「?」가 stats 탭 아래로 줄바꿈되지 않으며, usage는 부제목과 범위 탭 사이에 여백이 생겼고, health는 이제 career-ops-ui라고 말합니다.

추가

  • scripts/post-qa-cleanup.mjs: 기본 dry-run, --apply 시 자동 백업(*.bak-<ts>, 보고서는 qa/cleanup-backup-<ts>/로 이동): 트래커의 ZZ-QA-TEST 행, 유효한 SCORE 없는 *-t-role-* 보고서, pipeline의 example.com 항목.

참고

  • 회귀 라운드의 ar/ja 드리프트는 재실행에서 재현되지 않았습니다(모두 lang ✓ + A–G ✓) — language-check의 ta 항목과 강화된 SCORE 파서는 방어 깊이로 출시됩니다.
  • 프로덕션 청소는 사용자의 명시적「예」를 기다립니다: 먼저 dry-run 계획, 그다음 --apply.

[1.248.1] — 2026-10-09

location_filter에 부모의 always_allow와 block_hard 티어가 추가됐습니다(CAR-60) — 다국적 위치 문자열이 형제 차단 목록을 생존하고, 명시적 하드 차단은 더 이상 구제되지 않습니다.

수정

  • always_allow가 block를 이깁니다: block: [romania, poland, croatia]와 always_allow: [united kingdom]일 때 workable 병합 셀 「London, United Kingdom · Romania · Poland · Croatia」는 통과 — 홈 리전이 옵션에 있습니다(workable #4806의 소비자 케이스, 이제 부모 형태로).
  • block_hard가 always_allow를 이깁니다: 문자열 어디선가 always_allow 적중으로 구제되어서는 안 되는 국가 수준 용어입니다.
  • strict: true는 이제 block_hard를 제한 티어로 계산합니다; docs/help의 location_filter 섹션에 두 티어를 ×18로 문서화했습니다.

참고

  • 이번에는 의도적으로 미포팅: 부모의 단어 경계 로케이션 키워드 컴파일러와 USPS 주 이름 테이블(web-ui는 부분 일치 유지; 테이블은 미국 중심 설정용 — 필요하면 CAR-60으로). workable 소비자 테스트의 과도 allow-list 형식은 새 부모 형식과 함께 두 번째 판정으로 남습니다.

[1.248.0] — 2026-10-09

부모 패리티: 업스트림 제공자/liveness 수정 5건 포팅 — API를 옮긴 보드도 계속 작동하고, 독립 줄의 마감 배너가 더 이상 놓치지 않습니다.

수정

  • Gupy가 API를 portal.gupy.io로 따라가며 API가 실제로 읽는 필터 이름(workplaceType/type)을 전송 — 이전 복수형 이름은 조용히 무시되었습니다. country는 더 이상 전송되지 않고(설정된 국가는 전송 대신 항목 이름으로 경고), 기밀 고용주는 라벨 완전 일치로 드롭되며(「Confidencial Seguros」는 생존), max_pages는 100으로 제한 — API는 offset 10,000을 넘으면 400을 반환하고, 잘림 경고는 이제 한도 올리기 대신 키워드를 좁히라고 안내합니다.
  • Workable은 다국적 공고의 모든 국가를 유지합니다: 같은 채용 URL 아래 형제들이 한 행으로 접힙니다(「London, United Kingdom · Romania · Poland · Croatia」) — 첫 국가가 이기는 대신.
  • Liveness: 독립 줄의 배너는 윗줄의 일부가 아닙니다 — 공고 아래의 「Sign in if you want to apply」/「Get notified when this position is filled」은 마감 절로 읽히고, 줄에 걸친 실제 「until filled」은 여전히 활성으로 읽힙니다.
  • Radancy가 레거시 카드 마크업의 형제 job-location 요소를 읽습니다(Barclays 계열 레이아웃은 위치를 </a> 뒤에 둠) — 자체 위치가 없는 행은 이웃 것을 빌리지 않고 빈 채로 남습니다.
  • SmartRecruiters 폴백 채용 링크는 설정된 슬러그를 유지합니다 — 신뢰할 수 없는 ref가 없는 공고는 표시 이름이 아니라 테넌트 슬러그에서 공개 URL을 합성합니다.

추가

  • 노포트 문서화: 업스트림 _http 프록시 fetchImpl 수정(web-ui에는 프록시 분기가 없어 포팅하면 DNS-rebinding 가드의 동일성 검사가 무력화되고 저장소가 의도적으로 피하는 undici 의존성이 추가됨); 업스트림 verify-ats(+226줄)와 cv-facts(web-ui는 자체 ATS 스코어링과 CV 파싱 구현); 부모 대시보드 Go TUI와 CLI 스크립트; Teamtailor import 재배열(외관상).

참고

  • 알려진 갭을 후속으로: 부모 location 필터의 always_allow 티어(workable 소비자 테스트가 이것으로 UK 블록을 생존)가 web-ui에는 없습니다; 포트는 동일한 소비자 판정을 허용 목록 테스트로 표현했습니다. 별도 변경으로 기록.

[1.247.0] — 2026-10-09

CAR-49…58 디자인 스윕의 꼬리가 완료됐습니다 — 남은 minor/polish 발견 전부와, 이전 릴리스가 의도적으로 미뤄둔 다크 맵까지.

수정

  • 맵이 진짜 다크 테마를 렌더링합니다. 줌/레이어/속성 표시는 v1.246.0에서 어두워졌고, 이제 타일도 따라옵니다: 다크 모드는 CSS 반전된 OSM 레이어를 그립니다(벤더 키 불필요), 키가 있는 Carto-dark 프리셋은 MAP_TILE_DARK_URL로 사용 가능(그 호스트는 CSP img-src에 허용됨). 테마 전환 시 레이어를 라이브로 다시 마운트합니다.
  • 노란 콜아웃에 다크 변형이 생겼습니다(config, batch, hero 경고) — v1.246.0 토큰 메커니즘 사용. 과정에서 회귀도 포착: .callout a가 .btn-primary을 덮어쓰던 것을 :not(.btn)으로 스코프.
  • Apply 정보 카드의 URL이 단어 중간에서 잘리지 않습니다.
  • CV 헤더 버튼은 단일 아이콘 체계 (텍스트; 📁/📄/💾 이모지 혼용 해소).
  • 트래커 상태 탭의 대소문자 통일 — sentence case, 로케일별 배려 포함(CJK/ar/hi/ta는 성 형태 없음).
  • 상단바 아이콘을 단일 스트로크 SVG 세트로 — 🔔/🌙/🩺 혼용 해소; 테마 버튼의 해/달은 CSS로 그립니다.
  • 대시보드 Pipeline 카드의 분홍 강조 제거 (링은 hover/focus에만).
  • 저장 검색 삭제가 파괴적임을 보여줍니다 (.btn-danger, 중립 고스트 아님).
  • pipeline 미리보기에 실제 빈 상태 (제목 + 힌트 + CTA, 트래커 패턴).
  • 시간/비용 메타는 하나의 패턴: UI.pageMeta가 ⏱ + 비용을 뷰 제목 아래 한 줄로 그립니다(evaluate/deep/auto/mode-page/orientation).
  • Auto-pipeline에서 ✨ 제거 — 앱 유일의 장식 h1이 공통 왼쪽 가장자리로 복귀.
  • Batch docs URL 인라인 링크화.
  • interview-digest / orientation에 디자인된 빈 상태 (제목 + 힌트 + CTA).
  • career-plan Export는 플랜이 없으면 비활성, 액션은 한 행에.
  • stats: 중복된 「Market report」 제거, 지역 플레이스홀더도 들어맞음(×18 짧게, 고정 폭).
  • Config가 절대 경로를 새지 않습니다 — 서버 측 displayPath()가 ~/… 또는 파일 이름만 표시.
  • LLM_PROVIDER 헬퍼는 세 줄 요약 (×18 + pre-line), 150자 mono 벽 해소.
  • 프로필 EMAIL 카드는 주소를 한 줄로 유지 (줄임표; ≤480px에서만 줄바꿈).
  • Health 텍스트가 단어를 깨지 않습니다(「Run buttons」 온전; overflow-wrap anywhere).
  • Help의 인라인 코드는 RTL에서도 살아남습니다(LTR 아이솔레이트, nowrap, 스크롤 가능).
  • Hero의 「Live evals」 필이 ru/ar에서 충돌하지 않습니다(flex-wrap, 비축소 아이콘).

추가

  • 다크 타일 프리셋(MAP_TILE_DARK_URL + attribution)을 코드에 문서화; CSP img-src 추가로 Carto 호스트를 허용.

참고

  • 다크 타일 기본값은 OSM의 CSS 반전입니다 — 키 없는 Carto가 베이스맵을 API 키 뒤로 닫았으므로(요청으로 확인), 키 프리셋은 옵트인이며 기본값이 아닙니다.

[1.246.0] — 2026-10-09

CAR-48 시니어 디자인 스윕의 상위 10개 발견 항목을 모두 수정했습니다 — 블로커와 7개의 major 전부 포함입니다.

수정

  • Apply 다크 모드: 정보 카드의 링크가 다시 보입니다. 카드가 다크 모드에서도 밝은 표면을 유지해 «Need Playwright? See …» 링크가 ≈1.0:1이었습니다. 테마 인식 .callout--info(surface/border/text/link 토큰)로 다크 링크가 ≈7.3:1로 올라갑니다.
  • RTL이 숫자 조합을 뒤집지 않습니다. 점수 필(«1.5 / 5»), 리포트 밴드(«≥ 4.5», «< 3.5»), 대시보드 «/ 5.0»에 방향 아이솔레이션(LTR span)을 적용하고, ar 사전은 산문으로 자연스러운 구간은 단어로 다시 썼습니다.
  • CV 마크다운은 LTR 유지. 아랍어에서도 textarea와 미리보기는 dir="ltr"로 렌더링되고 주변 크롬은 RTL을 유지합니다.
  • 리포트 DATE 열은 ISO 날짜를 다신 감싸지 않습니다(nowrap + 표 형식 숫자).
  • 사이드바가 USAGE HUD 위에서 끝납니다(스크롤포트 예약 + 페이드) — 마지막 내비 항목이 패널 아래로 지나가지 않고, RTL도 미러링했습니다.
  • 모바일 스캔 @390: «Save search»가 온전히 보입니다 — 컨트롤 행이 줄바꿈·압축되어 뷰포트 가장자리에서 잘리지 않습니다.
  • 지도 컨트롤이 다크 테마를 따릅니다(줌·레이어·속성 표시). 타일은 의도적으로 그대로입니다: 타일 origin은 서버 측 CSP img-src로 고정되어 있습니다.
  • 채팅 FAB가 인터랙티브 요소를 가리지 않습니다 — 페이지 스크롤 패딩이 여유를 확보합니다(Portals의 Disable 버튼, Reports의 점수 필, two-pager 입력, Leaflet 속성 표시).
  • 활동 로그가 UI 언어로 말합니다: 22개 액션 슬러그를 ×18 로케일로 현지화(모르는 것은 원시 id 폴백), 필터 칩도 번역. TARGET 열은 auto-pipeline이 채우므로 유지합니다.
  • assessments 폼에 실제 레이블(문장 대소문자, htmlFor/id 결합) — 플레이스홀더 전용에서 개선.

참고

  • 이 릴리스에 없음: 지도 다크 타일(CSP img-src 확장 필요 — 서버 측 변경이라 의도적으로 클라이언트에서 하지 않음); 노란 콜아웃의 다크 변형(config, batch) — 토큰 메커니즘은 후속 작업을 위해 준비됨.

[1.245.0] — 2026-10-09

타밀어(தமிழ்)가 18번째 UI 로케일로 합류합니다 — 17 로케일 물결 이후 처음으로 새로 추가되는 언어이며, 키 완전 패리티를 갖춥니다.

추가

  • 타밀어(ta): 1449/1449 키, en 대비 완전 패리티, 누락된 플레이스홀더 없음, hi 스타일 인도계 테크 관례 적용(프로바이더·모델명·경로·명령은 라틴 문자 유지). detect()는 ta, ta-IN, ta-LK를 받습니다. 타밀어는 LTR(테스트로 고정).
  • docs/help/ta.md 전체 번역(H2 33 / H3 125, 소스 개수는 라이브 레지스트리와 대조, Hermes 카나리아 앵커, YAML 축자 수록)과 README.ta.md·CHANGELOG.ta.md 미러.
  • 열거 게이트 17 → 18: LANGS, detect 프로브, i18n 감사, 체인지로그 패리티, RTL 가드, CI langs — 아울러 CI 목록에서 누락됐던 hi도 추가.

참고

  • cvstart.org 랜딩은 당분간 17 로케일 유지 — 랜딩 번역은 별도 작업입니다. 사이트 콘텐츠 동기화는 이미 docs/help/ta.md와 ta 체인지로그를 배포합니다.
  • report-header.js의 REPORT_LABELS는 17 유지 — 타밀어 보고서 파싱은 부모 저장소의 타밀어 보고서 생성과 함께 제공됩니다.

[1.244.2] — 2026-10-08

스캔 페이지 폴리시: 런처, 상태 바, 리포스트 패널, 필터가 일관된 크롬으로 재설계되었습니다 — 그리고 결과 테이블은 보드 데이터로 더 이상 늘어나지 않습니다.

수정

  • 급여 셀은 금액 범위만 표시합니다. 일부 보드는 복리 혜택 설명 전체를 급여 필드에 넣습니다 — 표시 셀은 이제 금액 부분만 보여주고 전체 텍스트는 툴팁으로 이동했습니다(이전: 6줄 셀이 모든 행을 늘렸습니다).
  • 제목이 빈 행은 회사명을 표시하고(그다음 중립 대시) 거대한 빈 셀 대신 표시합니다.
  • 시니어리티 배지는 고정 폭 열에서 절대 줄바꿈하지 않습니다.
  • 점수 없는 행은 흐린 «◎ —»를 표시하며 툴팁에 two-pager 비교에서 일치하는 키워드가 없었다고 설명합니다(이전: 점수 있는 행 옆에서 깨진 것처럼 보였습니다).
  • aux 높이 계약: 이제 aux 셀 내부의 콘텐츠 요소를 측정합니다 — td는 행 높이까지 늘어나 실제 줄바꿈을 가렸습니다.

추가

  • 크롬 재설계: 런처 카드(정렬된 컨트롤 행, 지배적인 프라이머리 버튼), 상태 점(대기/실행/완료/오류)이 있는 터미널 상태 표시줄은 reduced-motion을 지원합니다, 리포스트 패널은 높이 상한과 스티키 헤더가 있습니다(1,560 클러스터가 155,000px 패널을 렌더링했습니다), 필터 블록은 균일한 반응형 그리드와 정렬된 푸터입니다.

참고

  • 테스트 5045 → 5068 유닛; 브라우저 레이아웃 계약 확장(aux 한 줄 경계).
  • 이 릴리스에 없음: URL 해시 필터 상태, 키보드 행 탐색, 5 lakhs INR 파싱(기존 후속). live-LLM × 7 로캘은 업스트림 크레딧으로 차단되었다가 해제됨(CAR-44).

[1.244.1] — 2026-10-08

수정

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

참고

  • Everything else in #/scan is identical to v1.244.0 — only the three regression fixes above changed.
  • Deliberately not done: URL-hash filter state, keyboard row navigation and 5 lakhs INR parsing (all pre-existing follow-ups).

[1.244.0] — 2026-10-08

스캔 결과가 벽이 아니라 목록처럼 읽힙니다: 한 공고 = 두 줄, 신호는 아이콘, 700행 스캔은 37,000px 페이지 대신 페이지가 있는 표입니다.

수정

  • 행 구조. 각 공고는 두 줄의 경계가 있는 행으로 렌더링됩니다: 1행은 제목, 2행은 company · location · source · date · work-type. 부스트 배지, 제목 적합도 밴드, 적합도 점수가 지역화된 접근 가능한 이름과 툴팁이 있는 아이콘이 되었습니다(스크린 리더는 단어의 벽이 아니라 «Соответствие: сильное» / “Fit: strong”을 읽습니다); 신뢰 및 재배치 배지도 같은 레일에 접혔습니다. 시니어리티와 급여는 데스크톱 전용 보조 열로 남습니다.
  • 제목 위생. 뒤에 붙는 | Germany | Remote 세그먼트는 제목에서 메타 줄로 분리됩니다 — 유니코드 인식, 꼬리가 실제 근무 형태 마커이고 중간 세그먼트가 지역 형태일 때만 (「C++ | Rust | Go Developer」 같은 정당한 파이프는 절대 분리되지 않습니다).
  • 가로 번창 종료. 고정 테이블 레이아웃, min-width: 0, 툴팁에 전체 텍스트가 있는 말줄임표 한 줄 제목/메타: 1440px와 390px에서 페이지 오버플로 0, 내부 테이블 스크롤 0 (이전 페이지는 모바일에서 675px 넘쳤습니다).
  • 페이지네이션. 결과는 페이지당 50개로 렌더링됩니다(25/50/100/200 선택 가능) — 700행 스캔은 이제 ~37,000px 대신 ~4,600px이고 DOM은 5,500+ 대신 ~1,000 노드를 유지합니다.

추가

  • 레이아웃 계약 테스트: 두 줄 행, 아이콘의 접근 가능한 이름(en + ru), 페이지네이션 노드 예산, title-fit 카운트/순서 가드가 브라우저 스위트에서 실행됩니다 — 리디자인이 조용히 회귀할 수 없습니다.

참고

  • 테스트 5036 → 5045 유닛, 브라우저 스위트에 레이아웃 계약 추가, 평균 커버리지 98.14 % 라인 / 89.34 % 브랜치(하한 96/86).
  • 스캐너가 찾는 것, 점수 공식, last-scan.json은 건드리지 않습니다 — title-fit은 어노테이션으로 남습니다.
  • 이 릴리스에 없음: URL 해시 필터 상태와 키보드 행 탐색(다음), 5 lakhs INR 파싱(기존).

[1.243.2] — 2026-10-08

수정

  • 배포 가능한 릴리스가 v1.243.2로 잘렸습니다. v1.243.1 태그는 게시 후 재지정되었고, 서버의 git fetch --tags는 기존 태그를 덮어쓰기를 올바르게 거부합니다 — 그래서 v1.243.1은 배포 가능하지 않았습니다. 이 태그는 동일한 트리(v1.243.0 기반의 트래커 결과-모달 window-리스너 수정)와 이 버전 상승을 담습니다. 다른 변경은 없습니다. 게시된 npm 1.243.1 타르볼에는 이미 수정이 포함되어 있습니다.

참고

  • 앱 코드는 v1.243.1과 동일합니다 — 새로운 배포 가능 태그만 추가되었습니다(서버의 git fetch --tags가 재지정된 v1.243.1을 거부했습니다).
  • 의도적으로 하지 않음: 게시된 태그를 강제로 이동(서버 측 태그 강제 갱신 안 함).

[1.243.1] — 2026-10-08

수정

  • 「결과 기록」모달이 이제 내비게이션 시 실제로 닫힙니다. v1.243.0 가드는 document에서 hashchange를 기다렸지만 이 이벤트는 거기서 발생하지 않습니다 — 수정은 죽은 채로 배포되었고 모달은 다음 뷰를 계속 막았습니다(v1.243.1 회귀 라운드에서 프로덕션에서 발견). 가드는 window에서 대기하도록 바뀌었고 테스트도 거기서 디스패치하며 깨진 코드에 대해 빨강으로 검증되었습니다.

[1.243.0] — 2026-10-08

브라우저 레이어가 작업물을 안전하게 지키고 여러분의 언어로 말합니다: 저장하지 않은 편집 손실 없음, 조용한 실패 없음, 번역된 UI에서 조용히 남는 영어 없음, 모든 곳에서 AA 대비.

수정

  • 저장하지 않은 편집이 리렌더링을 넘어 유지됩니다. CV 편집기는 dirty 버퍼를 유지하고 매 렌더링마다 복원합니다 — 취소, 언어 전환, CV Studio로 이동이 이제 조용히 버리는 대신 확인을 요청하며, 커리어 플랜도 같은 방식으로 생성된 텍스트를 지킵니다. Config/CV Studio/career-plan/memory/two-pager에서 로드가 실패하면 조용히 빈 내용으로 파일을 덮어쓰는 대신 오류를 표시하고 Save를 비활성화합니다.
  • “결과 기록” 모달이 더 이상 내비게이션을 넘어 남아 있지 않습니다. #/tracker에서 열어 둔 채 다른 화면을 클릭하면 모달이 페이지 전체를 막고 있었습니다(v1.242.1 two-stand 회귀에서 발견) — 이제 라우트가 바뀌면 닫힙니다. 스캔 화면의 형제 모달들도 내비게이션 시 SSE 스트림을 멈추고 리스너를 분리합니다.
  • 연봉과 키워드 파싱이 모든 문자 체계를 읽습니다. 키워드 칩은 유니코드 단어 경계를 사용합니다(키릴 문자, c++, .net이 0행으로 사라지는 대신 올바르게 필터링됩니다). 하나로 공유되는 연봉 파서가 $182.9K - $240K, от 100 000 руб, 100 тыс. руб., 50 000 Kč(이전에는 5천만 USD로 읽힘)와 범위 의미론($100-150K)을 바로잡습니다. 필수 조건 “독일 또는 네덜란드”가 더 이상 일치와 위반을 동시에 세지 않습니다.
  • 스트림은 정확히 한 번 정리됩니다. 끊어진 SSE 연결이 오류를 두 번 전달해 Generate 버튼이 영원히 비활성화된 채 남을 수 있었습니다. 모든 종단 상태(done/error/close/throw, 죽은 자식 프로세스 포함)는 하나의 경로로 정리되고 버튼을 다시 활성화합니다. auto-pipeline은 마지막 버퍼 프레임을 버리는 대신 플러시합니다.
  • 작은 경로 속의 개인정보와 정확성. 버그 리포트 본문은 더 이상 평가된 공고 URL이나 리포트 슬러그를 담지 않습니다. CV 개인정보 가림이 맨 linkedin.com/in/… 링크와 전부 대문자인 이름을 가리며 EU 날짜를 더 이상 망가뜨리지 않습니다. 국가 판별은 가장 긴 일치를 택하고 두 국가가 함께 언급되면 추측을 거부합니다(“Cambridge, MA”는 더 이상 영국으로 판정되지 않습니다). 파일명 다운로드는 키릴 문자 이름을 유지합니다.
  • 라우터와 접근성. 스킵 링크가 더 이상 ontent로 404를 내지 않습니다. 활성 내비게이션 항목은 aria-current="page"를 가지며 <main>과 <nav>는 각각 하나뿐입니다. Escape가 모바일 드로어를 닫고(닫힌 드로어는 이제 탭 순서에서 진짜로 벗어납니다), scroll-padding-top이 sticky 바 너머까지 포커스를 보이게 유지하며, sticky 배너가 더 이상 탑바를 가리지 않습니다.
  • 두 테마 모두에서 대비가 AA입니다 — 다크 토스트는 흰 바탕에 흰 글자였습니다(1.10:1). 이제 --rausch 위의 토스트, 버튼, 배너, 링크는 테마 불변 토큰으로 결정되며, 계산된 WCAG 계약 테스트(≥ 4.5:1)가 이를 보호합니다.
  • 이번 라운드의 나머지 전부: evaluate는 잘림 경고를 렌더링하고, memory/config/two-pager는 실패한 로드 위에서 Save를 거부하며, scan은 SSE를 고아로 남기지 않습니다. 스캔 결과는 흘러간 정규식 대신 서버 레지스트리에서 API 기반 보드를 분류하고, 트래커의 “Proceed with Caution”은 경고이지 badge-red가 아니며, stats는 현지화된 상태를 반영하고, 막대 차트는 RTL에서 올바르게 읽히고, docs FAB는 더 이상 휴대폰에서 콘텐츠를 가리지 않으며, GET /app.js는 인덱스 셸 대신 404로 답하고, GET /api/runners는 자신의 액션을 나열합니다.

추가

  • 덴마이크어가 자동 감지에 합류 — da-DK 브라우저가 이제 덴마이크어 UI를 받습니다(사전은 완비되어 있었고 감지가 놓치고 있었습니다). zh-Hant*는 번체 중국어로 매핑됩니다. cv-diagnostics(이력서 체크리스트)가 완전히 현지화되었습니다(28개 diag.* 키 × 17). 필드 명세 라벨 26개가 추가되고 죽은 키 31개가 제거되었습니다. 제공자 목록은 더 이상 Hermes가 “자동 순서의 마지막”이라고 주장하지 않으며, docs-fab/메뉴 aria-label이 현지화되었습니다.

참고

  • 테스트 4812 → 5036 단위, 브라우저 118 + 새 탐색/대비 계약, 커버리지 평균 라인 98.15 % / 분기 89.34 %(하한 96/86).
  • 이번 릴리스에서 제외: #/scan 리디자인(Phase 4 — v1.244.0, 스펙 초안 작성됨). 전용 export.docxFailed 사전 키(실패 시 common.error를 재사용). 5 lakhs INR은 여전히 5로 파싱됩니다(기존 문제).

[1.242.1] — 2026-10-08

수정

  • 릴리스 아카이브에 node_modules 심볼릭 링크가 다시 포함되지 않습니다. v1.242.0 깃 태그에 루트 node_modules 심볼릭 링크와 site/node_modules가 포함되어 있었고(포괄적인 git add -A가 후행 슬래시가 있는 ignore 패턴을 우회했습니다), 서버 배포의 tar 추출이 실패했습니다 — 배포는 안전하게 롤백되었고 프로덕션은 1.241.1을 유지했습니다. 두 심볼릭 링크는 추적에서 제거되고 ignore 패턴이 확장되었습니다. npm 타르볼은 영향을 받지 않았습니다(패킹 시 npm은 node_modules를 제외합니다).

참고

  • 앱 코드는 v1.242.0과 동일합니다 — 패키징만 변경. 소스 정정 내용은 이 배포로 프로덕션에 반영됩니다(v1.242.0은 프로덕션에 도달하지 못했습니다. tar 실패로 서버 배포가 롤백되었습니다).
  • 의도적으로 하지 않음: v1.242.0 재태깅(npm은 이미 1.242.0을 게시했습니다. 레지스트리 타르볼은 깨끗합니다 — 패킹 시 npm은 node_modules를 제외합니다).

[1.242.0] — 2026-10-07

스캐너의 데이터 레이어가 다시 신뢰할 수 있게 되었습니다: 죽었던 소스가 살아났고, 형식이 잘못된 답변이 더 이상 빈 보드로 위장할 수 없으며, 적대적인 보드 URL이 더 이상 스캔을 리디렉션할 수 없습니다.

수정

  • 죽었던 소스가 다시 살아났습니다. justjoin(API 엔벨로프가 {data, meta.next.cursor}로 변경)은 새 연봉 필드와 함께 커서 순회로 전체 카탈로그를 읽습니다. nofluffjobs는 salaryCurrency 없이 400으로 답합니다 — 상위 프로젝트의 필수 쿼리를 보내고 결과를 페이지네이션합니다(pageTo). himalayas와 jobicy는 10만 건 이상 중 최신 약 20건만 봤습니다 — 이제 둘 다 전체 카탈로그를 순회합니다(페이지 상한이 있는 오프셋 / 커서 페이지네이션).
  • 잘못된 형태의 200은 첫 페이지에서 예외를 던집니다. 약 40개 소스가 형식이 잘못된 답변이나 챌린지 응답을 “공고 0건”으로 읽어 스캔이 조용히 “성공”했습니다. 새 server/lib/sources/_shape.mjs 가드(requireArray / requireContainer / requireObject)가 모든 패밀리에서 실패를 크게 알립니다. 이후 페이지에서 실패하면 이미 수집한 페이지를 유지하며, 페이지네이션은 필터링된 개수가 아니라 원본 페이지 길이 기준으로 중단합니다.
  • SSRF: 부분 문자열 벤더 검사를 파싱된 정확 호스트 핀으로 교체. lever(clever.com은 lever.co를 포함), greenhouse(호스트 5개 + 레거시 boards[.eu].greenhouse.io 경로 슬러그 호스트), ashby, smartrecruiters, workable, gem REST, ibm, arbeitsagentur, hecklerkoch(www만), workingnomads(http://169.254.169.254가 DNS 가드를 넘어 도달 가능했음), remoteok, remotive, rss, successfactors. 모든 곳에서 redirect:'error'; 공고 URL은 핀으로 고정된 호스트의 https:여야 합니다(javascript: / data: / 호스트 외부는 폐기).
  • 잘못 설정된 portals 항목 하나가 더 이상 전체 스캔을 중단시키지 않습니다. resolveAdapter가 어댑터 예외를 잡고, detectApi는 회사별로 래핑되며, 예외를 던지는 어댑터는 null을 반환합니다. comeet 가져오기 오류는 로그나 격리 기록에 닿기 전에 ?token=을 가립니다.
  • 페이지네이션과 최신성. workday는 100건을 넘는 테넌트를 순회합니다(오프셋 페이지, MAX_PAGES). telegram은 가장 오래된 글을 조용히 남기는 대신 가장 최신 글을 유지하고 ?before=로 페이지네이션합니다. tencent는 Count가 없어도 계속 순회합니다. taleo는 프랑스어 머리글 표를 파싱합니다. avature는 원본 페이지 길이 기준으로 중단합니다. UTC 날짜 스탬프(UTC보다 동쪽에서 amazon 하루 오차, torre, workingnomads, trudvsem). HTML 엔티티 디코딩(geekjob, getmatch, hh). mycareersfuture는 12개 필드 전체의 공고 형태를 출력합니다.
  • 원격 감지 강화. arbeitsagentur, vdab, rippling, teamtailor: 계약 비율(“Verpleegkundige (100%)”, bundesweit)과 “distributed”라는 단어(“Distributed Systems Engineer”)는 더 이상 현장 역할에 Remote 태그를 붙이지 않습니다.

추가

  • tests/adapters-pin-coverage.test.mjs가 핀이 도입한 호스트 핀 분기 커버리지를 완성합니다.

참고

  • 테스트 4419 → 4812 단위, 브라우저 118. 커버리지 평균 라인 98.15 % / 분기 89.36 %(게이트 하한 96 / 86).
  • 이번 릴리스에서 제외: 같은 리뷰 라운드의 클라이언트 지적들(Phase 3 — views, libs, CSS/a11y, i18n). sources/habr.mjs는 여전히 전용 테스트 파일이 없습니다(래칫 면제).

[1.241.1] — 2026-10-07

라이브 평가가 모든 로케일에서 끝까지 작동하고, 채용 지도가 여러 지역이 나열된 긴 공고도 표시하며, 배포가 더 이상 실행 중인 스캔을 끊지 않습니다.

수정

  • 평가가 방법론 전체를 봅니다. CV와 프로필을 인라인하자 컨텍스트 예산(144 KB)이 여전히 modes/oferta.md의 끝부분을 잘라 모든 라이브 평가에서 마지막 블록이 빠졌습니다. 이제 예산은 192 KB, 프롬프트 소프트 한도는 256 KB이며 llm-dispatch.mjs에서 한 번만 정의됩니다.
  • 선택한 언어로 작성되는 보고서. 언어 지시문이 프롬프트의 끝뿐 아니라 시작에도 놓이며, 일반 단어(role, team, design…)는 보고서의 언어로 작성됩니다. 이름, 기술 용어, 원문 그대로의 인용만 영어로 남습니다. 대부분 영어로 작성되던 힌디어와 일본어 보고서를 바로잡습니다.
  • 느린 평가가 더 이상 HTTP 502로 끝나지 않습니다. 평가 타임아웃이 300초입니다(기존에는 제공자 기본값인 180초).
  • 힌디어 블록 문자. A–G 문자를 데바나가리로 표기한 보고서(## ए), ## बी) … ## जी))를 인식하며, SCORE:는 현지 숫자(३.८, ٣٫٨, 3.8)와 소수점 쉼표를 허용합니다.
  • 채용 지도: 긴 위치. “Berlin Office · Berlin · Germany · Bosnia · …” 같은 셀(300자 이상)이 HTTP 400으로 거부되어 공고에 마커가 없었습니다. 이제 처음 나오는 실제 장소를 사용하며(·, ;, |, /, 줄바꿈; “Remote …” 구간, “(HQ)”, “Office”는 건너뜁니다), 2000자를 넘는 쿼리만 거부됩니다.
  • 배포와 매시간 스캔. 배포가 스캔 및 자동 평가 타이머를 잠시 멈추고, 실행 중인 작업이 끝나기를 최대 15분 기다린 뒤 재시작하며, 롤백 시에도 항상 타이머를 재개합니다.

추가

  • cvstart.org의 채용 지도를 17개 언어로 제공하며, 영어와 러시아어 README에도 실었습니다.
  • 모든 언어의 지도 스크린샷 — 언어마다 한 장(scripts/capture-map-screenshots.mjs)씩, 17개 README 전체, cvstart.org, 그리고 새 도움말 소절 “지도 사용법”(§33, ×17)에 실었습니다.

참고

  • 테스트 4404 → 4419, 브라우저 118. 원격 QA(모든 라우트, 사이트, 링크, 17개 로케일의 라이브 LLM)가 프로덕션에서 통과했습니다.
  • 이번 릴리스에서 제외: 스트리밍 평가 — 300초 타임아웃은 여전히 엄격한 한도입니다(느린 로컬 모델은 여전히 도달할 수 있음). Hermes 브리지도 스트리밍 없이 호출합니다.

[1.241.0] — 2026-10-07

28개 에이전트 코드 리뷰(검증된 지적 약 190건)에 따른 보안 강화 릴리스: 보안, 프로세스 크래시, 데이터 손실 유형을 모두 닫았으며, @bullitt186이 기여한 채용 지도가 추가되었습니다.

추가

  • 채용 지도(#/map) — 파이프라인, 마지막 스캔, 트래커의 공고를 OpenStreetMap 지도에 표시합니다. Nominatim으로 지오코딩하며, 식별용 User-Agent, 초당 1건 큐, 백오프, 디스크 캐시를 사용합니다. Leaflet은 이 서버에서 직접 제공하며(CDN 없음), CSP는 img-src에 타일 출처만 추가됩니다. @bullitt186의 기여입니다(#381).
  • 요청 가드 — 서버가 제공하지 않는 Host(DNS 리바인딩)와 교차 사이트 쓰기, 부수 효과가 있는 GET(/api/stream/*, /api/run/*, /api/geocode)을 거부합니다. 공개 이름을 전달하는 리버스 프록시는 이를 ALLOWED_HOSTS에 나열해야 하며, 배포 워크플로는 공개 URL로부터 해당 systemd 드롭인을 작성합니다.
  • 커버리지 게이트 — npm run test:coverage:gate(scripts/coverage-report.mjs)는 파일별 라인/분기 커버리지를 출력하고, 상향 조정되는 기준선 아래로 내려가면 실패합니다.

수정

  • 잘못된 요청이 더 이상 서버를 멈추지 않습니다. Express 4는 거부된 비동기 핸들러를 무시했기 때문에 /api/deep, /api/auto-pipeline, /api/career-plan, /api/tracker의 잘못된 타입 필드나 /api/stats의 NUL 바이트가 프로세스를 종료시켰습니다. 이제 JSON 400으로 응답하며, 그 밖의 거부는 500이 됩니다.
  • 중단되거나 실패한 스캔이 더 이상 마지막 결과를 지우지 않습니다. 스캔이 중지되었거나 모든 소스가 실패하면 last-scan.json을 유지하고, 단일 회사 스캔은 교체하는 대신 병합합니다. 잘못 설정된 portals.yml 항목 하나가 더 이상 전체 스캔을 중단시키지 않습니다.
  • 평가가 방법론 전체를 봅니다. 모드 파일이 16 KB에서 잘려 oferta.md(92 KB)의 C–G 블록이 사라졌습니다. 이제 파일별 한도는 모드 128 KB, CV 64 KB이며 잘림이 보고됩니다. 비어 있거나 잘린 답변은 빈 보고서를 쓰는 대신 실패 처리됩니다.
  • SSRF: 리디렉션 홉에서 사설 대상을 다시 검사하고, 모든 DNS 응답을 검사하며, 스캔 데드라인이 본문까지 포함하고, *_BASE_URL 키는 벤더의 호스트로만 전송되며(Hermes/Ollama: 루프백 또는 LAN), pandoc은 --sandbox로 실행됩니다.
  • 이벤트 루프 정지: 이차 복잡도 정규식 두 개(HTML 제거, 마크다운 정제)를 선형 스캐너로 교체했습니다.
  • 데이터 손실: 파이프라인 행을 삭제하면 다른 행의 보상 정보가 유지되었고, URL의 $&가 pipeline.md를 손상시켰으며, 모의 면접·네트워킹·심층 리서치 저장이 이전 파일을 덮어썼고, 면접 기록이 마지막 40턴이 아니라 처음 40턴을 유지했습니다.
  • LLM 계층: 자동 파이프라인과 심층 리서치가 공유 디스패치를 통해 LLM_PROVIDER와 모든 제공자를 따르고, 사용량을 기록하며 잘림을 보고합니다. Gemini 평가/테스트는 더 이상 보고서를 저장하지 않고, OpenAI는 max_completion_tokens를 사용하며, Codex 전용 OPENAI_MODEL은 gpt-5로 전송되고, 채용 공고는 신뢰할 수 없는 데이터로 구분되어 처리됩니다.
  • 보고서, 심층, 인라인 PDF는 --skip-fact-check를 전달하며(CV 팩트 체크가 숫자가 있는 모든 보고서를 막았습니다), 프로필의 페이지 형식이 더 이상 덮어써지지 않습니다.
  • 스캐너: 격리는 URL 기준이며(URL을 고치면 재시도됨), 실행 내 중복 제거는 정규화된 URL 기준이고, 빈 목록 항목이 더 이상 모든 것과 일치하지 않으며, 쓰기는 원자적이고, skipped_* 기록 행은 “확인됨”으로 취급되지 않습니다.
  • 프로세스 제어: SIGKILL 단계적 확대가 한 번도 실행되지 않았고, 배치 실행은 연결이 끊기면 전체 프로세스 그룹을 종료합니다.
  • CI와 릴리스: CI가 이제 변경 로그 패리티, 워크플로, i18n 게이트를 실행하고, 워크플로 권한은 최소 권한이며, 프로덕션 시크릿은 production 환경에서만 사용되고, npm 패키지에 docs/help/가 포함됩니다.
  • 테스트: 어떤 테스트도 더 이상 네트워크나 실제 상위 프로젝트에 접근하지 않으며(명시적 CAREER_OPS_ROOT는 항상 존중됨), 복사된 알고리즘은 프로덕션 코드로 교체되었습니다.

참고

  • 테스트 4056 → 4404, 브라우저 118. 서버 커버리지 기준선: 라인 96.7 %, 분기 86.3 %(scripts/coverage-baseline.json).
  • 명세는 이제 docs/sdd/specs/ 한 폴더에 있으며, 프로그램 계획은 docs/sdd/PLAN.md, 불변 조건→게이트 매트릭스는 docs/sdd/TRACEABILITY.md입니다.
  • 운영자 참고: 리버스 프록시 뒤에서는 ALLOWED_HOSTS=<공개 호스트>를 설정하세요. 공개 호스트의 Ollama/Hermes 기본 URL은 이제 거부됩니다.

[1.240.0] — 2026-10-06

상위 프로젝트 패리티 — career-ops main @ 62905981(VERSION 1.35.0, b39931e 이후 상위 커밋 177개). 새 소스 6개 — 103 → 109(영문 104 + 러시아어 5) — 기존 제공자 8개에 반영한 수정, 그리고 @bullitt186이 기여한 체크리스트 파이프라인 형식.

추가

  • 새 소스 6개 — 103 → 109(영문 104 + 러시아어 5), 영문 어댑터 98 → 104.
    • ADP Workforce Now(cid + ccId가 있는 workforcenow.adp.com) — 실제로 반환된 행 수 기준의 $skip 페이지네이션. jobRequisitions도 meta도 없는 응답은 빈 보드로 읽히지 않고 예외를 던집니다. 선택형 상세 보강(adpWorkforcenow.fetchDetails, 기본 25, 상한 100).
    • Gupy(employability-portal.gupy.io) — 보드 전체 키워드 스윕, 최신순이며 since_days에서 조기 중단. workplaceType을 단수형 pt-BR 문자열로 읽어 하이브리드 공고가 누락되지 않습니다. 비공개 채용 페이지는 제외됩니다.
    • JazzHR(*.applytojob.com) — 일부만 개편되어도 공고가 나오도록 맨 앵커 폴백을 갖춘 카드 파서. 공고 링크는 있는데 파싱된 카드가 0이면 예외를 던지고, 정말로 빈 보드는 []를 반환합니다.
    • Startup Jobs(startup.jobs/feeds/jobs) — RSS, 요청 1회. 형식이 잘못되었거나 HTML이거나 잘린 본문은 []를 반환하지 않고 예외를 던집니다(상위 프로젝트의 병합 후 리뷰 수정, 08fe5d06). 항목 매칭 전에 CDATA와 주석을 마스킹합니다.
    • Taleo(<tenant>.taleo.net, tre.taleo.net은 거부) — 셸 페이지 GET 후 searchjobs POST. 포털 id가 없는 셸은 비공개 보드로 보고 예외를 던집니다. 열은 머리글로 매칭합니다.
    • UKG Pro / UltiPro(recruiting[N].ultipro.{com,ca}) — Top=50 + Skip. totalCount는 중단 조건으로 절대 신뢰하지 않으며, 페이지 상한은 100(최대 1500으로 제한), 선택형 상세 페이지는 문자열을 인식하는 중괄호 탐색으로 파싱합니다.

수정

  • 상위 프로젝트의 체크리스트 형식 파이프라인 — 상위 career-ops는 data/pipeline.md를 - [ ] url | … 행으로 이루어진 ## Pending / ## Processed 섹션으로 쓰는데, UI는 이를 대기 0건으로 읽었고, 상위가 절대 보지 않는 파일 끝에 펜스를 덧붙이는 방식으로 썼습니다. parsePipeline, addPipelineUrl, removePipelineUrl이 이제 그 형태를 읽고 씁니다(처리 완료 행과도 중복 제거, 급여는 라벨이 붙은 note: comp … 세그먼트로). 펜스 형식은 그대로입니다. @bullitt186 기여(#380).
  • 국가를 위치에 병합 — Ashby(기본 address.postalAddress), Breezy(country.name), Recruitee(평면 location)는 이름에 국가가 이미 온전한 단어로 들어 있지 않으면 국가를 덧붙이므로, 영국 기본·미국 보조인 원격 직무가 더 이상 위치 필터에 걸러지지 않습니다.
  • MokaHR — hire-r1.mokahr.com 지역 호스트를 허용합니다(허용목록은 정확히 app.mokahr.com + hire-r1.mokahr.com). API POST와 공고 링크는 보드 자체의 호스트를 쓰며, 응답 본문 안의 success:false는 이제 빈 보드로 읽히지 않고 예외를 던집니다.
  • Avature — article--jobs 카드가 파싱됩니다(제목은 헤더 앵커에서, 위치는 icon-address span에서).
  • SAP SuccessFactors — /go/<Category>/<id>[/<offset>]/ 저장된 검색 URL이 테넌트 루트로 해석됩니다. 이전에는 …/tile-search-results/로 갔는데, 이 주소는 200을 반환하지만 타일이 0개입니다.
  • Deutsche Bahn — db.jobs는 렌더링할 수 없는 공고가 하나라도 있는 결과 페이지를 통째로 비웁니다. 이제 순회는 pubExternalDate_tdt로 정렬하고 페이지당 1000건(최대 5페이지)을 가져오며, 원시 히트 앵커 개수에서 멈추고, 결과 헤더가 없거나 공고 링크가 파싱되지 않으면 짧은 보드를 반환하는 대신 예외를 던집니다.
  • HigherEdJobs — HTTP 200으로 응답한 Incapsula 챌린지가 항목 0개로 파싱되어 빈 보드로 읽혔습니다. 이제 예외를 던집니다.
  • 테스트 하나가 개발자 머신에서 실제 상위 프로젝트를 읽었습니다 — tests/reports-list-cache.test.mjs는 cv.md/portals.yml이 없는 임시 디렉터리를 CAREER_OPS_ROOT로 지정했는데 paths.mjs가 이를 무시하므로, 로컬에서는 상위의 보고서를 세었고(3개가 아니라 6개) 옆에 상위가 없는 CI에서는 통과했습니다.

참고

  • 테스트 3782 → 4056. 새 스위트: sources-adp-workforcenow, sources-gupy, sources-jazzhr, sources-startup-jobs, sources-taleo, sources-ultipro, sources-location-country-fold, sources-deutschebahn-blanked-page, sources-higheredjobs-challenge-page, 그리고 #380의 parsers-pipeline-checklist.
  • 상위 프로젝트: 포크가 상위 main까지 따라잡았고(144 → 0 커밋 뒤처짐) ADR-0002의 분기점 네 가지가 온전함을 확인했습니다. 상위의 키릴 문자 LOCATIONISH_RE 되돌리기는 반영되지 않았습니다.
  • v1.239.0에서 이미 출시되어 반복하지 않음: AppliTrack, NEOGOV, Red Rover, SchoolSpring, OCC Mundial, Greenhouse 임베드 보드, Workday myworkdaysite.com.
  • 이식하지 않음, 이유와 함께: 신뢰 프록시 이그레스(CAREER_OPS_TRUST_PROXY_EGRESS, _http.mjs / _ip-guard.mjs / _dns-cache.mjs) — web-ui는 자체 http-json.mjs 전송 계층으로 스캔합니다; scan-history.tsv 열 레지스트리와 언어 인식 채용 요청 중복 제거 — web-ui는 1–12번 위치를 읽는데 그 위치는 바뀌지 않았고, URL로 중복 제거합니다; SmartRecruiters requisitionId / language — web-ui의 직무 데이터 형태에는 소비자가 없습니다; Gem isoCountry → 국가 이름 — 상위의 249개 항목 alpha-3 표가 필요해 보류; CLI 전용 변경(모드, 업데이터, doctor, PDF/ATS 페이로드, 트래커 스크립트, Go 대시보드, 싱가포르 모드).

[1.239.4] — 2026-09-29

v1.239.3 라이브 회귀 테스트에 따른 패치.

수정

  • 한국어와 번체 중국어 평가에서 점수 요약이 없다고 보고됐습니다. 이 보고서들은 1만~1만 1천 자에 이르고 요약은 맨 끝에 오기 때문에 출력 한도 8192 토큰을 넘어섰습니다. 이제 평가(와 자동 파이프라인)는 16384 토큰까지 허용하며, 그래도 제공자가 답변을 자르면 빠진 블록을 나열하는 대신 첫 경고에서 그 사실을 알립니다.
  • 라이브 점검이 짧은 독일어 답변을 독일어가 아니라고 판정했습니다(독일어 불용어 3개, 영어 0개). 목록형 답변은 불용어가 적을 수 있어, 영어가 전혀 없으면 3개로 충분하도록 했습니다.
  • 테스트 3778 → 3782.

참고

  • 심층 조사와 모드 경로는 8192 토큰 한도를 유지합니다. 라이브 실행에서 그 답변들은 한도에 도달하지 않습니다.

[1.239.3] — 2026-09-29

v1.239.2 라이브 회귀 테스트에 따른 패치.

수정

  • v1.239.2가 일본어와 힌디어를 고친 뒤에도 아랍어 평가는 A–G 검사를 통과하지 못했습니다. 마스킹한 제목 골격(로그에 보고서 본문 없음)으로 원인을 확인했습니다. 아랍어 보고서는 프롬프트가 무엇을 요구하든 블록 문자를 아브자드 순서의 아랍 문자로 씁니다. 이제 검사는 제목 앞부분에 단독으로 놓인 أ ب ج د هـ و ز를 A–G로 인정합니다(키릴 문자 유사 문자를 이미 인정하는 것과 같습니다). 아랍어 단어 안의 같은 문자는 인정하지 않습니다.
  • 라이브 점검은 A–G 검사가 실패하면 이 마스킹된 골격을 출력해, 다음 사례를 로그로 진단할 수 있게 합니다.
  • 테스트 3776 → 3778.

참고

  • v1.239.2 참고에는 검사를 완화하지 않겠다고 적었지만, 아랍어에 대해서는 완화했습니다. 세 번의 라이브 실행에서 프롬프트만으로는 라틴 문자가 유지되지 않았기 때문입니다.

[1.239.2] — 2026-09-29

v1.239.1 라이브 회귀 테스트에 따른 패치.

수정

  • 아랍어 평가는 블록 문자를 번역했고 일본어 평가는 점수 요약을 빠뜨렸습니다. v1.239.1은 프롬프트 마지막 줄에서 언어만 다시 지정했습니다. 이제 그 줄에서 각 제목의 라틴 문자 A–G와 ---SCORE_SUMMARY--- 블록(마커와 키는 영어)을 번역하지 말 것, 그리고 해당 언어 고유의 문자로 쓸 것도 지시합니다.
  • 테스트 3775 → 3776.

참고

  • 보고서 검사는 번역된 문자나 마커를 받아들이도록 완화하지 않았습니다. 형식의 안정성은 프롬프트가 유지합니다.

[1.239.1] — 2026-09-29

v1.239.0 라이브 회귀 테스트에 따른 패치.

수정

  • 일본어와 우크라이나어 평가가 거의 영어로 나왔습니다. 언어 지시가 프롬프트 맨 앞에 있었고, 그 뒤로 영어 프로젝트 파일과 채용 공고가 수십 KB 이어졌습니다. 이제 프롬프트의 마지막 줄에서 언어를 다시 지정합니다.
  • 서버가 이미 다른 스캔을 실행 중일 때 라이브 점검이 스캔 실패로 보고했습니다(배포 직후 재시도된 매시간 스캔). 서버가 두 번째 스캔을 거부하는 것은 올바른 동작이며, 이제 점검은 최대 30분까지 기다렸다가 다시 시도합니다.
  • 테스트 3774 → 3775.

참고

  • 서버의 단일 스캔 제한은 완화하지 않았습니다. 두 번째 스캔은 여전히 SCAN_BUSY로 거부되며, 바뀐 것은 점검뿐입니다.

[1.239.0] — 2026-09-29

career-ops @ b39931e와 동기화: 새 소스 5개와 이식한 수정 3개.

추가

  • 새 소스 5개(98 → 103, 영문 어댑터 93 → 98): 학교·공공 부문 채용을 위한 AppliTrack(applitrack.com/<학군>), NEOGOV(SchoolJobs / GovernmentJobs), Red Rover(jobs.redroverk12.com/org/<id>), SchoolSpring(<학군>.schoolspring.com), 그리고 멕시코 최대 채용 사이트 OCC Mundial(검색어가 있는 명시적 provider: occ). 모두 호스트가 고정되고 HTTPS만 쓰며 리디렉션을 거부합니다.
  • 테스트 3500 → 3774.

수정

  • Greenhouse 임베드 보드(job-boards.greenhouse.io/embed/job_board?for=<보드>)가 “embed”라는 이름의 보드를 가리켜 실패했습니다. 이제 보드를 ?for=에서 가져오며, 실제 Greenhouse 호스트에서만 그렇게 합니다.
  • myworkdaysite.com의 Workday 보드(/recruiting/<tenant>/<site>)가 인식되지 않았습니다. 이제 스캔되며 공고 링크도 같은 호스트를 가리킵니다.
  • 괄호가 들어간 보고서 파일 이름(042-acme-(berlin)-….md)이 트래커에서 첫 )에서 잘렸습니다. 이제 이름 전체가 유지됩니다.

참고

  • CLI 전용인 상위 프로젝트 변경은 이식하지 않았습니다 — PDF·CV 템플릿, scaffolder, 배치 실행기, career-profile 가져오기, ATS 키워드 커버리지, 면접 모드 번역, CLI 호스트 pi. web-ui는 이것들을 실행하지 않습니다.
  • 트래커에서 그런 보고서를 열려면 보고서 경로가 파일 이름의 괄호를 받아들여야 합니다. 이 릴리스에서는 그 경로를 바꾸지 않았습니다.

[1.238.3] — 2026-09-27

스캔 중에도 페이지가 응답하고, 원격 QA 로그가 더 이상 프로덕션 호스트를 노출하지 않습니다.

수정

  • 대시보드와 보고서가 로드되는 데 수 초가 걸렸고, 스캔 중에는 타임아웃됐습니다. /api/reports와 /api/dashboard가 요청마다 모든 보고서를 읽고 파싱해 프로덕션 서버에서 약 3.7초가 걸렸고, 그동안 다른 모든 요청이 막혔습니다. 스캔 중에는 페이지 로드가 30초 타임아웃에 걸렸습니다. 이제 파싱한 헤더를 파일별로 캐시하고 파일이 바뀔 때만 갱신하므로, 목록은 보고서당 파일 확인 한 번으로 끝납니다(보고서 500개: 로컬에서 430 ms → 3 ms).
  • 원격 QA 결과가 프로덕션 호스트 이름 일부를 공개 로그에 출력할 수 있었습니다. GitHub는 비밀 값이 온전히 나타날 때만 가리는데, 180자로 자른 오류 메시지가 호스트 이름 중간에서 끝났습니다. 이제 결과와 보고서 전체를 자르기 전에 가립니다.
  • 모든 AI 평가가 형식 오류로 표시됐습니다. 프롬프트가 보고서 검사에 필요한 ---SCORE_SUMMARY--- 블록을 요청한 적이 없었고(상위 프로젝트의 평가 스크립트는 요청합니다), 번역된 보고서는 “Block”이라는 단어까지 번역해 검사가 섹션을 찾지 못했습니다. 이제 프롬프트가 요약과 모든 제목의 블록 문자를 요청하고, 검사는 문자 앞의 번역된 단어를 허용하며, 요약 블록은 보고서가 화면에 표시되거나 저장되기 전에 제거됩니다.

추가

  • 테스트 3488 → 3500.

참고

  • 스캐너는 여전히 서버 프로세스 안에서 실행됩니다. 이번 릴리스는 또 다른 큰 병목을 없애지만 스캔을 worker로 옮기지는 않습니다.

[1.238.2] — 2026-09-27

프로덕션 서버가 매시 스캔 중에 여전히 보이던 502 수정.

수정

  • 스캔 중 페이지와 리소스가 502를 반환했습니다. Node는 유휴 keep-alive 연결을 5초 후 닫고, Caddy는 유휴 연결을 최대 2분간 재사용합니다. 프로세스 내부 스캔으로 서버가 바쁜 동안 Caddy가 막 요청을 보낸 소켓을 Node가 닫아 Caddy가 502 connection reset by peer를 반환했습니다(스캔 한 번에 62회, 서버 자체는 정상). 이제 서버는 유휴 연결을 125초(프록시보다 길게) 유지하므로 항상 프록시가 먼저 닫습니다.

추가

  • deploy.yml → verify가 프록시가 502를 반환한 이유(오류 종류, 주소는 가림), 마지막 재시작 이후 분당 502 수, 매시 스캔 결과를 보여줍니다.
  • release.yml은 수동 실행 시 없는 태그를 만들 수 있어, 태그를 push할 수 없는 곳에서도 릴리스할 수 있습니다.
  • 테스트 3486 → 3488.

참고

  • 스캔은 여전히 서버 프로세스 안에서 실행되며 몇 초간 서버를 붙잡을 수 있습니다. worker로 옮기는 작업은 이번 패치에 포함되지 않습니다.

[1.238.1] — 2026-09-27

프로덕션 서버 첫 라이브 회귀 테스트 후 안정성 패치: 한 번에 하나의 스캔과 사이트 수정.

수정

  • 스캔 두 개가 동시에 돌면 서버가 죽었습니다. 모든 GET /api/stream/scan이 아무 보호 없이 서버 프로세스 안에서 전체 스캐너를 실행했고, UI에서 시작한 스캔이 매시 타이머와 겹치면서 프로세스가 JavaScript heap out of memory로 종료됐습니다(두 번, 그동안 502 오류). 이제 한 번에 하나만 실행됩니다. 두 번째 요청은 코드 SCAN_BUSY인 SSE error를 받고 아무것도 시작되지 않습니다. 배포 워크플로는 서버 메모리 한도도 올립니다(heap_mb, 기본 448 MB).
  • cvstart.org의 /help와 /changelog가 휴대폰에서 옆으로 스크롤됐습니다(ja/zh /changelog는 데스크톱에서도). 긴 코드와 목차가 이제 줄바꿈됩니다.
  • 사이트맵의 언어 대체 목록에 힌디어가 없었습니다. 사이트의 i18n 검사가 이제 사이트맵을 언어 레지스트리와 비교합니다.
  • 도움말 §19가 키를 “8개” 언어 파일에 추가하라고 안내했습니다 — 실제로는 17개입니다.

추가

  • 원격 회귀 테스트(.github/workflows/remote-qa.yml): 배포된 앱의 모든 경로 × 모든 언어(읽기 전용), cvstart.org의 모든 페이지 × 언어 × 휴대폰/데스크톱, README와 위키의 모든 링크, 그리고 요청 시 실제 스캔과 모든 언어의 라이브 AI 호출.
  • 서버 배포 워크플로(.github/workflows/deploy.yml): recon, deploy(바이트 단위로 정확한 롤백 포함), verify(스모크 테스트와 안정성 보고서).
  • 테스트 3481 → 3486.

참고

  • 이번 릴리스에서 스캐너 자체의 메모리 사용량은 줄이지 않았습니다. 보호 장치가 두 스캔의 동시 실행을 막고 drop-in이 상한을 올립니다. 98개 소스의 실제 스캔을 프로파일링하려면 운영 네트워크가 필요합니다.
  • 매시 타이머 career-ops-scan은 변경하지 않았습니다. 이제 recon이 실행하는 명령을 보여 줍니다.

[1.238.0] — 2026-09-27

상위 동등성 — career-ops main @ 993085ce(VERSION 1.34.0, de2224a9 이후 182개 커밋). 새로운 소스 4개, 미러링된 프로바이더 수정 10건, 스캐너 전반의 SSRF 허점 하나를 막았고, 스캔 결과에 무료 타이틀 적합도 힌트를 추가했습니다.

추가

  • 새로운 소스 4개 — 94 → 98(93 EN + 5 RU), 89 → 93 EN 어댑터.
    • Eploy(provider: eploy) — 브랜드화된 임의의 호스트에서 테넌트의 /live-jobs.xml 사이트맵을 읽습니다(HTTPS 전용; IP 리터럴, localhost, *.local, *.internal, 단일 라벨 호스트는 거부됩니다). 사이트맵이 아닌 응답(로그인 페이지)은 0건으로 통과시키지 않고 예외를 던집니다. 상세 페이지 조회는 옵트인입니다(eploy: { fetchDetails, detailLimit }).
    • HiringRoom(*.hiringroom.com) — 먼저 JSON-LD /portal/jobs를 읽고, 레거시 /jobs 카드를 폴백으로 사용합니다. 페이로드 안의 http:// 공고 URL은 HTTPS로 재구성합니다.
    • PeopleSoft Candidate Gateway — 브랜드화된 임의의 호스트에서 /psc/{site}/EMPLOYEE/HRMS/c/HRS_HRAM_FL.HRS_CG_SEARCH_FL.GBL 경로로 감지합니다. PeopleSoft 자체의 동일 출처 세션 리다이렉트를 직접 따라가며(최대 10홉, 각 홉을 테넌트 오리진에 다시 고정하고 사설 주소와 대조), “더 보기” 폼을 재현하고, 완료로 보고하는 대신 부분 순회임을 표시합니다(peoplesoftIncomplete).
    • PrevueAPS(*.prevueaps.ca) — 공고 페이지에서 사이트 ID를 알아낸 뒤 JSON API를 읽습니다.
  • #/scan 행에 타이틀 적합도 힌트가 추가되었습니다. 각 결과는 공고 제목을 config/profile.yml의 타깃 역할(target_roles.primary와 아키타입 이름)과 비교한 대략적인 strong / related / weak 적합도 칩을 가집니다. 이는 무료 키워드 추정치로, 결과를 걸러내거나 재정렬하거나 개수를 바꾸는 일은 전혀 없으며 툴팁도 이를 명시합니다. 결과가 서빙될 때 계산되므로 프로필을 편집하면 다음 새로고침에 반영됩니다. 17개 로케일로 번역됨. 상위 저장소 #3261의 미러.

수정

  • 보안 — DNS 리바인딩 가드가 실제 스캔에서는 한 번도 실행되지 않았습니다. http-json.mjs는 순수한 전역 fetch가 전달되었을 때만 해석된 주소를 확인했지만, 두 스캐너 모두 makeTimeoutFetch()를 주입하므로 모든 스캔에서 이 검사를 건너뛰고 있었습니다. 10.x나 127.0.0.1로 해석되는 호스트명을 가리키는 소스도 그대로 가져와졌습니다. 이제 가드는 makeTimeoutFetch 자체 내부에서 실행되며, 정체된 리졸버가 스캔을 멈춰버리지 않도록 스캔 타임아웃과 경합합니다. 이번 릴리스 리뷰 중 발견.
  • 보안 — IPv4 주소를 내장한 IPv6 주소가 사설 주소로 취급되지 않았습니다. http://[::ffff:127.0.0.1]/(URL 파서가 [::ffff:7f00:1]로 다시 씀)는 isValidJobUrl을 통과했습니다. ::ffff:a.b.c.d / ::a.b.c.d의 점 표기와 16진 표기 모두 이제 내장된 주소로 분류됩니다. 상위 저장소의 _ip-guard.mjs.
  • Rippling이 v2 보드 API로 이동(ats.rippling.com/api/v2/board/<slug>/jobs). 페이지네이션(기본 10페이지, 최대 50), 공고 링크에 대한 호스트 고정, slug 검증 포함. 붙여넣은 API URL에서 이제 api가 아니라 실제 slug가 나옵니다.
  • Recruitee — 다중 위치 공고는 모든 장소를 나열하고(A · B), (Sample) 데모 공고와 제목 없는 행은 제거되며, 두 URL 중 하나라도 유효하면 공고가 유지됩니다.
  • Pinpoint — 시드로 심어진 데모 공고(중복된 데모 영상)를 제거합니다.
  • Telegram 채널 — |가 여러 개 있는 첫 줄을 더 이상 제목 | 회사명으로 읽지 않으며, 더 많은 직무 단어를 인식합니다. 포크의 키릴 문자 대응 LOCATIONISH_RE는 그대로입니다(ADR-0002).
  • Workday — 첫 페이지의 422/401/403은 한 번만 시도하며, Workday의 점검 페이지나 장애 리다이렉트는 보드를 죽은 것으로 판정합니다(strict 모드에서는 격리됨). CXS 및 상세 요청은 이제 리다이렉트를 거부합니다.
  • BambooHR — 리다이렉트된 /careers/list는 공개 임베드 피드로 재판정합니다. 비어 있으면 공고가 없는 살아 있는 보드, 그 외에는 죽은 보드입니다.
  • Heckler & Koch / Rheinmetall — 그냥 heckler-koch.com / rheinmetall.com은 www.로 재작성되어 리다이렉트 없는 전송 계층으로도 도달할 수 있습니다. Ashby는 리다이렉트를 거부합니다. beesite는 취소 가능한 delay()로 페이지 속도를 조절합니다.
  • 타이틀 필터가 양쪽에서 악센트를 폴딩합니다(EN, RU 스캐너 모두). Développeur가 developpeur 부정어에 걸립니다.
  • 쿨다운 회사명 매칭이 비라틴 문자 이름과 법인 형태를 이해합니다(CJK/한국어 마커, 터키어 점 있는 İ). CJK 이름은 예전에는 빈 키로 뭉개져 절대 매칭되지 않았습니다.
  • **location_filter.strict: true**는 허용 목록이나 차단 목록이 설정되어 있을 때 위치가 비어 있으면 폐쇄 실패(fail closed) 처리합니다.
  • Liveness — Greenhouse 임베드(gh_jid), Arbeitsagentur, We Work Remotely에 대한 새로운 공개 API 검사. SmartRecruiters는 이제 공고의 active 플래그로 판정합니다.
  • PeopleSoft — 상대 경로의 “더 보기” 폼 액션은 오리진 루트가 아니라 검색 페이지를 기준으로 해석됩니다.

참고

  • 테스트 3210 → 3481. 새 스위트: sources-eploy, sources-hiringroom, sources-peoplesoft, sources-prevueaps, title-fit, fetch-timeout-dns-guard, cooldown-company-match-unicode, liveness-api-more-rungs, ru-scanner-title-accent-fold.
  • 이식하지 않은 것과 그 이유: 위치 필터의 유니코드 단어 경계(web-ui의 필터는 부분 문자열 기반이라 고칠 경계 자체가 없습니다 — 상위 저장소의 위치 필터를 완전히 이식하는 작업은 향후 과제입니다); 동일 제목 공고 중복 제거(web-ui는 URL로만 중복 제거합니다); 애그리게이터 재게시 경고, 블랙리스트 도메인 범위, 미검증 0건 영수증, scan-runs.tsv 마이그레이션(web-ui에는 이런 표면이 전혀 없습니다); Workday 패싯 분할과 잘림 태그(web-ui는 보드당 한 페이지만 가져옵니다); BambooHR enrichDate(날짜 보강 훅이 없습니다); 약 20개 프로바이더에 걸친 상위 저장소의 _http.mjs sleep 리팩터(web-ui는 이미 공유되는 취소 가능한 delay를 사용합니다); updater, doctor, PDF, tracker/merge-tracker, validate-profile, discover-new-companies, web/ Next.js 앱, GitHub 봇 — CLI 전용이거나 릴레이 대상입니다.
  • 상위 저장소와 의도적으로 다르게 유지한 것: Heckler & Koch / Rheinmetall은 계속 HTTPS 전용입니다(http→https 업그레이드 없음); 일반 스캔에서 죽은 Workday 보드는 스캔을 실패시키는 대신 여전히 []를 반환합니다.

[1.237.1] — 2026-09-22

v1.237.0에 대한 외부 QA 점검에서 나온 패치. Jobstreet 수정 사항이 외부에서 처음으로 확인되었습니다: AU, NZ, HK, MY 호스트에서는 예전 형식 /id/job/<id>가 깔끔한 404를 반환하고 새 형식 /job/<id>가 실제 Cloudflare로 보호되는 경로에 도달합니다. id.jobstreet.com에서는 그 반대가 성립합니다. 잃어버린 링크는 실재했습니다. 결함 두 건이 발견되었으며, 둘 다 v1.237.0 자체가 추가한 부분에 있었습니다.

수정

책 링크의 레이블은 현지화되었지만 대상은 그렇지 않았습니다. SPA의 17개 로케일과 cvstart.org의 17개 로케일 모두 Agentic Coding Design Patterns 푸터 링크를 영어판으로 가리키고 있었던 반면, 번역된 유일한 레이블 — 러시아어 «Паттерны агентного кодинга» — 은 러시아어판을 약속하고 있었습니다. 새로운 data-i18n-href 적용기(절대 https:// 값으로 제한된, data-i18n-title과 같은 형태)와 footer.patternsUrl 키가 ru는 러시아어판으로, 그 밖의 모든 로케일은 영어판으로 보냅니다. 회귀 테스트는 이 불변식을 양방향으로 단언합니다: 번역된 제목은 현지화된 URL을 함의합니다. SEEK가 호스트를 이전하고 있으며, 전송 계층은 리다이렉트를 거부합니다. www.seek.com.au → au.seek.com, www.seek.co.nz → nz.seek.com: 상세 페이지는 이미 301을 반환하며, 두 호스트 쌍 모두 오늘 v5 검색 API를 200으로 서비스합니다. http-json.mjs가 redirect:'error'를 설정하기 때문에(가치 있는 SSRF 방어책입니다), API 경로가 리다이렉트를 시작하는 날 예전 호스트의 AU/NZ 항목이 실패하게 됩니다 — 그리고 www. 호스트만 허용목록에 있는 한 아무도 이전할 수 없습니다. au.seek.com과 nz.seek.com이 이제 ALLOWED_JOBSTREET_HOSTS에 있습니다. 예전 호스트는 그대로 남아 있으므로 기존 설정과 이미 만들어진 링크는 계속 작동합니다. 흉내낸 도메인(au.seek.com.evil.com, au-seek.com)은 여전히 거부됩니다. Wiki: Home 문서 지도의 Agentic Practices 행은 열두 개 중 유일하게 [[…|…]] 안에서 |를 이스케이프하지 않아, GitHub가 셀을 잘라냈습니다 — 링크는 죽고 설명은 숨겨졌습니다. 문자 하나 차이였습니다.

참고

소스와 어댑터 개수는 변함없습니다: 94개 소스(89 EN + 5 RU), 89개 어댑터. 테스트는 3201 → 3210(+5 푸터 링크 로케일, +4 SEEK 호스트). 외부에서는 닫을 수 없어, 주장 대신 기록만 해 둔 것들: Oracle Cloud(Akamai가 REST 프로브 두 건을 모두 막았습니다), Personio 고정과 appendWorkType(portals.yml 항목이 필요하고, UI에는 삭제 기능이 없습니다), 그리고 liveness 문자열 사례(제어 가능한 페이지가 없음; 실사용 프로브 40건 중 12건 생존, 28건 판단 불가, 거짓 만료 0건). Help ×17은 이제 AU-Main과 NZ-Main 각각에 두 호스트 형식을 모두 나열합니다. 헤딩 구조는 32 H2 / 122 H3로 변함없습니다.


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