careermate 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/AGENTS.md +5 -3
  2. package/README.md +30 -10
  3. package/THIRD_PARTY_NOTICES.md +2 -1
  4. package/dist/career-os/README.md +4 -3
  5. package/dist/career-os/eop/career-description.md +3 -0
  6. package/dist/career-os/eop/cover-letter.md +8 -4
  7. package/dist/career-os/eop/fit-analysis.md +1 -1
  8. package/dist/career-os/eop/job-analysis.md +1 -1
  9. package/dist/career-os/knowledge/cover-letter.md +4 -3
  10. package/dist/career-os/knowledge/fit-matching.md +5 -3
  11. package/dist/career-os/knowledge/human-writing.md +2 -0
  12. package/dist/career-os/knowledge/verifiers/ai-detection-risk.md +57 -0
  13. package/dist/career-os/knowledge/verifiers/ats-compat.md +1 -1
  14. package/dist/career-os/knowledge/verifiers/human-voice.md +2 -0
  15. package/dist/career-os/knowledge/verifiers/responsiveness-on-target.md +1 -1
  16. package/dist/career-os/knowledge/verifiers/truthfulness.md +1 -0
  17. package/dist/doctor.mjs +19012 -809
  18. package/dist/mcp.mjs +19027 -824
  19. package/dist/migrate.mjs +83 -6
  20. package/dist/public/i18n/en/common.js +4 -0
  21. package/dist/public/i18n/en/documents.js +0 -10
  22. package/dist/public/i18n/en/home.js +5 -0
  23. package/dist/public/i18n/en/jobs.js +1 -1
  24. package/dist/public/i18n/en/profile.js +0 -5
  25. package/dist/public/i18n/ko/common.js +4 -0
  26. package/dist/public/i18n/ko/documents.js +0 -10
  27. package/dist/public/i18n/ko/home.js +5 -0
  28. package/dist/public/i18n/ko/jobs.js +1 -1
  29. package/dist/public/i18n/ko/profile.js +0 -5
  30. package/dist/public/lib.js +72 -0
  31. package/dist/public/pages/applications.js +10 -6
  32. package/dist/public/pages/documents.js +4 -7
  33. package/dist/public/pages/home.js +26 -6
  34. package/dist/public/pages/profile.js +2 -3
  35. package/dist/public/styles.css +39 -4
  36. package/dist/web.mjs +18548 -649
  37. package/docs/MCP_TOOLS.md +19 -10
  38. package/docs/START_WORKFLOW.md +1 -1
  39. package/docs/career-os/README.md +4 -3
  40. package/docs/career-os/eop/career-description.md +3 -0
  41. package/docs/career-os/eop/cover-letter.md +8 -4
  42. package/docs/career-os/eop/fit-analysis.md +1 -1
  43. package/docs/career-os/eop/job-analysis.md +1 -1
  44. package/docs/career-os/knowledge/cover-letter.md +4 -3
  45. package/docs/career-os/knowledge/fit-matching.md +5 -3
  46. package/docs/career-os/knowledge/human-writing.md +2 -0
  47. package/docs/career-os/knowledge/verifiers/ai-detection-risk.md +57 -0
  48. package/docs/career-os/knowledge/verifiers/ats-compat.md +1 -1
  49. package/docs/career-os/knowledge/verifiers/human-voice.md +2 -0
  50. package/docs/career-os/knowledge/verifiers/responsiveness-on-target.md +1 -1
  51. package/docs/career-os/knowledge/verifiers/truthfulness.md +1 -0
  52. package/package.json +3 -2
  53. package/packages/core/src/index.ts +1 -0
  54. package/packages/core/src/jobsearch.ts +186 -0
  55. package/packages/core/src/services.ts +24 -2
  56. package/packages/core/src/summary.ts +196 -0
  57. package/packages/core/src/verify/charcount.ts +87 -0
  58. package/packages/core/src/verify/index.ts +1 -0
  59. package/packages/core/src/verify/lint.ts +5 -0
  60. package/packages/db/src/repositories.ts +42 -8
  61. package/packages/db/src/schema.ts +29 -0
  62. package/packages/exporters/src/docx.ts +165 -0
  63. package/packages/exporters/src/index.ts +142 -9
  64. package/packages/exporters/src/markdown.ts +16 -11
  65. package/packages/knowledge/src/index.ts +17 -5
  66. package/packages/mcp-tools/src/tools.ts +181 -59
  67. package/packages/prompts/src/system.ts +1 -0
  68. package/packages/shared/src/schemas.ts +64 -0
  69. package/scripts/init.ts +5 -0
package/AGENTS.md CHANGED
@@ -12,16 +12,18 @@ CareerMate는 사용자 PC에만 데이터를 두는 **로컬 커리어 작업
12
12
 
13
13
  - **사용자의 언어로 응답하라(출력 언어).** 기본값은 사용자가 쓴 언어다 — 한국어로 말하면 한국어로, 영어 등 다른 언어로 말하면 그 언어로 답한다. 이 지침·도구 응답(`user_message` 등)·플레이북이 한국어로 쓰여 있어도 그대로 복사하지 말고 **사용자 언어로 옮겨** 전달하고, 선택지·예시·안내 문구도 같은 언어로 맞춘다. 단 **사실·수치·고유명사·저장된 원문은 언어와 무관하게 보존**한다. (대화 언어와 *제출용 산출물의 언어·시장 관행*은 분리한다 — 자소서·이력서 본문의 언어와 관행은 **대상 공고·시장**을 따르며, 한국 공고면 한국 관행(문항형·NCS·블라인드), 비한국 공고면 그 시장 관행(ATS·단일 레터)을 적용한다. 대화 언어와 다를 수 있다.)
14
14
  - **기존 데이터를 항상 먼저 활용하라(조회는 최소로).** 연결 직후에는 `get_onboarding_status` **하나만** 부른다 — 무엇이 비었는지·완성도·다음 단계를 한 번에 돌려준다. 완전 신규(프로필 없음)면 더 조회하지 말고 곧장 사용자에게 이력서·정보를 청해 저장 단계로 간다. 이미 채워진 게 있을 때만 `get_application_context`를 **한 번** 더 불러 본문(프로필·대표 이력서·경력·프로젝트·스킬·자소서·최근 지원)을 가져온다 — `list_jobs`·`get_profile`·`get_resumes`·`get_cover_letters`·`list_recent_activity`는 거기에 이미 포함되니 온보딩에서 따로 부르지 마라(불필요한 호출은 사용자 승인 프롬프트만 늘린다). 이미 채워진 항목은 다시 묻지 마라.
15
- - **사용자가 파일을 주면 `read_document`로 읽어라.** 이력서·경력기술서·자소서·채용공고가 PDF·Word(`.docx`)·한컴(`.hwp`/`.hwpx`)·텍스트(`.txt`/`.md`) 파일로 컴퓨터에 있고 사용자가 경로로 가리키면, `read_document({ path })`로 본문 텍스트를 추출한 뒤 그 내용으로 작업하고 결과는 아래 저장 도구로 보관한다(파일 내용을 새 파일로 다시 쓰지 마라). 경로는 가능하면 절대 경로로 준다. 이미지·스캔 PDF는 텍스트 레이어가 없어 추출되지 않을 수 있는데, 그때는 이미지를 직접 볼 수 있는 클라이언트로 읽거나 사용자에게 내용을 텍스트로 붙여넣어 달라고 안내한다.
15
+ - **사용자가 파일을 주면 `read_document`로 읽어라.** 이력서·경력기술서·자소서·채용공고가 PDF·Word(`.docx`)·한컴(`.hwp`/`.hwpx`)·텍스트(`.txt`/`.md`) 파일로 컴퓨터에 있고 사용자가 경로로 가리키면, `read_document({ path })`로 본문 텍스트를 추출한 뒤 그 내용으로 작업하고 결과는 아래 저장 도구로 보관한다(파일 내용을 새 파일로 다시 쓰지 마라). 경로는 가능하면 절대 경로로 준다. 이미지·스캔 PDF는 텍스트 레이어가 없어 추출되지 않을 수 있는데, 그때는 이미지를 직접 볼 수 있는 클라이언트로 읽거나 사용자에게 내용을 텍스트로 붙여넣어 달라고 안내한다. **여러 문서를 한꺼번에 넘기려 하거나 파일 첨부가 안 되는 클라이언트(CLI 등)면**, `open_inbox`로 인입 폴더(`~/.careermate/inbox`)를 안내한 뒤 사용자가 다 넣었다고 하면 `read_inbox`로 한 번에 본문을 추출한다(낱개 경로를 직접 알려주는 경우엔 `read_document`). `read_inbox`도 `read_document`와 동일하게 PDF·Word·HWP를 자동 추출하고, 텍스트로 추출되지 않는 파일(텍스트 레이어 없는 이미지·스캔본 등)만 직접 읽기로 넘긴다. **공고를 파일이 아니라 URL(링크)로 주면 CareerMate는 그 페이지를 가져오지 않는다 — 네(AI)의 브라우징·웹 도구로 본문을 직접 읽어 분석하고 `save_job_posting`에 텍스트로 저장하라(데이터 사고·수집은 두뇌인 당신 몫이다). 웹 도구가 없는 환경이면 사용자에게 공고 본문을 붙여넣어 달라고 요청한다.**
16
16
  - **공고 분석·자소서 작성 전에는 반드시 `get_application_context`를 먼저 호출하라.** 한 번의 호출로 프로필·대표 이력서·경력·스킬·기존 자소서·대상 공고·선호 문체·강조 포인트를 모두 돌려준다. 맥락 없이 작성하지 마라.
17
- - **결과는 다시 CareerMate에 저장하라.** 분석 → `save_fit_analysis`, 자소서 → `save_cover_letter_version`, 경력기술서 → `add_resume`(`kind=career_description`), 공고 → `save_job_posting`, 면접 자료 → `save_interview_prep`. 커리어 데이터는 흩어진 파일이 아니라 CareerMate 안에 둔다. 임의의 로컬 파일 생성은 최소화하라(사용자가 파일을 원하면 `export_cover_letter`로 `~/.careermate/exports`에 내보낸다).
17
+ - **결과는 다시 CareerMate에 저장하라.** 분석 → `save_fit_analysis`, 자소서 → `save_cover_letter_version`, 경력기술서 → `add_resume`(`kind=career_description`), 공고 → `save_job_posting`, 면접 자료 → `save_interview_prep`. 커리어 데이터는 흩어진 파일이 아니라 CareerMate 안에 둔다. 임의의 로컬 파일 생성은 최소화하라(사용자가 파일을 원하면 자소서는 `export_cover_letter`, 이력서·경력기술서는 `export_resume`, 프로필은 `export_profile`로 `~/.careermate/exports`에 내보낸다).
18
+ - **여러 문서를 한 번에 요청받아도 각 문서는 각자의 저장 도구로 따로 저장하라.** "경력기술서랑 자기소개서 둘 다 써줘"처럼 한 턴에 여러 문서를 만들었더라도, 한 저장 호출의 본문(content)에 다른 문서를 이어붙이지 마라 — 경력기술서는 `add_resume`(`kind=career_description`), 자기소개서는 `save_cover_letter_version`으로 **각각 따로** 저장한다(작성은 한 답변에 둘 다 보여줘도 무방하나, 저장은 문서별 도구로 분리). 한 문서 본문에 다른 문서가 섞이면 대시보드에 통째로 붙어 등록된다.
18
19
  - **도구 응답은 사람 말로 바꿔라.** 응답에 `user_message`가 있으면 그 내용을 우선 활용하되 **사용자의 언어로 옮겨** 전달하고(한국어 원문을 그대로 복사하지 않는다), `suggested_next_action`은 선택지로 제안한다. `id`, `job_id`, `cover_letter_id`, `workflow_id`, JSON 원문, 도구 이름은 내부 작업용으로만 쓰고 사용자에게 그대로 복사하지 않는다.
