지난 글에서는 평가 사례의 조건과 설명을 나눴다. 설명이나 검토 상태를 고쳤다는 이유로 이전 평가와 비교할 수 없게 되면 안 됐기 때문이다.

이번에는 지원 결과를 기록하는 기능을 붙였다. PR #13에 담은 M4-C 작업이다. “지원했다”, “면접을 봤다”, “탈락했다”에서 조금 더 나아가, 어느 단계까지 갔는지 돌아볼 수 있게 만드는 일이다.

그런데 리뷰에서 또 비슷한 질문을 만나게 됐다.

새로운 사실을 추가한 것인가, 이전 사실을 고친 것인가?

이 글은 수정 커밋 c2a862a를 재검토하고 PR을 병합한 뒤 남기는 기록이다. 아래 사례는 실제 지원자의 기록이 아니라 합성 데이터로 확인했다.

같은 탈락이어도, 지나온 과정은 다르다

서류에서 탈락한 지원과 최종 면접에서 탈락한 지원은 마지막 상태만 보면 둘 다 rejected다. 하지만 나중에 지원 경험을 돌아볼 때 알고 싶은 내용은 다르다.

어떤 역할에서는 대화가 시작됐는지, 어떤 지원에서는 면접까지 이어졌는지. 결과를 기록하는 도구라면 이런 차이는 남길 수 있어야 할 것 같았다.

그래서 지원 상태와 별도로 서류·기술 면접·최종 면접 같은 단계를 기록하고, 알려진 단계에 도달한 지원 건수를 집계하도록 했다. 단계를 모르면 모른다고 남긴다. 최종 면접 기록이 있다고 해서 그전에 기술 면접도 봤을 것이라고 채워 넣지는 않는다.

원래의 공고 판정도 그대로 둔다. REALISTIC으로 저장했던 공고에서 탈락했다고 그 판정을 PASS로 바꾸지는 않는다. 지원해 볼 만하다는 판단과 실제 채용 결과는 같은 것이 아니기 때문이다.

앱의 방향을 정리했던 글에서 나눴던 두 질문을, 이번에는 데이터와 화면으로 옮겨 본 셈이다.

다음 소식을 알려줬는데, 앞의 소식을 대체했다

처음 구현에도 진행과 정정을 구분하는 옵션은 있었다.

  • append: 새 진행 상황을 이력에 추가한다.
  • replace: 이전 결과 이력 전체를 현재 집계에서 제외하고 정정된 기록을 기준으로 삼는다.

문제는 옵션을 생략했을 때 replace가 기본이었다는 점이다.

리뷰에서는 이력 모드를 지정하지 않고 다음 순서로 결과를 보냈다.

지원함 → 기술 면접 → 최종 면접에서 탈락

기대했던 것은 현재 상태는 탈락이되, 기술 면접과 최종 면접에 도달했다는 기록은 둘 다 남는 것이었다. 실제로는 최종 결과를 기록하면서 앞의 기술 면접 도달 기록이 집계에서 빠졌다.

DB에서 과거 행이 지워진 것은 아니다. 이전 이력을 더 이상 집계에 쓰지 않게 된 것이다. 그래도 사용자가 요약 화면을 보고 “어디까지 진행됐지?”라고 물었을 때 지나온 과정이 빠진다는 점에서는 잘못된 기본값이었다.

도구 설명에는 정정할 때만 replace를 쓰라고 적어 놓고, 서버는 아무 말이 없으면 정정으로 처리하고 있었다. 설명과 기본 동작도 서로 맞지 않았다.

기본은 이어 쓰기, 정정은 명시하기

수정 커밋에서는 옵션을 생략하면 append로 처리하도록 바꿨다. 같은 순서로 결과를 기록했을 때 기술 면접과 최종 면접 도달이 각각 한 건씩 유지되는 회귀 테스트도 추가했다.

이제 평범한 진행 보고는 기존 이력을 이어 간다. 반대로 “아까 말한 면접 기록은 잘못됐고, 실제로는 서류에서 탈락했어”처럼 앞선 기록을 정정하려는 경우에는 replace를 명시한다.