19
- - **공고 분석 뒤에는 자기소개서를 곧장 쓰지 말고 선택지를 보여줘라.** 적합도 분석을 저장하고 쉬운 말로 설명한 뒤 "이 공고에 맞춘 자기소개서를 써드릴까요?"라고 묻고, `1. 네, 이 공고에 맞춘 자기소개서를 써줘` / `2. 아니요, 분석만 저장해줘`처럼 고르게 한다. 사용자가 1번을 고른 경우에만 자소서 작성·저장 흐름으로 이어간다.
20
+ - **공고 분석 뒤에는 자기소개서를 곧장 쓰지 말고 선택지를 보여줘라.** 적합도 분석을 저장하고 쉬운 말로 설명한 뒤 "이 공고에 맞춘 자기소개서를 써드릴까요?"라고 묻고, `1. 네, 이 공고에 맞춘 자기소개서를 써줘` / `2. 아니요, 분석만 저장해줘`처럼 고르게 한다. 사용자가 1번을 고른 경우에만 자소서 작성·저장 흐름으로 이어간다. **1번(쓰기)을 고르면 작성 전에, 회사가 지정한 문항·양식·글자수 제한이 있으면 먼저 달라고 요청하라** — 한국 자소서는 문항형(회사별 항목·글자수)이 많아 문항·양식이 결과 질을 좌우한다. 공고·맥락에 없으면 사용자에게 문항 텍스트·제출 양식·글자수(상·하한, 공백포함 여부)를 묻고, 끝내 없으면 일반 양식으로 진행한다고 알린다. 받은 문항·양식·글자수는 작성에 반영하고 가능하면 공고에 함께 저장한다.
20
21
  - **표준 워크플로우를 따르라(핵심 6 + 선택 1)**: onboarding, analyze_job, write_cover_letter, write_career_description, manage_application_status, prepare_interview — 그리고 사용자가 LinkedIn·포트폴리오 같은 자기표현 자산을 요청하면 `build_personal_brand`. 순서가 헷갈리면 `get_workflow_guide`를 호출한다.
21
22
  - **사용자 대면 결과는 전문가 절차로 만들고, 저장 전 자가검증하라.** 공고 분석·자소서·경력기술서·면접 자료 등을 만들기 전에는 `get_workflow_guide`로 그 작업의 실행 절차(EOP)와 적용할 전문가 플레이북·검증기 순서를 먼저 받고, `get_playbook`(도메인 깊은 지식)으로 작성한 뒤 저장 직전 `get_verifier`(검증 루브릭)로 **당신이** 자가검증한다(사람이 쓴 듯한 글은 작성 직전 `get_writing_style_guide`도 함께 적용). CareerMate는 셀 수 있는 항목만 돕고 의미 판단은 당신 몫이다. 사실·수치·고유명사는 그대로 보존한다.
22
23
  - **8단계 지원 상태를 존중하라**: `draft`(작성 중) → `planned`(지원 예정) → `applied`(지원 완료) → `document_passed`(서류 합격) → `interview`(면접 진행) → `final_passed`(최종 합격) / `rejected`(불합격) / `on_hold`(보류). 면접 준비는 사용자가 요청하면 공고 기준으로 저장할 수 있고, `document_passed` 이상에서는 다음 행동으로 우선 제안한다. 상태 변경은 `update_application_status`.
23
24
  - **업데이트 요청은 구분해서 처리하라.** 사용자가 "최신이야?", "업데이트 있어?"처럼 확인만 요청하면 `check_for_update`로 확인한다. "업데이트해줘", "CareerMate 업데이트해줘", "최신으로 올려줘"처럼 적용을 명시하면 `update_careermate`를 바로 호출한다(이 도구가 최신 버전 확인도 함께 한다). 성공 후에는 AI 앱 또는 MCP 연결 재시작이 필요하다고 안내한다.
24
25
  - **결과를 낼 때마다 대시보드로 안내하라.** 공고 저장·적합도 분석·자소서 버전·상태 변경·면접 준비 등 무언가를 저장·완료할 때마다 대시보드(`http://127.0.0.1:4319`) 주소를 알려준다. 브라우저를 직접 여는 건 **첫 온보딩 때 한 번만**(`open_dashboard`) — 이후에는 자동으로 열지 말고 링크만 보여주고, 사용자가 "열어줘"라고 하면 그때 `open_application`(단건)·`open_dashboard`(전체)로 연다.
26
+ - **지원·문의·버그 신고는 정해진 경로로 안내하라(연락처를 지어내지 마라).** 사용자가 문제 신고·기능 요청·일반 문의를 하면: **버그·기능 요청**은 GitHub Issues(`https://github.com/osntak/careermate/issues`), **일반 문의**는 공개 이메일(`osntak@gmail.com`)로 안내한다 — 같은 링크가 **대시보드 설정 화면의 '도움말·문제 신고' 카드**(영어 UI는 'Help & report a problem')와 **사이트 푸터(careermate.life)** 에도 모여 있으니 그쪽을 알려줘도 된다. **보안 취약점은 공개 이슈로 올리지 말고** 비공개 절차(`SECURITY.md`의 GitHub Security Advisories)로 안내한다. 어느 경로든 신고·문의에 **이름·이메일·연락처·자소서 본문 같은 개인정보를 붙여넣지 말라고 먼저 경고**한다(데이터는 로컬에만 있으니 신고에 개인정보가 필요 없다).
25
27
  - **절대 사용자 데이터를 외부로 업로드하지 마라.** 모든 데이터는 `~/.careermate`(Windows: `%USERPROFILE%\.careermate`)에만 있고, 대시보드는 `127.0.0.1`에만 바인딩된다. CareerMate는 (선택적 버전 확인 외) 네트워크로 사용자 데이터를 보내지 않는다.
26
28
  - 기술 용어(MCP, `job_id` 등)는 사용자에게 노출하지 말고, 매 단계 무엇을 하는지 **사용자의 언어로** 쉽게 설명하라. 확실하지 않으면 지어내지 말고 사용자에게 확인하라.
27
29
 
package/README.md CHANGED
@@ -33,10 +33,20 @@
33
33
  - **AI와 대화로 모든 작업** — MCP 도구로 온보딩·프로필·이력서·자소서·공고·핏 분석·지원 상태·면접 준비·전문가 플레이북·AI 티 안 나는 글쓰기까지 처리.
34
34
  - **지원 상태 8단계 관리** — `draft`(작성 중) · `planned`(지원 예정) · `applied`(지원 완료) · `document_passed`(서류 합격) · `interview`(면접 진행) · `final_passed`(최종 합격) · `rejected`(불합격) · `on_hold`(보류). `document_passed` 이상에서는 면접 준비를 다음 행동으로 제안합니다.
35
35
  - **자기소개서 버전 관리** — 공고별로 자소서 버전을 쌓고 타임라인으로 비교, 파일로 내보내기.
36
- - **채용공고 파싱** — 붙여넣은 공고 텍스트를 구조화해 저장.
36
+ - **공고 검색·가져오기** — 키워드(직무·기술)로 원티드·점핏 같은 공개 채용 사이트에서 공고를 바로 가져와, 마음에 드는 것만 저장. 키 발급·설치 없이 동작하며, 공개 공고를 *가져오기만* 합니다(봇 차단 우회·자동 대량수집 없음, 보내는 건 검색어뿐).
37
+ - **채용공고 파싱** — 붙여넣거나 가져온 공고 텍스트를 구조화해 저장.
37
38
  - **로컬 대시보드** — 프레임워크·CDN 없는 바닐라 JS로 만든 7페이지 웹 화면(다크모드 지원).
38
39
  - **데이터 내보내기/삭제** — Settings 페이지에서 직접.
39
40
 
41
+ > **예: 공고 검색** — "백엔드 공고 찾아줘"라고 하면 AI가 공개 사이트에서 공고를 모아 이렇게 보여주고, 고른 것만 저장합니다:
42
+ >
43
+ > > "백엔드" 공고 6건을 찾았어요 (원티드·점핏):
44
+ > > 1. **미소(miso)** — 백엔드 개발자 (Node.js) · 서울 · 경력 5~11년
45
+ > > 2. **콕스웨이브** — [AX Workflow Builder] 백엔드 엔지니어 · 서울 · 경력 3~7년
46
+ > > 3. **다우기술** — HTS 채널 개발 · 서울 마포구 · `JavaScript` `Mfc` · ~7/7 마감
47
+ > >
48
+ > > 어떤 공고를 저장해서 적합도 분석·자소서로 이어갈까요? (예: "1번, 3번 저장")
49
+
40
50
  ---
41
51
 
42
52
  ## 구성
@@ -150,15 +160,15 @@ npx -y careermate init
150
160
  | 이력서 | `read_document` · `add_resume` · `get_resumes` · `export_resume` · `delete_resume` · `open_inbox` · `read_inbox` |
151
161
  | 경력·프로젝트·스킬 | `add_experience` · `get_experiences` · `delete_experience` · `add_project` · `get_projects` · `delete_project` · `add_skill` · `get_skills` · `delete_skill` |
152
162
  | 자기소개서 | `get_cover_letters` · `save_cover_letter_version` · `delete_cover_letter` · `export_cover_letter` |
153
- | 채용공고 | `save_job_posting` · `get_job_posting` · `list_jobs` · `delete_job_posting` |
163
+ | 채용공고 | `search_jobs` · `save_job_posting` · `get_job_posting` · `list_jobs` · `prescreen_job` · `delete_job_posting` |
154
164
  | 핵심 컨텍스트 | **`get_application_context`** (지원에 필요한 맥락을 한 번에 모아줌) |
155
165
  | 핏 분석 | `save_fit_analysis` |
156
166
  | 지원 상태 | `update_application_status` |
157
167
  | 면접 준비 | `save_interview_prep` |
158
168
  | 글쓰기 | `get_writing_style_guide` (AI 티 안 나는 한국어 글쓰기 규칙) |
159
- | 전문가 지식 (Career-OS) | `get_playbook` (도메인 플레이북 16종) · `get_verifier` (저장 전 검증 루브릭 6종) |
169
+ | 전문가 지식 (Career-OS) | `get_playbook` (도메인 플레이북 16종) · `get_verifier` (저장 전 검증 루브릭 7종) |
160
170
  | 저장 전 점검 | `validate_cover_letter` (자소서 저장 전 미리보기) · `set_verify_mode` (점검 엄격도 기본/엄격) |
161
- | 대시보드/활동 | `open_dashboard` · `open_application` · `list_recent_activity` · `get_workflow_guide` |
171
+ | 대시보드/활동 | `open_dashboard` · `open_application` · `list_recent_activity` · `get_followups` · `get_pipeline_stats` · `get_workflow_guide` |
162
172
  | 업데이트 | `check_for_update` · `update_careermate` |
163
173
 
164
174
  이 도구들 위에 7종의 워크플로우가 정의되어 있어 AI가 단계별로 자연스럽게 안내합니다: 핵심 6종(`onboarding`, `analyze_job`, `write_cover_letter`, `write_career_description`, `manage_application_status`, `prepare_interview`)과 LinkedIn·포트폴리오용 `build_personal_brand`.
@@ -235,7 +245,7 @@ CareerMate/
235
245
  - **정적 파일 보호** — 경로 traversal(상위 폴더 탈출) 차단.
236
246
  - **본문 크기 제한** — 요청 본문 8MB 제한.
237
247
  - **민감 정보 비노출** — 이력서·자기소개서 본문은 로그나 에러 응답에 노출되지 않습니다.
238
- - **외부 전송 없음** — MCP 서버는 네트워크 호출을 하지 않으며, 모든 데이터는 당신의 컴퓨터에만 남습니다. 내보내기·삭제는 대시보드 **Settings**에서 직접 할 수 있습니다.
248
+ - **사용자 데이터 외부 전송 없음** — CareerMate는 당신의 프로필·이력서·자소서 등 **개인 데이터를 외부로 보내지 않습니다.** 모든 데이터는 당신의 컴퓨터에만 남습니다. 외부로 나가는 네트워크 호출은 (1) 선택적 버전 확인, (2) 공고 검색(공개 잡보드)뿐이며, 이때도 **보내는 것은 검색 키워드뿐**(개인 데이터 아님)이고 공개 공고를 *가져오기만* 합니다(봇 차단 우회·자동 대량수집 없음). 내보내기·삭제는 대시보드 **Settings**에서 직접 할 수 있습니다.
239
249
 
240
250
  ---
241
251
 
@@ -305,10 +315,20 @@ You can open the dashboard at any time to see your stored data. For a step-by-st
305
315
  - **Everything through conversation with AI** — MCP tools cover onboarding, profile, resumes, cover letters, job postings, fit analysis, application status, interview prep, expert playbooks, and human-sounding writing.
306
316
  - **8-stage application status** — `draft` · `planned` · `applied` · `document_passed` · `interview` · `final_passed` · `rejected` · `on_hold`. Interview prep is suggested at `document_passed` or later.
307
317
  - **Cover-letter versioning** — Stack versions per posting, compare on a timeline, export to a file.
308
- - **Job-posting parsing** — Turn pasted posting text into structured records.
318
+ - **Job search & import** — Pull postings by keyword (role/skill) straight from public job boards (e.g. Wanted, Jumpit) and save only the ones you like. No API key or setup; it only *fetches* public postings (no bot-protection bypass, no bulk harvesting — only the search keyword is sent).
319
+ - **Job-posting parsing** — Turn pasted or imported posting text into structured records.
309
320
  - **Local dashboard** — A 7-page web UI built with framework-free, CDN-free vanilla JS (dark mode supported).
310
321
  - **Export / delete your data** — Directly from the Settings page.
311
322
 
323
+ > **Example: job search** — Ask "find backend jobs" and the AI gathers postings from public boards, presents them like this, and saves only the ones you pick:
324
+ >
325
+ > > Found 6 "backend" postings (Wanted · Jumpit):
326
+ > > 1. **miso** — Backend Developer (Node.js) · Seoul · 5–11 yrs
327
+ > > 2. **Coxwave** — [AX Workflow Builder] Backend Engineer · Seoul · 3–7 yrs
328
+ > > 3. **Daou Tech** — HTS Channel Dev · Seoul Mapo-gu · `JavaScript` `Mfc` · due 7/7
329
+ > >
330
+ > > Which should I save to analyze fit / draft a cover letter? (e.g. "save #1 and #3")
331
+
312
332
  ---
313
333
 
314
334
  ## Architecture
@@ -423,15 +443,15 @@ Dark mode is supported.
423
443
  | Resume | `read_document` · `add_resume` · `get_resumes` · `export_resume` · `delete_resume` · `open_inbox` · `read_inbox` |
424
444
  | Experience / projects / skills | `add_experience` · `get_experiences` · `delete_experience` · `add_project` · `get_projects` · `delete_project` · `add_skill` · `get_skills` · `delete_skill` |
425
445
  | Cover letter | `get_cover_letters` · `save_cover_letter_version` · `delete_cover_letter` · `export_cover_letter` |
426
- | Job posting | `save_job_posting` · `get_job_posting` · `list_jobs` · `delete_job_posting` |
446
+ | Job posting | `search_jobs` · `save_job_posting` · `get_job_posting` · `list_jobs` · `prescreen_job` · `delete_job_posting` |
427
447
  | Core context | **`get_application_context`** (gathers all context needed for an application in one call) |
428
448
  | Fit analysis | `save_fit_analysis` |
429
449
  | Application status | `update_application_status` |
430
450
  | Interview prep | `save_interview_prep` |
431
451
  | Writing | `get_writing_style_guide` (rules for human-sounding Korean writing) |
432
- | Expert knowledge (Career-OS) | `get_playbook` (16 domain playbooks) · `get_verifier` (6 pre-save rubrics) |
452
+ | Expert knowledge (Career-OS) | `get_playbook` (16 domain playbooks) · `get_verifier` (7 pre-save rubrics) |
433
453
  | Pre-save check | `validate_cover_letter` (dry-run preview before saving) · `set_verify_mode` (check strictness: default/strict) |
434
- | Dashboard / activity | `open_dashboard` · `open_application` · `list_recent_activity` · `get_workflow_guide` |
454
+ | Dashboard / activity | `open_dashboard` · `open_application` · `list_recent_activity` · `get_followups` · `get_pipeline_stats` · `get_workflow_guide` |
435
455
  | Update | `check_for_update` · `update_careermate` |
436
456
 
437
457
  On top of these tools, seven workflows are defined so the AI can guide you naturally, step by step: the six core flows (`onboarding`, `analyze_job`, `write_cover_letter`, `write_career_description`, `manage_application_status`, `prepare_interview`) plus `build_personal_brand` for LinkedIn/portfolio assets.
@@ -509,7 +529,7 @@ CareerMate/
509
529
  - **Static-file protection** — Path traversal (escaping the parent folder) is blocked.
510
530
  - **Body size limit** — Request bodies are capped at 8MB.
511
531
  - **No sensitive-data leakage** — Resume and cover-letter content is never exposed in logs or error responses.
512
- - **No external transmission** — The MCP server makes no network calls, and all data stays only on your computer. Export and delete are available directly in the dashboard **Settings**.
532
+ - **No personal-data transmission** — CareerMate never sends your personal data (profile, resumes, cover letters) anywhere; all data stays only on your computer. The only outbound network calls are (1) the optional version check and (2) job search (public job boards) — and even then only the **search keyword** is sent (no personal data), to *fetch* public postings (no bot-protection bypass, no automated bulk harvesting). Export and delete are available directly in the dashboard **Settings**.
513
533
 
514
534
  ---
515
535
 
@@ -42,7 +42,7 @@ SOFTWARE.
42
42
 
43
43
  ## 번들에 포함되는 npm 의존성 (런타임)
44
44
 
45
- 배포 시 `dist/` 번들(esbuild)에 코드가 인라인되는 런타임 의존성입니다. MCP 서버·프로토콜(`@modelcontextprotocol/sdk`)과 입력 스키마 검증(`zod`), 그리고 `read_document`의 문서 텍스트 추출(순수 JS)에 사용합니다. 각 라이선스 고지를 보존하며, 각 라이선스 전문은 설치된 `node_modules/<패키지>/LICENSE` 에 포함됩니다.
45
+ 배포 시 `dist/` 번들(esbuild)에 코드가 인라인되는 런타임 의존성입니다. MCP 서버·프로토콜(`@modelcontextprotocol/sdk`)과 입력 스키마 검증(`zod`), `read_document`의 문서 텍스트 추출, 그리고 이력서·자기소개서의 `.docx` 내보내기(`docx`)에 사용합니다(모두 순수 JS). 각 라이선스 고지를 보존하며, 각 라이선스 전문은 설치된 `node_modules/<패키지>/LICENSE` 에 포함됩니다.
46
46
 
47
47
  | 패키지 | 용도 | 라이선스 | 저작권 |
48
48
  | --- | --- | --- | --- |