다만 현재의 정정 기능은 특정 이벤트 하나만 고치는 편집기가 아니다. 이전 결과 이력 전체를 집계에서 제외하는 방식이다. 도구 설명에도 이 범위를 먼저 확인하도록 적었다. 일부 기록만 고치는 더 세밀한 기능은 아직 없다.

이 차이를 ChatGPT가 실제 대화에서 항상 잘 구분하는지는 별도로 확인해야 한다. 이번에 확인한 것은 서버의 기본 동작과 도구 설명, 그리고 합성 입력에 대한 처리다.

개인의 맥락을 기억하는 비서를 생각하면, 이 작은 옵션이 꽤 중요하게 느껴졌다. 사용자의 다음 말을 모두 앞선 말의 취소로 받아들이면 기억을 쌓기 어렵다. 반대로 명시적인 정정을 무시한 채 계속 덧붙이기만 해도 잘못된 기억이 남는다.

같은 말을 다시 했다고, 최근 기록이 되면 안 된다

리뷰에서는 오래된 저장 형식과 관련된 문제도 발견했다.

예전 기록에는 이번에 추가한 단계나 출처 필드가 없다. 그 기록에 똑같은 지원 상태를 다시 보내면, 내부에서 기본값이 채워지는 것까지 변경으로 판단했다. 사용자가 알려준 사실은 그대로인데 이벤트가 추가되고 최근 수정 시각도 바뀌었다.

현재 집계의 기간 필터는 실제 면접 날짜가 아니라 마지막 수정 시각을 기준으로 한다. 그러니 이 시각이 움직이면 기간별 집계에 포함되는 기록도 달라질 수 있다.

수정 후에는 이전 기록을 같은 기본값으로 해석한 뒤 비교한다. 실제로 달라진 내용이 없으면 저장하지 않는다. 테스트에서는 이벤트 수, 저장된 JSON, 수정 시각이 모두 그대로인지 확인했다.

이 역시 단순한 중복 제거보다 기록의 의미에 가까운 문제였다. 앱이 새 형식을 읽게 됐다는 것과 사용자가 새로운 소식을 알려줬다는 것은 달라야 했다.

이번에 확인한 범위

c2a862a의 임시 사본에서 기존 설치 의존성을 재사용해 검증했다. 테스트 157개(shared 7 + server 150), 정책 평가 28개, 타입 검사·린트·빌드가 모두 통과했다.

단계별 결과가 달라도 원래 판정은 유지되는지, 진행 이력이 보존되는지, 정정하면 이전 집계가 철회되는지, 같은 요청을 바로 반복해도 이벤트가 늘지 않는지 등을 합성 데이터로 확인했다. 단계가 알려지지 않은 탈락을 서류 탈락으로 추정하지 않는 것도 포함한다.

이 숫자는 추천 정확도가 아니다. 외부 모델 API는 호출하지 않았고, 실제 ChatGPT 호스트에서 도구 선택과 정정 확인이 어떻게 이어지는지도 아직 검증하지 않았다. 지금의 결론은 로컬·개인용 초안으로 다음 작업을 이어갈 수 있다는 정도다.

기억의 양보다, 기억을 바꾸는 규칙

처음에는 지원 결과를 더 자세히 저장하면 된다고 생각했다. 해보니 필드를 늘리는 것보다 먼저 정해야 할 규칙이 있었다.

무엇을 새 소식으로 받아들일지, 무엇을 이전 말의 정정으로 볼지, 같은 말을 다시 들었을 때는 아무것도 바꾸지 않을지.

앞으로 데이터가 많아지고 프롬프트가 정교해져도, 이 구분이 흐리면 사용자가 남긴 경험을 제대로 돌아보기 어려울 것 같다. 개인 비서처럼 작은 범위로 유지하더라도 마찬가지다.

아직 채용 시장을 분석하거나 개인의 경험에서 스스로 학습하는 앱은 아니다. 이번에는 그보다 앞선, 사용자가 알려준 사실을 어떻게 이어 쓰고 고칠지부터 정리했다.

기능 하나를 붙였는데, 결국 “무엇을 기억해야 하는가”에서 한 걸음 더 나아간 셈이다. 그 기억을 언제, 어떤 뜻으로 바꿔도 되는가.