@@ -52,5 +52,6 @@ SOFTWARE.
52
52
  | [`hwp.js`](https://github.com/hahnlee/hwp.js) | `.hwp`(HWP 5.x) → 텍스트 | Apache-2.0 | Copyright Han Lee and other contributors |
53
53
  | [`fflate`](https://github.com/101arrowz/fflate) | `.hwpx` 압축 해제 | MIT | Copyright (c) 2023 Arjun Barrett |
54
54
  | [`pdfjs-dist`](https://github.com/mozilla/pdf.js) | `.pdf` → 텍스트 | Apache-2.0 | Copyright Mozilla Foundation and contributors |
55
+ | [`docx`](https://github.com/dolanmiu/docx) | 이력서·자기소개서 → `.docx` 내보내기 | MIT | Copyright (c) 2016 Dolan Miu |
55
56
 
56
57
  > Apache-2.0(`hwp.js`, `pdfjs-dist`)은 라이선스 사본과 NOTICE 고지 보존을 요구합니다. 위 표와 `node_modules`의 동봉 라이선스로 이를 충족합니다.
@@ -32,6 +32,7 @@ EOP·이 문서를 맹신하지 말 것. **저장된 사용자 데이터나 공
32
32
  | "이 공고 적합도/나랑 맞아?/지원할 만해?" | [fit-analysis](eop/fit-analysis.md) | job-analysis, profile-extraction |
33
33
  | "이 공고 분석/뜯어줘", "무슨 회사·직무·레벨이야" | [job-analysis](eop/job-analysis.md) | — |
34
34
  | "이력서/경력 정리·입력", "기본정보 채워" | [profile-extraction](eop/profile-extraction.md) | — |
35
+ | "경력기술서/경력서술서/career description 써줘·정리해줘" | [career-description](eop/career-description.md) | profile-extraction, ats |
35
36
  | "자소서/자기소개서/지원동기/커버레터 써줘·고쳐줘" | [cover-letter](eop/cover-letter.md) | company-research, human-writing, fit-analysis |
36
37
  | "면접 준비/예상질문/모의면접" | [interview-prep](eop/interview-prep.md) | company-research, fit-analysis |
37
38
  | résumé·ATS·linkedin·portfolio·salary·offer·rejection·onboarding | `knowledge/` 플레이북 | — |
@@ -72,12 +73,12 @@ EOP·이 문서를 맹신하지 말 것. **저장된 사용자 데이터나 공
72
73
  - **충돌(데이터 vs 데이터, 공식자료 vs EOP):** §0 근거 우선순위 적용, 사실 보존, 사용자에게 알림.
73
74
  - **충돌(도메인 vs 도메인):** 여러 `knowledge/` 도메인이 같은 주제를 건드리면 정본(소유) 도메인을 따른다 — 연봉 숫자 전술=salary-negotiation(recruiter-screen은 게이트 맥락의 조건부 규칙만 상속), 오퍼 비교·가중치=offer-evaluation-decision, 30-60-90=onboarding-first-90-days, 탈락 진단=rejection-triage-iteration, 슬롭/키워드/정량 사전=공유 모듈. 검증기 간 충돌은 **사실(truthfulness)을 최상위 타이브레이크**로 두고, ATS 키워드와 human-voice는 둘 다 만족하는 대역(진짜 경험 문장에 JD 용어를 진실하게 삽입)을 먼저 찾는다.
74
75
 
75
- ## 5. EOP 목록
76
- [fit-analysis](eop/fit-analysis.md) · [job-analysis](eop/job-analysis.md) · [profile-extraction](eop/profile-extraction.md) · [cover-letter](eop/cover-letter.md) · [interview-prep](eop/interview-prep.md)
76
+ ## 5. EOP 목록 (6종)
77
+ [fit-analysis](eop/fit-analysis.md) · [job-analysis](eop/job-analysis.md) · [profile-extraction](eop/profile-extraction.md) · [cover-letter](eop/cover-letter.md) · [career-description](eop/career-description.md) · [interview-prep](eop/interview-prep.md)
77
78
 
78
79
  각 EOP 구조 = 전문가 프레임 · 입력 수집 · 분석 절차 · 한국/영문 특수 · 출력 계약 · 자가검증 루브릭 · 근거.
79
80
 
80
81
  ## 6. 디렉터리·기존 문서와의 관계 (무엇을 버리지 않는가)
81
82
  - **`knowledge/` (Phase A — 16 도메인 플레이북 + 6 verifiers)** = **정본 deep 지식**(대학 커리어센터·NCS·ATS 등 출처 충실). **버리지 않는다.** 각 EOP는 이 플레이북을 *실행 절차로 압축*하고 상단 "지식 출처"로 가리킨다 — EOP=얇은 실행층, knowledge=깊은 지식층. 함께 적용한다.
82
83
  - **`validation/`** = 새 리서치 4편(`research/`, knowledge **보강**: 검증 출처+한국 시장+리뷰어 루브릭) + 다중 LLM(cross-vendor) 교차검증 하니스(`runs/`, `PROTOCOL.md`, `MANDATE.md`). 런타임 소비 경로는 아님.
83
- - **`implementation/`** = CareerMate **개발자용** Phase B 내부 설계(`ARCHITECTURE.md`·`CONTRACT.md`·`EXPERTS.md`·`VERIFIERS.md`·`LOOP_ENGINE.md`·`EVALUATION.md`·`CONSENSUS_ENGINE.md`·`TODO.md`·`KNOWLEDGE.md`·`CONSUMPTION.md` + `phase-b2/`). MCP 도구·DB·det 엔진 등 빌드 스펙 — **외부 LLM 소비에는 불필요**(소비 진입점은 이 README + `eop/` + `knowledge/`).
84
+ - **`implementation/`** = CareerMate **개발자용** Phase B 내부 설계(`ARCHITECTURE.md`·`CONTRACT.md`·`EXPERTS.md`·`VERIFIERS.md`·`LOOP_ENGINE.md`·`EVALUATION.md`·`CONSENSUS_ENGINE.md`·`TODO.md`·`KNOWLEDGE.md`·`CONSUMPTION.md` + `phase-b2/`). MCP 도구·DB·det 엔진 등 빌드 스펙 — **외부 LLM 소비에는 불필요**(소비 진입점은 이 README + `eop/`(6 EOP) + `knowledge/`).
@@ -111,6 +111,8 @@
111
111
 
112
112
  저장은 `add_resume`으로 한다. 경력기술서 작성 산출물은 `kind=career_description`, `source=ai`를 사용하고, 제목은 사용 목적이 드러나게 쓴다. 대표 문서 지정은 사용자가 동의했을 때만 한다.
113
113
 
114
+ **자소서·이력서 등을 한 턴에 함께 요청받았더라도, 경력기술서 저장 content엔 경력기술서 본문만 넣는다.** 자기소개서는 별도로 `save_cover_letter_version`에 저장하고, 한 번의 `add_resume` 호출 본문에 자소서·이력서 같은 다른 문서를 이어붙이지 않는다(작성은 한 답변에 둘 다 보여줘도, *저장은 문서별 도구로 분리*한다).
115
+
114
116
  ## 7. 자가검증 루브릭
115
117
 
116
118
  저장 직전 아래 기준으로 스스로 점검하고 수정한다.
@@ -121,6 +123,7 @@
121
123
  - C3 자기소개서 문장을 그대로 옮겨 동기·감정 중심 산문이 됨.
122
124
  - C4 이력서/프로필/프로젝트와 기간·역할·성과가 충돌함.
123
125
  - C5 공동 작업을 개인 단독 성과로 과장함.
126
+ - C6 한 저장 본문에 경력기술서와 다른 문서(자기소개서 등)가 함께 들어 있음 — `add_resume` content엔 경력기술서만, 자소서는 `save_cover_letter_version`으로 분리 저장.
124
127
 
125
128
  **MAJOR:**
126
129
  - M1 직무 나열만 있고 행동·산출물·성과가 없음.
@@ -13,17 +13,21 @@
13
13
 
14
14
  ## 1. 입력 수집
15
15
  `get_application_context` → profile·대표 resume·경력/프로젝트·대상 job·기존 자소서·선호 문체. 사용자가 파일을 주면 `read_document`. 부족하면 사용자 확인.
16
+ **기존 자소서는 참고용이지 템플릿이 아니다(자기복제 주의).** 전문을 그대로 따라 쓰지 마라 — 특히 직전 자소서 1편을 변주만 하는 실패가 잦다. 합격 신호가 있는 과거 자소서(연결된 지원 status가 `document_passed` 이상 — `recent_applications`에서 `cover_letter_id`로 확인)가 있으면 그 *구조·앵글*을 참고하되 본문은 새로 쓴다. 차별화 절차는 §2-3.
16
17
  판정: **로케일**(ko 문항형 vs en 단일 레터), **문항 유형**(지원동기/성장과정/직무역량/입사후포부/약점·갈등), **글자수 상·하한과 count_mode**(공백포함/제외/byte — 실제 지원 필드로 검증; 미지정 시 공백포함 기본).
18
+ **문항·양식·글자수가 컨텍스트/공고에 없으면 작성 전 사용자에게 요청한다**(문항 텍스트·제출 양식·글자수 — 추측·임의 양식 금지). 끝내 없으면 일반 양식으로 진행함을 명시한다.
17
19
 
18
20
  ## 2. 분석·작성 절차
19
21
  1. **회사 리서치**(company-research): 미션·사업·제품·최근 활동·인재상 → 본인과 연결할 고유 포인트 확보.
20
22
  2. **문항 의도 해석:** 지원동기=여기 오게 한 *구체 경험*(표면 관심 X); 성장과정=동기의 *근원+서사 연결*(인생 연대기 X); 직무역량=역할의 *핵심 역량 1~2개 정확 식별+증명*; 입사후포부=*회사 사업방향에 묶인* 단기·중기·장기(전문가 포지셔닝) 로드맵(과대 금지). **연차 수치(1~3년 등)는 일반 로드맵 골격일 때만 — 본인 기여·성과에 '입사 후 1~2년은'처럼 저장·공고에 없는 기간을 단정하지 마라(출처 밖 기간 단정=C4).** <!-- applied: r7-cover-letter / R7 cross-vendor PASS cl-s1=94 PERFECT (opus생성·codex채점) / 2026-06-20 -->
21
23
  3. **본인 증거 매핑:** 저장 경력/프로젝트에서 문항·역량을 증명할 경험 **1~2개를 깊게** 선택(얕게 5~6개 나열 금지).
22
- 4. **초안 작성:** 항목별 **소제목** + **두괄식**(핵심 결론 먼저) → **STAR-lite**(S/T 짧게, A에 무게, R=전후 델타 정량) → **직무/인재상 명시 연결**. 회사 고유 근거 1~3문장("회사명 placeholder로 바꾸면 어색"이어야 함). 글자수 **상한의 ~70%+를 채우되**, 입사후포부는 앞 문단과 **다른 새 기여**로(같은 성과·표현 반복 금지).
24
+ - **기존 자소서 차별화(있을 때 — 자기복제 방지):** 기존 자소서는 *참고*지 *템플릿*이 아니다. **(1) 사실은 일관되게** — 경험·수치·고유명사·사용자 보이스는 공고가 달라도 같아야 하며, 자기복제를 피하려고 억지로 비틀지 마라(사실 왜곡 = C4). **(2) 프레이밍·산문은 새로** — 직무 적합 앵글·why-this-company·도입 훅·문장 표현은 이 공고에 맞춰 새로 짠다. 같은 대표 경험을 또 쓸 거면 *이 공고의 요구역량·인재상에 맞는 다른 각*으로 재프레이밍하고, 가능하면 *다른 경험*으로 다양화한다. **직전 자소서를 회사명·일부 토큰만 바꿔 따라 쓰지 마라(가장 흔한 실패).**
25
+ 4. **앵글 설정(차별화 게이트 — 초안 전 확정):** 바로 쓰지 말고, 이 공고에 맞춘 **2~3개 후보 앵글**을 먼저 세운다. 네 축으로 잡는다 — **why**(왜 이 회사·직무인가: 표면 관심이 아닌 구체적 이유) · **problems**(이 회사/팀의 어떤 문제를 풀고 싶은가 — 회사 리서치·공고 기반) · **approach**(저장 경험이 증명하는 *나만의* 접근/방법) · **tone**(원하는 문체 — `profile.preferred_tone` 우선, 없으면 담백/따뜻/격식 중 확인). **기존 자소서·다른 공고와 다른 각을 강제**해 자기복제를 끊는다(§2-3과 직결). 앵글이 컨텍스트로 자명하면 묻지 말고 1개로 진행하되 무엇을 골랐는지 검토 메모(§4②)에 적고, 모호하면 후보 앵글을 사용자에게 한 번 제시해 고르게 한 뒤 그 앵글로만 초안을 전개한다(과한 질문 금지 — 자명하면 그냥 진행). <!-- career-ops 차용: why/problems/approach/tone 앵글 프롬프트 -->
26
+ 5. **초안 작성:** 항목별 **소제목** + **두괄식**(핵심 결론 먼저) → **STAR-lite**(S/T 짧게, A에 무게, R=전후 델타 정량) → **직무/인재상 명시 연결**. 회사 고유 근거 1~3문장("회사명 placeholder로 바꾸면 어색"이어야 함). 글자수 **상한의 ~70%+를 채우되**, 입사후포부는 앞 문단과 **다른 새 기여**로(같은 성과·표현 반복 금지).
23
27
  - **STAR 앵커 우선(사실 변경 금지·표현 강화 허용):** Action/Result는 저장된 '한 일'(도입·적용·운영·분석한 것)과 저장된 결과에 앵커한다. 저장된 행위·맥락은 풍부하게 서술해도 좋다(평가자가 중시하는 경험 서술형 환영). **금지는 발명뿐** — 저장 근거가 없는 진단 결과·방법/도구·원인 규명·실패율·문서화·후속 성과를 새로 지어내지 마라. 저장에 없는 과정을 꼭 암시해야 하면 "기록/근거로 범위를 좁혔다" 수준의 중립 한 구절까지만. <!-- applied: P4-star-anchor / closed 2026-06-20 — codex 규칙-텍스트 전용 표결 agree(4/4) + claude 3모델 만장일치 + R7 산출물 PASS 간접지지(cl-s1=94 opus생성·codex채점 / cl-s2 codex생성 90 PASS) -->
24
28
  - **프레이밍 경계(작성·평가 공통):** 일반 도메인 원리는 *후보 귀속 없이* 맥락으로 OK. 비즈니스 임팩트·문제 프레이밍은 *저장된 성과/지표가 암시하는 범위 안*에서만. **(아래 예시는 IT 직군 하나의 예일 뿐 — 원리는 전 직군 동일: 영업=매출/전환 기록, 운영·생산=처리량/불량률 기록, 마케팅=유입/전환 기록 등.)** 예: p99 개선 기록 → "느린 구간을 좁혀" OK / 기록 없는 "결제 경험을 해치던" 단정 금지. 사고·이유 귀속은 *저장된 결정·행동이 논리적으로 함의할 때만*(예: "Kafka 보류 결정" 저장 → "복잡도 대비 효과가 적어 보류" OK / "새 기술보다 ~가 낫다고 봤다"식 새 판단 삽입 금지). **금지:** 후보가 측정·관찰·확인했다는 행위, 출처에 없는 중간 지표(A/B를 "클릭"으로 특정), 출처에 없는 파생 정확수치(%·배수) 단정(저장 전후값은 그대로 쓰거나 "절반 이하로" 같은 정성 표현만 허용), 진단 결과·원인·감정·의도를 후보의 사실로 단정. **수치·고유명사는 저장 데이터의 범위·채널·주체 그대로 쓴다('캠페인 누적'을 '인스타그램 누적'으로 좁히듯 채널/주체 재귀속 금지). 학습·기초만 저장된 것을 수행으로 승격하지 마라('SQL 기초 학습'+'주간 리포트 작성'→"SQL로 데이터를 추출해 리포트 작성"식 연결 단정 금지).** <!-- applied: fact-anchor-boundary / closed 2026-06-20 — codex 규칙-텍스트 전용 표결 agree(4/4) + claude 3모델 만장일치 + R7 경계강화 cross-vendor PASS 간접지지 -->
25
- 5. **슬롭 제거:** 빈 형용사("열정·성실·최선을 다하겠습니다")·증거 없는 종결구문("~라고 생각합니다·많은 것을 배웠습니다")·제너릭 도입("어릴 적부터·지원하게 되어")·AI 어휘("귀하·시너지") 제거. human-writing 가이드(`get_writing_style_guide`) 적용.
26
- 6. **규칙 점검:** 글자수 상·하한(byte/char) · 지정 양식 · 블라인드(공공: 직무무관 개인정보·학교·지역·가족·사진 금지).
29
+ 6. **슬롭 제거:** 빈 형용사("열정·성실·최선을 다하겠습니다")·증거 없는 종결구문("~라고 생각합니다·많은 것을 배웠습니다")·제너릭 도입("어릴 적부터·지원하게 되어")·AI 어휘("귀하·시너지") 제거. human-writing 가이드(`get_writing_style_guide`) 적용.
30
+ 7. **규칙 점검:** 글자수 상·하한(byte/char) · 지정 양식 · 블라인드(공공: 직무무관 개인정보·학교·지역·가족·사진 금지).
27
31
 
28
32
  ## 3. 한국/영문 분기
29
33
  - **KR 문항형:** 문항당 별개 글, 두괄식 + 문항-역량 매핑, 소제목, 글자수 엄수. 성장과정만 가벼운 서사 허용하되 핵심은 여전히 front-load.
@@ -42,7 +46,7 @@
42
46
  내부 루브릭·도구명·이 EOP는 노출하지 않는다. 결과 저장은 `save_cover_letter_version`, 안내는 대시보드 링크.
43
47
 
44
48
  ## 5. 자가검증 루브릭 (제출 전 — research §리뷰어 루브릭)
45
- **CRITICAL(하나라도 → 재작성):** C1 회사/직무/지역 오기·교차지원 복붙 흔적 / C2 자격·필수요건 미충족·미언급 / C3 글자수(byte/char cap)·양식·필수항목 위반(**제출용 본문 블록에 결론/근거/리스크 등 메타 텍스트 혼입** 포함) / C4 날조 또는 문서 간 모순 수치(**수치·고유명사는 저장 데이터의 범위·채널·주체 그대로 쓴다 — '캠페인 누적'을 '인스타그램 누적'처럼 더 좁은 채널/주체로 재귀속(범위 변경)하거나, 저장·공고에 없는 정확수치·기간·비율('입사 후 1~2년'·%·배수)을 단정하면 C4 날조**) / C5 블라인드 위반(공공). <!-- applied: r7-cover-letter / §5 C4 채널 재귀속·파생수치 경계 (R7 cross-vendor PASS) / 2026-06-20 -->
49
+ **CRITICAL(하나라도 → 재작성):** C1 회사/직무/지역 오기·교차지원 복붙 흔적·**기존 자소서 템플릿 복제**(다른 공고인데 직무 적합 앵글·도입·산문이 직전 자소서와 거의 같아 회사명만 바뀐 수준 — *단 사실·수치·고유명사·보이스의 일관성은 정상이며 억지 변형 금지*; 문제는 프레이밍·문장의 무차별 carryover다) / C2 자격·필수요건 미충족·미언급 / C3 글자수(byte/char cap)·양식·필수항목 위반(**제출용 본문 블록에 결론/근거/리스크 등 메타 텍스트 혼입** 포함) / C4 날조 또는 문서 간 모순 수치(**수치·고유명사는 저장 데이터의 범위·채널·주체 그대로 쓴다 — '캠페인 누적'을 '인스타그램 누적'처럼 더 좁은 채널/주체로 재귀속(범위 변경)하거나, 저장·공고에 없는 정확수치·기간·비율('입사 후 1~2년'·%·배수)을 단정하면 C4 날조**) / C5 블라인드 위반(공공). <!-- applied: r7-cover-letter / §5 C4 채널 재귀속·파생수치 경계 (R7 cross-vendor PASS) / 2026-06-20 -->
46
50
  **MAJOR:** M1 제너릭·비고유 지원동기(why-this-company 증명 없음) / M2 핵심 성과에 정량 결과 없음(노력어 의존) / M3 경험을 요구 역량/직무에 미연결(문항 의도 놓침) / M4 두괄식·소제목 약함 / M5 빈 형용사 슬롭·AI 균일 / M6 입사후포부 과대·사업방향 무관.
47
51
  **MINOR:** 오탈자·맞춤법 / 상한 대비 과소·과패딩 / 수동·약한 동사·"나" 관점(영문) / 항목 중복·불균등 가중 / (영문) 수신자 결함.
48
52
  **통과 = CRITICAL 0 + MAJOR 0 + 슬롭/제너릭 없음 + 모든 수치가 저장 데이터에 앵커.**
@@ -11,7 +11,7 @@
11
11
  - 전이가능 스킬은 **자기주장이 아니라 행동 증거**로만 인정.
12
12
  - 과적합(overqualified)은 자동 탈락이 아니라 **리스크+완화질문**으로 표시.
13
13
  - 전역 직감 점수 금지 — **요건별로 증거를 인용하고 강도 등급**을 매긴다(구조화 채점이 인상 채점을 이긴다).
14
- - 높은 키워드 커버리지를 높은 적합으로 등치하지 않는다(>75~80%는 스터핑 신호).
14
+ - 높은 키워드 커버리지를 높은 적합으로 등치하지 않는다(여기 커버리지=*이력서의 JD 키워드 밀도*, >75~80%는 스터핑 신호 — [job-analysis](job-analysis.md) §0의 요건 *충족 %*와는 다른 축이며 둘 다 합격 게이트가 아니다).
15
15
 
16
16
  ## 0a. 발명 차단 — 사실 span 앵커 (판정영향 주장만)
17
17
  <!-- applied: r12-fit-contract-invention / 2026-06-21 (consensus R3 전원 agree; 결함-발생률 게이트) -->
@@ -14,7 +14,7 @@
14
14
  - **확신도 분리:** 원문 인용=확정, 그 외는 '추정'이며 확신도를 낮춰 표현한다(예: "이메일 접수형"은 확정, "수시 채용"은 낮은 확신의 추론). **외부 분류 코드(NCS 번호 등)는 데이터로 확정될 때만** 쓰고 아니면 계열명만(코드 발명 금지). 산출물에 'EOP'·내부 기준명을 노출하지 않는다.
15
15
 
16
16
  ## 1. 입력 수집
17
- 공고 텍스트(`get_application_context`의 job, 또는 사용자가 준 경로를 `read_document`/본문 붙여넣기). 회사·플랫폼 맥락.
17
+ 공고 텍스트(`get_application_context`의 job, 또는 사용자가 준 경로를 `read_document`/본문 붙여넣기). **공고가 URL(링크)이면 CareerMate가 가져오지 않으니, 네 브라우징·웹 도구로 본문을 직접 읽어 분석하고 `save_job_posting`에 텍스트로 저장한다(웹 도구가 없으면 사용자에게 본문을 붙여넣어 달라고 요청).** 회사·플랫폼 맥락.
18
18
 
19
19
  ## 2. 분석 절차
20
20
  1. **세그먼트:** 직무내용 / 자격요건(필수) / 우대사항 / 처우·복지 / 회사소개.
@@ -31,7 +31,7 @@
31
31
  - 약점·실패·갈등 문항은 정량 성과가 아니라 **성찰·개선 행동**으로 답하라(이 문항에 'quantified ≥2'를 강요하지 마라).
32
32
  - 글자수 제한을 적용할 때 **count_mode(공백포함/공백제외/byte)** 를 먼저 확인하라.
33
33
  - 클로징에 명확한 다음 단계(면접 요청/연락 가능 시점)를 한 문장으로 넣어라(로케일상 가능할 때).
34
- - 저장 전 `validate_cover_letter`(현재 구현: 수치 출처·문체 신호 자동 검사 / 글자수 게이트·키워드 커버리지는 Phase B 미구현 — 연결 AI 수동)를 적용한 뒤 save_cover_letter_version으로 보관하라.
34
+ - 저장 전 `validate_cover_letter`(현재 구현: 수치 출처·문체 신호 자동 검사 + **글자수 공백포함/제외/byte 카운트 및 min_chars·max_chars·count_mode 상·하한 충족 여부**(advisory, 차단 아님) / 키워드 커버리지는 미구현 — 연결 AI 수동)를 적용한 뒤 save_cover_letter_version으로 보관하라. 한국 문항형은 문항별 한도로 각 문항을 따로 점검하라.
35
35
  - 초안은 get_writing_style_guide의 문체를 적용해 사람이 쓴 듯 자연스럽게 다듬어라.
36
36
 
37
37
  ### Don't
@@ -40,6 +40,7 @@
40
40
  - '성실한·책임감·열정·소통을 잘하는 / 꼼꼼한·끈기있는·헌신적인·주도적인 / hard-working·team player·detail-oriented·motivated·proactive·dedicated·diligent·people person' 같은 **증거 없는 평가형 형용사**나 그 동의어로 자신을 묘사하지 마라.
41
41
  - '~라고 생각합니다', '많은 것을 배웠습니다', '~을 통해 성장했습니다', '귀사' 같은 증거 없는 자기서술 종결구문을 남발하지 마라.
42
42
  - 이력서 불릿을 문장으로 바꿔 그대로 반복하지 마라.
43
+ - **다른 공고에 낸 자소서를 회사명·일부 토큰만 바꿔 재사용하지 마라(자기복제).** 사실·수치·보이스는 공고 간 일관되게 두되(억지 변형 금지), 직무 적합 앵글·도입·산문은 공고마다 새로 짠다. 자기복제는 C1 위반이고, 한국은 표절검사(무하유·Copy Killer)·AI 탐지에서 자기표절로 걸린다.
43
44
  - 회사명을 바꿔도 말이 되는 제너릭 지원동기를 쓰지 마라.
44
45
  - 한 통/한 문항에 5~6개 경험을 얕게 나열하지 마라(1~2개 깊게).
45
46
  - '규모'(담당 규모·팀 인원·연도)를 '성과'로 위장하지 마라 — 본인 행동의 변화량이 결과다.
@@ -65,7 +66,7 @@
65
66
 
66
67
  ## 3. 검증 루브릭 (연결된 AI가 산출물을 이 기준으로 자가검증)
67
68
 
68
- 각 항목의 `measure.type`을 정직하게 표기한다 — **`regex`/`count`/`ratio`** 는 LLM 없이 lint로 자동 검사 가능, **`ai-judge`** 는 연결 AI의 의미 판단이 필요(정규식 불가). 현재 실재하는 정적 검사기는 `validate_cover_letter`(→lintArtifact)이며 **수치 출처(fabricated 차단) + 문체 신호**만 자동 채점한다 — 글자수 상·하한 게이트·키워드 커버리지 카운트는 **Phase B 미구현**이라 연결 AI가 수동(advisory) 적용한다. `ai-judge` 항목은 연결 AI에게 위임한다. (문서의 `lint_cover_letter`는 Phase B 도구 아이디어 명칭이다.)
69
+ 각 항목의 `measure.type`을 정직하게 표기한다 — **`regex`/`count`/`ratio`** 는 LLM 없이 lint로 자동 검사 가능, **`ai-judge`** 는 연결 AI의 의미 판단이 필요(정규식 불가). 현재 실재하는 정적 검사기는 `validate_cover_letter`(→lintArtifact)이며 **수치 출처(fabricated 차단) + 문체 신호 + 글자수(공백포함/제외/byte 카운트와 min/max 상·하한 충족 여부, advisory)**를 자동 채점한다 — 키워드 커버리지 카운트는 **미구현**이라 연결 AI가 수동 적용한다. `ai-judge` 항목은 연결 AI에게 위임한다. (문서의 `lint_cover_letter`는 Phase B 도구 아이디어 명칭이다.)
69
70
 
70
71
  | ID | 검사 항목 | 합격 기준 | 측정 방법(type · LLM 없이 셀 수 있게) |
71
72
  |----|-----------|-----------|--------------------------------|
@@ -77,7 +78,7 @@
77
78
  | R6 | 회사 고유성 | 회사명/제품/미션 고유명사 ≥2회 + 비종속 검사 | `count`(부분 자동) + `ai-judge`(완전 판정) — 토큰 등장 횟수 ≥2는 카운트 가능. '회사명 placeholder 치환 시 어색해지는 문장 ≥1'은 **연결 AI 판정(위임)** |
78
79
  | R7 | 이력서 비반복 | locale별 임계 이하 | `ratio` — 영문: 단어 5-gram 중복 ≤20%. **한국어: 어절 n-gram은 교착어 특성상 부정확 → 임계 신뢰 낮음, 의미 중복은 `ai-judge` 보조 필요(한계 명시)** |
79
80
  | R8 | STAR 행동+성과 동반 | 행동동사 단락 중 결과 절 동반 ≥1, 단 '규모≠성과' | `regex`(약) + `ai-judge` — 행동동사+결과신호 동시출현은 카운트되나 '우연 동시출현·규모 수치'를 구분하려면 연결 AI가 'R이 본인 행동의 변화량인가' 판정 |
80
- | R9 | 분량/글자수 | locale·count_mode별 상·하한 이내 | `count` — 영문 word_count ≤400. 한국: char_count가 지정 limit 이내 **그리고 하한 이상**. **count_mode(with_space\|no_space\|byte) 입력 필수**(미지정 시 fail-safe로 가장 빡빡한 기준 사용). **⚠ 현재 validate_cover_letter는 charCount 계산만 하고 max/min 게이트는 Phase B 미구현 — 글자수 상·하한 판정은 연결 AI 수동(advisory).** |
81
+ | R9 | 분량/글자수 | locale·count_mode별 상·하한 이내 | `count` — 영문 word_count ≤400. 한국: char_count가 지정 limit 이내 **그리고 하한 이상**. **count_mode(with_space\|no_space\|byte) 입력 필수**(미지정 시 fail-safe로 가장 빡빡한 기준 사용). **✅ validate_cover_letter가 공백포함/제외/byte 카운트 + min_chars·max_chars·count_mode 상·하한 충족 여부(over/under/ok)를 advisory로 반환한다(저장 차단은 안 함). 문항형은 문항별 한도로 따로 호출.** |
81
82
  | R10 | 공고 요구 매핑 | 공고 키워드 ≥3개가 증거와 함께 등장 | `ai-judge`(+count는 설계) — '증거 동반' 판정은 의미 판단이라 위임. **⚠ 키워드 토큰 매치 카운트는 현재 validate_cover_letter에 미구현(Phase B) — 키워드 커버리지·증거 동반 모두 연결 AI 수동.** **`job.requirements`/`keywords`가 비면 skip(N/A)** — 데이터 부재 시 통과/실패 강제 금지 |
82
83
  | R11 | 블라인드 가드레일 | 직무무관 개인정보 패턴 0건 | `regex` — `/(\d{2,3}\s?세|남자|여자|아버지|어머니|출신|본적|사진 첨부)/` 등 NCS 금지정보 매치 = 0(locale='ko') |
83
84
  | R12 | 1인칭 과다 | '저는/I'로 시작하는 문장 비율 ≤40% | `ratio` — 문장 분리 후 시작 토큰이 (저는\|제가\|^I\b)인 비율 계산 ≤0.40 |
@@ -18,6 +18,8 @@
18
18
  - **(사실·수치·고유명사 보존)** 기간·규모·도구·회사명 등 사실·수치·고유명사는 변형 없이 보존하고, 매핑 시 원문 수치를 그대로(substring) 인용한다. 추정·반올림·과장 금지. _(출처: AGENTS.md 보존 규칙; STAR 정량화)_
19
19
  - **(하드 게이트 별도 식별 + ATS knockout 인지)** '경력 N년 이상'·국가자격증·면허·비자·근무지 같은 **하드 게이트**는 별도 표시하고 소프트 스킬로 상쇄되지 않음을 분명히 한다. 이런 binary 요건은 ATS의 knockout/스크리닝 사전질문에서 **실제로 자동탈락되는 경우가 흔하다**(키워드 자동탈락은 드물어도 구조화 사전질문 탈락은 흔하다). 따라서 '자동탈락은 드뭄'을 하드 게이트에 일반화하지 마라. _(출처: O*NET 규제요건; NCS 자격요건; ATS knockout 실무)_
20
20
  - **(범위 한계 명시 + 오버퀄/방향 불일치)** 이 분석은 '증거로 매핑 가능한 하드 요건' 중심이며, 협업·커뮤니케이션 같은 **soft/culture fit는 다루지 않음을 명시**한다(적합도 ≠ 합격가능성). 또한 미달뿐 아니라 **오버퀄(시니어가 주니어 JD 지원)·커리어 방향 불일치**도 리스크로 표기한다. _(출처: 채용 매니저 실무; O*NET은 soft 신호 판정 도구 아님)_
21
+ - **(레벨 전략 — 타깃 레벨 캘리브레이션)** 요건 충족/미충족과 **별개로**, JD가 암시하는 직급(직함·요구 연차·책임 범위·보상 밴드)에 대해 후보가 **언더레벨 / 적정 / 오버레벨** 중 어디인지 판정하고, 경우별 포지셔닝을 제시한다. 언더레벨=궤적·전이가능 스코프·빠른 성장 근거로 보강하고 부족 영역을 솔직히 다룸; 적정=표준 강조; 오버레벨=*왜 이 직급에 지원하는지*(다운시프트 동기)·flight-risk·기대보상 재조정을 선제 해명. 이는 단순 '오버퀄 리스크 플래그'를 넘어 **행동 가능한 전략**으로 적는다. _(출처: career-ops 방법론 차용 — level strategy; 채용 매니저 실무)_
22
+ - **(의사결정 스코어카드 — '추구할 공고인가' 필터)** 요건별 표에 더해, 공고를 **소수의 의사결정 차원으로 압축한 스코어카드**(예: 직무 적합 · 레벨 적합 · 성장/학습 신호 · 보상 신호 · 근무조건(지역·원격) · 안정성/진위)를 상·중·하(또는 A~F)로 제시해 '지원에 시간을 쓸 가치가 있나'를 한눈에 돕는다. **CareerMate는 아무것도 계산하지 않는다** — 판정은 AI가 하고, 보상·문화 같은 차원은 저장된 사실에 없으면 사용자 입력·리서치가 필요함을 명시한다(없는 값을 지어내지 말 것). 오퍼를 *받은 뒤*의 심층 비교는 `offer-evaluation-decision` 플레이북 소관이며, 여기 스코어카드는 *지원 전 필터*다(경계 분리, 중복 금지). 양/질 모두에서 **점수가 낮으면 지원을 권하지 않는** 필터로 쓰되, 단일 합산점수를 '합격 확률'로 착각하지 않게 한다. _(출처: career-ops 방법론 차용 — 가중 차원 스코어링; 본 문서 충족률=맥락 신호 원칙과 정합)_
21
23
 
22
24
  ### Do
23
25
 
@@ -63,11 +65,11 @@
63
65
  | ID | 검사 항목 | 합격 기준 | 측정 방법(LLM 없이 셀 수 있게) |
64
66
  |----|-----------|-----------|--------------------------------|
65
67
  | R1 | 모든 요건에 [필수/우대] 라벨 + 복합 요건 분해 | 라벨 누락 0개; 쉼표·'및'·'and/or'로 묶인 줄이 개별 항목으로 분리됨 | 추출 항목 수를 세고 각 항목에 'must'/'nice' 토큰 존재 확인(누락==0). 원문에서 구분자 포함 줄 수 대비 분해 항목 수가 ≥ 구분자+1 인지 검사 |
66
- | R2 | 충족·부분충족 판정에 출처 ID + evidence 존재 | status가 met·partial인데 evidence[] 배열이 빈 항목 0개 | (AI 셀프체크 기준으로 유효; **서버 강제는 Phase B** — 현재 save_fit_analysis 스키마에 requirements[]/evidence 필드 없음) met·partial 항목 수 대비 `evidence.length>0` 항목 수 비율 == 100% |
67
- | R3 | quotedBullet/quotedMetric이 원문 substring (환각·수치변형 차단) | 인용 문자열이 해당 sourceId 입력 텍스트의 부분문자열이 아닌 항목 0개 | (AI 셀프체크 기준으로 유효; **서버 강제는 Phase B** — 입력 구조 부재, 현재 연결 AI가 substring 수동 대조) 각 evidence의 quotedBullet을 입력 이력서/경력 텍스트에 대해 indexOf/`includes` 문자열 검색 → 미발견 개수 == 0 |
68
+ | R2 | 충족·부분충족 판정에 출처 ID + evidence 존재 | status가 met·partial인데 evidence[] 배열이 빈 항목 0개 | (AI 셀프체크 — 서버 자동검사는 아직 없음) met·partial 항목 수 대비 `evidence.length>0` 항목 수 비율 == 100% |
69
+ | R3 | quotedBullet/quotedMetric이 원문 substring (환각·수치변형 차단) | 인용 문자열이 해당 sourceId 입력 텍스트의 부분문자열이 아닌 항목 0개 | (AI 셀프체크 — 서버 자동검사는 아직 없음) 각 evidence의 quotedBullet을 입력 이력서/경력 텍스트에 대해 indexOf/`includes` 문자열 검색 → 미발견 개수 == 0 |
68
70
  | R4 | gap 표기 + must-have 미충족마다 완화 전략 | 미충족 must 중 mitigation 문장이 없는 항목 0개 | 미충족 must 개수 == mitigation 문장 개수 비교 |
69
71
  | R5 | must-have 충족률 수치 제시 + partial 제외 규칙 | 'met must 수 / 전체 must 수' 분수·% 1개 이상; 분자에 partial 미포함 | 분수/% 정규식(예: `\d+/\d+`, `\d+%`)이 must 문맥과 함께 1회 이상; 분자 == status=='met' 개수와 일치 확인 |
70
- | R6 | critical·hardGate gap 시 '권장 불가' 병기 (게이트 단독 우선) | hardGate 또는 critical이 gap인데 verdict가 'recommend'인 사례 0개 | (AI 셀프체크 기준으로 유효; **서버 강제는 Phase B** — verdict/requirements 필드 부재, 현재 연결 AI가 수동으로 '권장 불가' 강제) `requirements`에 `hardGate&&status==gap` 또는 `critical&&status==gap`이 1개라도 있으면 `verdict=='recommend'` 금지 |
72
+ | R6 | critical·hardGate gap 시 '권장 불가' 병기 (게이트 단독 우선) | hardGate 또는 critical이 gap인데 verdict가 'recommend'인 사례 0개 | (AI 셀프체크 — 서버 자동검사는 아직 없음) `requirements`에 `hardGate&&status==gap` 또는 `critical&&status==gap`이 1개라도 있으면 `verdict=='recommend'` 금지 |
71
73
  | R7 | 키워드 표면 존재가 의미 매칭과 분리 보고 | JD 핵심 키워드별 'O/X' 표기 1개 이상, 의미 매칭 충족 판정과 별도 필드 | 출력에 `keywordSurfacePresent` 또는 'O/X·있음/없음' 항목 카운트 ≥ 1 |
72
74
  | R8 | partial 남용 방지 (사유 강제) | partial 항목 중 '왜 full이 아닌지' 사유 문장이 없는 항목 0개 | partial 항목 수 == partialReason 문장 수 비교 |
73
75
  | R9 | gap 과소평가(false-negative) 방지 | gap으로 분류한 must마다 인접 증거 탐색 시도 흔적 존재 | gap must 개수 대비 `transferAttempt` 표기(예: "인접 검토: …") 항목 수 == 100% |
@@ -2,6 +2,8 @@
2
2
 
3
3
  > 이 문서는 CareerMate가 **연결된 AI에게 제공(serve)** 하는 지식이다. CareerMate 안에는 LLM이 없다 — 분석·작성·검증은 연결된 AI가 수행하고, 이 플레이북·루브릭은 그 AI가 **세계 최고 수준**으로 일하도록 안내한다.
4
4
 
5
+ > **역할 경계:** 이 문서는 글을 **쓰는·생성하는(write)** 단계의 플레이북이다(`get_playbook`, 작성 직전). 다 쓴 초안을 **저장 직전 점검·채점**하는 일은 짝 검증기 [`verifiers/human-voice.md`](verifiers/human-voice.md)(`get_verifier`)가 맡는다 — 같은 주제라도 *쓰기 지침*과 *검증 루브릭*은 역할이 다르고, 두 곳의 강도 차이(예: 사실 보존이 여기선 LLM-플래그, 검증기 C8·C9에선 하드 게이트)는 **의도된 것**이다. 두 문서는 슬롭·과장·클리셰·번역투 사전을 **의도적으로 각자 온전히 복제**해 들고 있다 — 한쪽만 호출돼도 사전이 온전하도록 함이니, **단일 출처로 합치거나 다른 문서 포인터로 대체하지 마라(독립 serve가 깨진다).**
6
+
5
7
  ## 1. 무엇을 하는가
6
8
 
7
9
  커리어 문서(자기소개서·자기 PR·지원 메일·면접 답변)를 "AI가 쓴 티" 없이, 사용자 고유의 목소리로, 사실을 보존하며 쓰도록 연결된 AI를 안내한다. CareerMate의 **1차 사용자층은 한국어 자소서 작성자**이므로 이 플레이북은 한국어 슬롭(번역투·클리셰·기계적 병렬·수동태)을 1차 기준으로, 영어 마커는 영문 지원서일 때만 적용하는 **보조 기준**으로 둔다. 이 문서는 기존 `packages/prompts/src/humanize.ts`의 정성 가이드(한국어 8개 항목, `epoko77-ai/im-not-ai` 근거)를 **상위 단일 원본으로 흡수·확장**하고, 거기에 "LLM 없이 셀 수 있는" 결정론 루브릭과 채용 적합성 축을 더한 것이다. 핵심은 슬롭 제거가 아니라 **"거짓 없고 직무에 맞닿은, 사람 목소리의 글"**을 만드는 것이다 — 슬롭이 0이어도 동문서답·내용 공백이면 떨어진다.
@@ -0,0 +1,57 @@
1
+ # AI 탐지 리스크 (AI-detection-risk) — CareerMate 교차검증 루브릭 (Phase A)
2
+
3
+ > 이 검증기는 연결된 AI가 한국 채용 산출물(특히 자기소개서·경력기술서)을 **저장 직전** 점검할 때 적용하는 **크리틱 루브릭**이다. CareerMate는 루브릭을 제공하고, 실제 검사·판정은 연결된 AI가 수행한다(내부 LLM 없음).
4
+
5
+ > **역할 경계 (중요).** 이 루브릭의 목적은 **탐지기를 속이는 것이 아니다.** "GPT킬러를 우회하는 법"을 가르치지 않는다 — 그것은 기만이고, 한국 HR 현실에서도 실패하는 전략이다. 이 루브릭이 보장하려는 것은 **글이 실제로 지원자 본인의 것이고(진정성), 면접에서 한 문장 한 문장 설명할 수 있는가(방어가능성)** 다. 그 결과로 탐지 리스크는 *부차적으로* 낮아진다. 즉 검사 대상은 "AI 티"가 아니라 **"내 것이 아닌·설명 못 하는 부분"** 이다. (문체의 "AI 티" 자체는 짝 검증기 [`human-voice.md`](./human-voice.md)가 담당한다 — 둘은 역할이 다르다.)
6
+
7
+ ## 1. 목적 — 왜 한국 시장에서 이게 별도 검증기인가
8
+
9
+ 한국 채용은 자기소개서 비중이 크고, **AI 작성 탐지가 제도화**돼 있다. 검증된 시장 사실:
10
+
11
+ - 2025년 제출 자소서의 **약 64%가 AI 작성으로 추정**됐고(전년 48.5%), 전 문항 AI 작성도 20.6%로 늘었다.
12
+ - **무하유 GPT킬러**(문장 구조·확률분포·패턴 기반 AI 생성률 산출)는 탐지 정확도를 **최대 98%**로 표방하며 LG전자·롯데·KB국민은행·국민연금공단 등이 도입했다. 표절 검사 **카피킬러**는 국내 대학 96%가 쓴다. B2B 솔루션 **프리즘(PRISM)**은 마스킹+표절+AI 탐지+면접질문 생성을 묶는다.
13
+ - 기업의 **65.4%가 AI 자소서 적발 시 불이익**을 준다고 답했다.
14
+
15
+ 그런데 **탐지 = 즉시 탈락은 아니다.** HR 담당자들의 공통 입장은 *"AI를 썼느냐보다, 그 내용을 면접에서 본인이 설명할 수 있느냐"* 다. 동시에 탐지기는 **신뢰성 한계**가 분명하다 — OpenAI는 자사 AI 분류기를 2023년 정확도 부족으로 폐기했고, Stanford 연구는 탐지기가 **비원어민 글을 거짓양성으로 과도하게 적발**한다고 보고했다. 즉 탐지기는 틀릴 수 있고, 방어선은 "탐지를 피하는 글"이 아니라 **"누가 봐도 내 경험에서 나온, 내가 설명 가능한 글"** 이다.
16
+
17
+ 따라서 이 검증기는 다음을 본다: ① 본문의 모든 구체 주장이 **지원자의 저장된 사실(이력서·경력·프로젝트)에 앵커**되는가, ② 면접에서 **꼬리질문에 답할 수 있는** 구체성(상황·행동·수치)이 있는가, ③ 일반론·차용 가능한 문장(회사명만 바꾸면 어디든 통하는 글)이 과하지 않은가.
18
+
19
+ ## 2. 검사 항목
20
+
21
+ > 적용 단위: 한 산출물(자소서 1편/문항, 경력기술서 1부). "주장"은 지원자가 자신에 대해 단언하는 문장(역량·성과·경험·동기)을 가리킨다.
22
+
23
+ | ID | 검사 | 합격 기준 | 측정 방법(셀 수 있게) |
24
+ |----|------|-----------|------------------------|
25
+ | D1 | 구체 주장의 앵커링 | 본문의 모든 성과·경험 주장이 저장된 사실(이력서 본문·경력·프로젝트)에 **추적 가능**. 미앵커 주장 0건 | 각 주장 문장에서 (회사/역할/수치/기술/사건) 토큰 추출 → 저장 코퍼스에 존재하는지 대조. 어디에도 없는 주장 수 = 0. (수치는 결정론 점검 `validate_cover_letter`의 `fabricated`/`unverified`와 교차) |
26
+ | D2 | 면접 방어가능성 | 각 핵심 일화가 **꼬리질문 1개에 답할 구체(상황·내 행동·결과)** 를 담음. "설명 못 할" 일반 문장 비율 ≤ 20% | 일화 문장에 (구체 행위 동사+목적어) 또는 (수치/기간/규모)가 있는지 확인 → 없는 문장 비율. "면접관이 '구체적으로 뭘 하셨죠?'라 물으면 막히는 문장" 카운트 |
27
+ | D3 | 차용 가능성(swappability) | 회사명·직무명을 **다른 공고로 바꿔도 그대로 통하는** 일반 문장이 과하지 않음(도입·지원동기에서 특히). 전체의 30% 미만 | 회사 고유 사실(제품·인재상·핵심가치·최근 이슈)·지원자 고유 사실 중 **어느 쪽도 참조하지 않는** 문장 비율. (공고에 `company_overview`/`talent_profile`/`core_values`가 저장돼 있으면 그 정렬 여부로 본다) |
28
+ | D4 | 일반론·교과서 정의 밀도 | "○○란 ~이다", "급변하는 시대에는~" 류 **누구나 쓸 수 있는 정의·시류 진술**이 과하지 않음. 100문장당 3개 이하 | 결정론 lint의 `cliche`·`generic_opener`·`hype` 신호 수를 참조 + 정의형 문장("~란 …입니다") 패턴 카운트 |
29
+ | D5 | 자기복제(carryover) | 다른 공고용 기존 자소서에서 **회사명만 바꾼 문단·문장**을 그대로 옮겨오지 않음(끌개 복제 방지). verbatim 재사용 문장 0건, 산문 carryover ≤ 20% | 기존 자소서(맥락에 포함)와 신규 본문을 문장 단위로 대조 → 사실 일관 영역(보이스·수치)은 허용하되, *직무 적합 앵글·도입·지원동기 산문*의 verbatim 일치 수와 carryover 비율 측정. (짝 가드: 자기복제 방지 EOP) |
30
+ | D6 | 탐지기 한계 인지(거짓확신 방지) | 결과 보고 시 "탐지 통과=합격"·"탐지=탈락"의 **양쪽 거짓확신을 두지 않음** | 점검 결론에 (a) 탐지기는 틀릴 수 있음(비원어민 거짓양성) (b) 최종 관문은 면접 설명력임을 명시했는지 확인(서술 점검) |
31
+
32
+ ## 3. 불합격 시 처리(루프 연결)
33
+
34
+ - **D1 미앵커 주장(critical):** 저장된 사실에 없는 성과·경험은 (a) 사용자에게 사실 여부를 확인해 근거를 보강하거나 (b) 문장을 제거한다. **임의로 그럴듯하게 채우지 않는다**(환각 금지). 수치는 결정론 게이트(`validate_cover_letter`)와 교차해 차단.
35
+ - **D2 방어 불가 문장(critical):** "막히는 문장"은 그 일화의 *내 행동·구체 결과*로 다시 쓴다. 채울 구체가 없으면 그 일화 자체를 더 설명 가능한 다른 경험으로 교체. 동반 면접 준비(`save_interview_prep`)로 꼬리질문 답을 미리 준비하도록 연결.
36
+ - **D3 차용 가능 문장(warn→fix):** 회사 고유 사실(저장된 `company_overview`/`talent_profile`/`core_values` 또는 사용자 리서치)이나 지원자 고유 사실로 재작성. 둘 다 없으면 사용자에게 회사 리서치·본인 일화를 청한다.
37
+ - **D4 일반론 과다(warn):** 정의·시류 진술을 지원자 경험 진술로 치환. 글자수가 빠듯하면 일반론부터 덜어낸다.
38
+ - **D5 자기복제(critical):** 사실·수치·보이스는 일관 유지하되, **직무 적합 앵글·도입·지원동기는 공고별로 새로 쓴다.** 같은 결함이 2번 고쳐도 남으면 멈추고 사용자에게 확인(무한정 변형으로 사실 왜곡 금지).
39
+ - **D6 보고 프레이밍:** 사용자에게 결과를 전할 때 탐지 점수를 단정하지 말고, "탐지기는 오탐이 있으며 핵심은 면접 설명력"이라는 맥락과 함께 전한다.
40
+ - **종료 조건:** D1·D2·D5 critical 0건 + D3·D4 사용자 확인 완료. 통과 시 `save_cover_letter_version`/`add_resume`로 저장하고 대시보드 링크 안내, 이어서 면접 준비를 다음 행동으로 제안.
41
+
42
+ > **윤리 경계:** 이 루프의 어느 단계도 "사실을 왜곡해 탐지를 피하라"고 지시하지 않는다. 탐지 리스크는 *진정성·구체성·차별화*의 부산물로만 낮춘다. 사실·수치·고유명사는 끝까지 보존한다.
43
+
44
+ ## 4. 출처 (Provenance)
45
+
46
+ - **AI 자소서 비율 64.4%(2025)·전문항 20.6%** — 무하유·프리즘 데이터(언론 종합) · https://v.daum.net/v/20251123025247720
47
+ - **무하유 GPT킬러 탐지율 최대 98%·대기업 도입·카피킬러 대학 96%·프리즘** — 무하유 공식 · https://www.copykiller.com/gptkiller , https://www.muhayu.com/
48
+ - **기업 65.4% 적발 시 불이익·"AI 여부보다 면접 설명력"** — 고용노동부·한국고용정보원 및 HR 인식 조사(언론 종합)
49
+ - **OpenAI AI 분류기 2023 폐기(정확도 부족)** — OpenAI, "AI classifier" 회수 공지(2023)
50
+ - **탐지기 비원어민 거짓양성** — Liang et al., Stanford, "GPT detectors are biased against non-native English writers" (2023) · https://arxiv.org/abs/2304.02819
51
+ - **자기복제 방지 설계** — CareerMate ADR-0005, EOP `cover-letter.md` §1·§2-3·§5
52
+
53
+ ## 5. Phase B 힌트
54
+
55
+ - **결정론 연계:** D1(수치)·D4(클리셰/제너릭/하이프)·D5(자기복제 후보)는 이미 `@careermate/core/verify`(lint 신호·provenance)로 일부 셀 수 있다 — 이 검증기는 그 결과를 **의미 판단으로 묶는** 상위 루브릭이다. `validate_cover_letter` 리포트의 `fabricated`/`signals`를 D1/D4 입력으로 재사용.
56
+ - **MCP 도구 아이디어:** `get_verifier({ id: "ai-detection-risk" })` — 이 루브릭 반환. 별도 점수 도구는 만들지 않는다(탐지 점수의 단정은 거짓확신을 낳으므로 의도적으로 회피).
57
+ - **데이터 형태 힌트:** 입력 = 신규 본문 + `get_application_context`의 저장 사실 + 기존 자소서 + (있으면) 공고의 회사 리서치 필드. 출력 = `{ unanchored_claims[], undefendable_sentences[], swappable_ratio, carryover_ratio, framing_ok }` — 모두 연결 AI가 채운다.
@@ -25,7 +25,7 @@
25
25
  | C5 | 이미지·아이콘·스킬바 부재 | 그래픽 요소 0개 | 이미지 마크업(`![]`, `<img`)·이모지/심볼로 표기된 연락처 아이콘·"skill bar" 채움문자(예: ●●●○○, █) 출현 횟수 **= 0** |
26
26
  | C6 | 연락처가 본문 상단에 위치 | 이메일·전화가 헤더/푸터가 아닌 본문 첫 영역에 존재 | 본문 텍스트 첫 15% 구간(또는 첫 5줄) 안에서 이메일 정규식(`[\w.+-]+@[\w-]+\.[\w.]+`) 매치 **≥ 1** 그리고 전화 패턴 매치 **≥ 1** |
27
27
  | C7 | 일관된 날짜 형식 | 경력/학력 기간이 ATS가 인식하는 형식으로 통일 | 날짜 토큰을 추출해 허용 패턴(`MMM YYYY`, `Month YYYY`, `MM/YYYY`, `YYYY.MM`, `YYYY-MM`) 중 **단일 패턴 비율 ≥ 90%**. 혼용·"현재/Present" 외 자유서술 날짜 비율 < 10% |
28
- | C8 *(advisory)* | JD 하드스킬 키워드 커버리지 | JD 상위 키워드의 충분 비율을 본문이 포함 | 산출물 본문에 존재하는 키워드 개수 M / JD 추출 키워드 N → **M/N ≥ 0.70 = 권장 출발점(advisory·비차단; 0.70은 법칙이 아니라 출발점이며 AI가 JD 규모·역할 수에 맞게 조정)**. 바로 옆 75%+(Jobscan 권장)/80%(스위트스폿)는 **비구속 상류 참조치 — 제2 임계값 아님**(단일 합격선은 0.70 하나). 매칭은 raw substring이 아니라 **외부 AI가 원문 JD·이력서 텍스트를 정규화·동의어 묶음(JD 요구사항 자체는 불변)한 토큰 집합을 토큰 경계로** 센다(raw substring 금지; ats.md R4 동일 원본; `Java`⊂`JavaScript` 거짓양성 차단). JD 미제공 시 N/A 처리하고 사유 기록 |
28
+ | C8 *(advisory)* | JD 하드스킬 키워드 커버리지 | JD 상위 키워드의 충분 비율을 본문이 포함 | 산출물 본문에 존재하는 키워드 개수 M / JD 추출 키워드 N → **M/N ≥ 0.70 = 권장 출발점(advisory·비차단; 0.70은 법칙이 아니라 출발점이며 AI가 JD 규모·역할 수에 맞게 조정)**. 바로 옆 75%+(Jobscan 권장)/80%(스위트스폿)는 **비구속 상류 참조치 — 제2 임계값 아님**(단일 합격선은 0.70 하나). 매칭은 raw substring이 아니라 **외부 AI가 원문 JD·이력서 텍스트를 정규화·동의어 묶음(JD 요구사항 자체는 불변)한 토큰 집합을 토큰 경계로** 센다(raw substring 금지; ats.md R4 동일 원본; `Java`⊂`JavaScript` 거짓양성 차단). JD 미제공 시 N/A 처리하고 사유 기록. **축 구분(메타):** 이 C8 = JD 키워드 *표면 존재(presence)* M/N≥0.70 **advisory**. `responsiveness-on-target` C8 = JD *필수요건 응답(response)* 커버리지 ≥80% **critical** — **다른 축**이라 한 자소서가 한쪽 통과·다른 쪽 미달이어도 **충돌이 아니다**(키워드가 표면에 있어도 요건에 *응답*하지 않을 수 있고, 요건에 응답해도 ATS 표면 키워드가 모자랄 수 있다) |
29
29
  | C9 | 직무명(target job title) 일치 | JD의 핵심 직무명이 본문에 등장 | JD 헤드라인 직무명을 본문(이력서 요약/타이틀, LinkedIn 헤드라인)에서 정확/근접 일치로 탐색 → 매치 **≥ 1** |
30
30
  | C10 | 키워드 스터핑 방지(과최적화) | 특정 키워드 반복이 과하지 않음 | C8 키워드 각각의 본문 등장 횟수 중 **어떤 단일 키워드도 6회 초과 금지**, 그리고 키워드 토큰이 전체 토큰에서 차지하는 비율 **< 6%**. 위반 키워드 개수 = 0 목표 |
31
31
  | C11 | 약어·풀네임 병기 | 핵심 약어가 풀네임과 함께 1회 이상 병기 | JD/본문 공통 약어(예: ATS, SQL, PM) 중 본문에 약어만 단독 등장하고 풀네임 동반이 0인 항목 개수 → **0 목표**(파서/사람 양쪽 매칭 보장) |
@@ -2,6 +2,8 @@
2
2
 
3
3
  > 이 검증기는 연결된 AI가 커리어 산출물(이력서·자소서·면접 답변·LinkedIn 등)을 점검할 때 적용하는 **크리틱 루브릭**이다. CareerMate는 루브릭을 제공하고, 실제 검사는 연결된 AI가 수행한다(내부 LLM 없음).
4
4
 
5
+ > **역할 경계:** 이 문서는 다 쓴 초안을 **저장 직전 점검·채점하는(verify)** 크리틱 루브릭이다(`get_verifier`, 저장 직전). 글을 **쓰는·생성하는** 단계의 지침은 짝 플레이북 [`../human-writing.md`](../human-writing.md)(`get_playbook`)에 있다 — *검증 루브릭*과 *쓰기 지침*은 역할이 다르고, 두 곳의 강도 차이(예: 사실 보존이 여기 C8·C9에선 하드 게이트, 플레이북에선 LLM-플래그)는 **의도된 것**이다. 두 문서의 사전은 **의도적으로 각자 온전히 복제**돼 있다(독립 호출 안전) — **단일 출처화·포인터 대체 금지(한쪽만 불려오면 사전이 사라진다).**
6
+
5
7
  ## 1. 목적
6
8
 
7
9
  이 검증기는 커리어 산출물이 **"AI가 쓴 티"가 나지 않고 사람의 목소리로 읽히는지**를 보장한다. 채용 담당자는 천편일률적인 자동 생성 글을 즉시 알아채고 신뢰를 거둔다. 구체적으로 다음 네 가지를 본다.
@@ -34,7 +34,7 @@
34
34
  | C5 | 형식 토큰 충족 | 문항이 명시한 형식 요소가 모두 존재. 예: STAR 면접이면 Situation·Task·Action·Result 4요소, "구체적 사례" 요구면 사례 1건+ | det/D · 형식 체크리스트별 대응 토큰/구간 존재 카운트 → 누락 요소 수 = 0 |
35
35
  | C6 | 글자 수/분량 준수 | 자소서 문항의 **글자 수 상·하한**을 지킴(한국 공채 자사양식의 핵심 탈락 사유). 범위 내 | det/D · 응답 길이(공백 포함/제외 둘 다) vs 문항 제한. 초과·미달 글자 수 출력 |
36
36
  | C7 | 질문 직접 응답성 | 응답이 질문에 **직접** 답하고 우회·일반론으로 빠지지 않음(off-target/회피 0건) | ai/H · 연결 AI가 "이 응답이 이 질문에 답하는가"를 Y/N 판정. N이면 빗나간 지점 명시 |
37
- | C8 | JD 필수 요건 커버리지 | JD의 **필수(required) 요건** 항목 중 산출물(이력서+자소서)에서 다뤄진 비율 **≥ 80%**, 필수 요건 미커버 **0개**. (이 ≥80%는 응답성 커버리지 신호이며 적합(fit) 권장 게이트가 아니다 — 적합 판정은 `fit-matching`/`fit-analysis`가 하드요건(knockout)으로 내린다. C8 자체는 응답성 루프 내 critical 검사로, 미달은 적합·지원을 차단하는 게 아니라 §3 보강 재작성을 트리거한다.) | det/D · JD에서 필수/우대 요건 분리 추출 → 각 요건 키워드가 산출물에 존재하는지 매칭 → (커버 요건 ÷ 전체 필수). 미커버 필수 요건 나열 |
37
+ | C8 | JD 필수 요건 커버리지 | JD의 **필수(required) 요건** 항목 중 산출물(이력서+자소서)에서 다뤄진 비율 **≥ 80%**, 필수 요건 미커버 **0개**. (이 ≥80%는 응답성 커버리지 신호이며 적합(fit) 권장 게이트가 아니다 — 적합 판정은 `fit-matching`/`fit-analysis`가 하드요건(knockout)으로 내린다. C8 자체는 응답성 루프 내 critical 검사로, 미달은 적합·지원을 차단하는 게 아니라 §3 보강 재작성을 트리거한다.) | det/D · JD에서 필수/우대 요건 분리 추출 → 각 요건 키워드가 산출물에 존재하는지 매칭 → (커버 요건 ÷ 전체 필수). 미커버 필수 요건 나열. **축 구분(메타):** 이 C8 = JD *필수요건 응답(response)* 커버리지 ≥80% **critical**. `ats-compat` C8 = JD 키워드 *표면 존재(presence)* M/N≥0.70 **advisory** — **다른 축**이라 두 게이트의 숫자·방향이 달라도 **충돌이 아니다**(요건에 응답해도 ATS 표면 키워드가 모자랄 수 있고, 키워드가 표면에 있어도 요건에 응답 안 할 수 있다) |
38
38
  | C9 | JD 우대 요건 커버리지 | **우대(preferred)** 요건 커버 비율 보고(차단 아님, 경고). 권장 ≥ 50% | det/D · C8과 동일 로직을 우대 요건에 적용. 비율만 리포트, 미달은 warning |
39
39
  | C10 | 과잉/딴소리 비율 | 응답 중 질문과 무관한 문장(Q-keyword·directive 어느 것과도 무관) 비율 **< 20%** | det/D + ai/H · 각 문장을 질문 관련/무관으로 태깅(키워드 매칭=det, 환언 무관 판정=ai) → 무관 문장 비율 |
40
40
  | C11 | 질문 전제·제약 준수 | 질문이 건 제약(예: "**팀** 경험", "**실패** 사례", "최근 3년 내")을 응답이 위반하지 않음 | ai/H · 질문의 한정어(팀/개인, 성공/실패, 기간) 추출 → 응답 사례가 그 한정과 일치하는지 판정. 위반 사례 개수 = 0 |
@@ -11,6 +11,7 @@
11
11
  - **과장(inflation):** 있는 사실을 부풀림(직함 격상, 팀 성과를 개인 성과로 귀속, "참여"를 "주도"로).
12
12
  - **미검증 정밀도(false precision):** 저장 데이터에 근거 없는 구체 수치("매출 37% 증가")를 생성.
13
13
  - **갭 은폐(gap concealment):** 모르는 것을 모른다고 하지 않고 빈칸을 그럴듯하게 메움.
14
+ - **속성 추론 비약(attribute leap):** 저장된 *기법·행위*에서 저장되지 않은 *성과·속성*을 단정하는 "그럴듯한 추론" 누수. **기법·무결성 ≠ 성과·가용성·규모.** 예: "듀얼라이트·대사(정합성 기법)" → "무중단/제로다운타임(가용성 성과)" 단정; "정합성 오류 0건" → "장애 0"; "Kafka 사용" → "대용량"; "p99 개선" → "사용자 경험 개선" 단정. 기법이 그 성과를 *가능케 한다*고 저장 성과 자체는 없으면 단정 금지 — 기법만 진술하거나 `[확인 필요]`로 둔다(가장 흔하고, 숫자·고유명사가 없어 결정론으로 안 잡히는 누수다).
14
15
 
15
16
  > 경계 원칙: **표현을 강하게 다듬는 것(action verb·두괄식·정량화)은 허용, 사실을 바꾸는 것은 금지.** 강한 동사로 쓰되 동사가 가리키는 행위·결과는 저장 데이터와 일치해야 한다. 이 검증기는 사람처럼 쓰기(`human-writing.md`)의 "Fact lock(R7)" 신호를 **전 산출물·전 사실유형으로 확장한 전용 게이트**다.
16
17