Skip to content

[개인 노트 · 리뷰 불필요] 작업 인계 — 조용함. #625 에 내 파일 두 줄이 걸려 있다 (46회차) - #283

Draft
yoonjiseok wants to merge 1 commit into
mainfrom
notes/handoff-0902
Draft

yoonjiseok wants to merge 1 commit into
mainfrom
notes/handoff-0902

Conversation

@yoonjiseok

@yoonjiseok yoonjiseok commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

개인 작업 노트다. 리뷰·머지 대상이 아니다. 다른 랩탑/세션에서 이어가기 위한 인계용이고
파일 변경은 없다(빈 커밋). 다 끝나면 닫는다. #196 과 같은 형태.

9/15 — 내가 승인한 PR 에서 내 문장이 낡는 것을 오준서가 잡았다 (갱신 46회차)

main   29a1d71 · 초록 · ai-service 1138 · eval 93   (Python 3.11 · CI 와 같다)
배포   alpha = 최종 환경 (#464 ⓒ — prod 는 안 세운다)
머지   #610 #616 (남의 것 · 어제 밤~오늘)
열림   #613(강희진 승인만) · #623(draft · #624 뒤)
리뷰 큐 0      배정 이슈 7      09-15 12:40 조회 (`/pr` · 46회차는 조용함)
전제   제출 끝. 실데이터·실로직으로 간다 — #406 의 "이번 라운드" 는 만료

★★ 내 코드가 어디에 있나

이 PR(#283)에는 코드가 없다 — 빈 커밋 + 본문만(#196).

무엇 어디 상태
#617 draft 드러내기 · #619 「N 벌」 주석 main 머지됨
#613 F-EXT-002 인용 넓힘 origin/fix/F-EXT-002-evidence-covers-required-456 be3b7a4 5커밋
#623 Judgment.rubric_status origin/feat/F-SCR-001-judgment-rubric-status-609 1823ae1 1커밋 · draft
git fetch origin
git checkout -b fix/F-EXT-002-evidence-covers-required-456 origin/fix/F-EXT-002-evidence-covers-required-456
git checkout -b feat/F-SCR-001-judgment-rubric-status-609  origin/feat/F-SCR-001-judgment-rubric-status-609

CLAUDE.local.md 는 안 넘어간다(gitignore) · 작업 전 git fetch(#298·#338).


46회차 — 조용하다. 새로 온 것이 하나도 없다

조회는 돌았고 변화가 없는 것이다(못 돈 것이 아니다). main 도 내 PR 둘도 그대로이고,
#625 의 마지막 발언은 내 답이다. 45회차 내용이 그대로 유효하다.

새 리뷰 요청 0 · 내게 온 새 답 0 · main 29a1d71 (안 움직임)
#612  여전히 CLEAN · 전원 승인 · 아무도 안 누름     ← 이틀째

★★ #625내가 승인한 PR 이 내 문장을 낡게 만든다. 오준서가 잡았다

#619(내 것, 어제 06:27 머지)가 main 에 넣은 줄이다.

# test_measurement_invalid_route.py:108`MANUAL_PARSE_TYPE_MISMATCH`) 계약 enum  없지만, …

#625 가 그 코드를 계약 enum 에 넣는다(openapi.yaml:942). 머지되는 순간 거짓이 된다.
단정이 아니라 docstring 이라 안 빨개진다 — 그래서 더 나쁘다.

내가 그 PR 을 승인하면서 못 봤다. 더 나쁜 것은 같은 리뷰에서 "정확한 문면은 「대개는
다르고 겹치는 예외가 둘」"
이라고 적어 놓고 그 문장이 걸리는 내 파일을 안 본 것이다.

내가 보탠 것 — 낡는 것이 한 줄이 아니라 둘이다

:106routes.py 의 문장을 인용하는데 이 PR 이 그 문장을 지운다.

before  ❗여기 코드는 `ApiError.code` 가 아니다.
after   이 표는 … 대개 겹치지 않는다 / ❗이 코드만 예외다

→ 머지되면 없는 문장을 인용한다. #341(절 제목 인용이 #305 로 끊긴 것)과 같은 종류다.
대체 문면은 인용 대신 표 이름(_REFUSAL_RESPONSE)으로 가리키게 냈다 — 그쪽 문면이 또
바뀌어도 안 끊긴다.

❗고치는 자리는 그 PR 이다 — 내가 따로 내면 순서 창이 생긴다

내가 지금 고친다   → #625 머지 전에는 「enum 에도 있다」가 거짓
#625 가 같이 고친다 → enum 추가와 문면이 한 커밋      ← 맞다

#623#624 와 같은 모양이라 내 파일 편집에 동의한다고 적었다.

전수로 훑었고 한 곳 더 있는데 그건 안 낡는다

routes.py:130                          #625 가 이미 고쳤다
test_manual_source_propagates:112      ExtractionWarning 코드 얘기 → 그대로 참

❗훑을 때 백틱 때문에 한 번 빗나갔다ApiError.code 가 아니 로 찾으니 `ApiError.code` 가
가 안 잡혔다. "정규식 이스케이프 때문에 부분열 검사가 빗나간다" 를 또 밟았다.

#612 — 전원 승인·재타겟 완료인데 아무도 안 누르고 있다

정세현이 #610 을 머지하고 #612 base 를 main 으로 돌렸다(결정 9.1 대로 재타겟 먼저 →
브랜치 삭제라 자식이 안 닫혔다). 지금 가드 pass(전원 승인)인데 강희진 PR 이라 나도 정세현도
안 누른다.
그 위에 #614 가 대기 중이다.

#625 앞선 왕복 — 규약은 아직 안 올린다

내가 "그물을 만들면 자기 문면부터 걸어 본다" 를 규약 후보로 냈고, 강희진이 두 사례가 반대
방향
이라 한 문장이 반쪽만 막는다고 답했다.

#617  텍스트를 세는 그물 → 자기 설명문이 세어져    거짓 양성
#621  문면을 무는 그물   → 자기 설명문이 안 세어져  거짓 음성

공통 모양은 모집단이라고 답하고("그 모집단에 지금 내가 쓰는 파일이 들어가는지"),
지금 안 올리는 데 동의했다. 이건 #533 ⓒ 의 "그물은 모집단이 맞아야 한다" 재발이라
셋째 사례가 나와야 붙일지 세울지 정해진다.

지금 열린 PR

#628 #625 #624   내가 승인 · 머지 대기 (#625 는 오준서 변경요청 하나 · 내 파일)
#623  ★ 내 것 — draft · #624 뒤
#613  ★ 내 것 — 강희진 승인만
#612  전원 승인 · 아무도 안 누름 → 그 위 #614 대기
#627 #626 #629 #622 #602  남의 것

다음에 할 것

# 무엇 상태
1 #625 가 내 파일 두 줄을 같이 고치면 재확인 → 승인 유지 대기
2 #624 머지되면 #623 main 합쳐 다시 재고 draft 해제 대기 · 내가 이어받는다
3 #628 머지되면 두 대조가 서로 가리키는 한 줄 대기 · 내가 이어받는다
4 #613 강희진 승인 → 머지 대기
5 #589 ⓐ · #630 심사 근거 · #491 투영 — 전부 답 대기 대기
6 결정 10.64 재측정0.7 이 gemini 관측값이다 나 · 착수 가능
7 #615 재생성(정세현) · #377 움직이면 내가 신호 남 · 내가 신호

이 회차에서 굳은 것

  • 내가 쓴 문장이 남의 PR 에서 낡는다. 승인하기 전에 그 변경이 내 파일의 어떤 주장을
    거짓으로 만드는지
    본다. 이번엔 같은 리뷰에서 옳은 문면을 적어 놓고 내 파일에 적용을
    안 했다 — 말과 자리가 따로 놀았다.
  • 문장을 인용하면 그 문장이 바뀔 때 끊긴다. 인용 대신 표·함수 이름으로 가리킨다
    (#341 이 절 제목에서 밟은 자리).
  • 백틱이 든 문면은 부분열 검색이 빗나간다. `X` 가X 가 로 안 잡힌다.
  • 규약을 이르게 굳히면 다음 사람이 그 문장만 지킨다. 반대 방향 사례 둘로는 못 세운다.
  • 남의 PR 은 전원 승인·초록이어도 안 누른다 — 알리는 것까지가 내 몫(#612).

로컬 상태

브랜치   main (29a1d71) · fix/F-EXT-002-…-456 (#613) · feat/F-SCR-001-judgment-rubric-status-609 (#623)
미커밋   없다 (CLAUDE.local.md 는 gitignore)
테스트   ai-service 1138 · eval 93 (main) · Python 3.11.16 · venv 는 `.venv`
         ❗검증은 러너와 같은 명령으로:
         pytest tests/ -q --junitxml=/tmp/ai.xml && python3 .github/scripts/no_skip.py /tmp/ai.xml x
server   ./gradlew test -Porg.gradle.java.installations.paths=/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
         ❗이 머신에서는 `--no-daemon` · 입력 등재 검증은 한 번 돌린 뒤 변조
         남의 브랜치는 `git worktree add --detach` · 끝나면 `worktree remove --force`
감시     ❗배경 감시가 세 번 다 메모리로 죽었다. 안 건다 — 필요할 때 조회한다
명령     `/pr` (개인 · `~/.claude/commands/pr.md`) — 이 노트를 갱신한다. `patrol/scan.sh` 를 부른다
         ❗그것도 랩탑 간에 안 넘어간다. 옮기려면 `.claude/commands/` 로 옮겨 PR
추적     #609 — ① 앞 절반 머지(#617) · 뒤 절반 #623(draft) · 템플릿 후보는 데모 뒤

CLAUDE.local.mdgit 에 안 올라간다 — 인계 정본은 이 PR 이다.

파일 변경 없는 빈 커밋이다. 다른 세션·랩탑에서 이어가기 위한 인계용이고
내용은 PR 본문에 있다. #196 과 같은 형태.
@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/2 오후 — 리뷰 사이클 기록

본문은 상태 스냅샷이라 매번 갈아 썼는데, 오늘 값이 있었던 건 대부분 리뷰에서 나왔고
그건 스냅샷에 안 남는다.
그래서 여기 붙인다.

★ 오준서 정체가 풀렸다 (08:57)

#271  재설명·재검증 화면      머지 ✅
#272  선행지표 뷰            머지 ✅
#273  고령자 모드 AAA         머지 ✅

#271 이 들어갔다. 어제 15:29 · 오늘 아침 두 번 재촉한 것이고, 이제 내 재설명이
전체 경로로 처음 돈다 — 리허설이 첫 실행이 되는 것을 면했다. 그게 재촉의 이유였다.

내가 오늘 한 것

낸 것    PR #298 (#284 (c))  ·  PR #286 (머지)
         이슈 #284 · #290 · #294
리뷰     승인 6건  #289 #291 #292 #293 #296 #297
         코멘트 3건 #288 #299 #300  ← 셋 다 아직 열려 있다

❗리뷰에서 잡은 것 — 여섯. 대부분 변이를 걸어서 나왔다

읽어서 찾은 건 하나뿐이다. 나머지는 되돌려 보고 테스트가 안 깨지는 것을 본 것이다.

PR 무엇이 안 잡혔나 결과
#291 unmeasuredItemCount()return 0 이 전건 초록 강희진이 머지 전에 테스트 2건 넣음
#291 previewGate 인자 제거도 초록 같이 들어감 (독립 테스트로)
#293 넓은 catchisObject()·path() 변이를 삼킨다 catch 좁히고 죽은 가드까지 지움
#297 rulesVersion 을 상수로 박아도 잡히나 declaredVersion() 으로 이미 잠겨 있었다
#299 rulesVersion 0 생략이 안 잡힌다 열려 있다
#300 build.gradle 새 줄이 체인을 끊었다 열려 있다

#300 은 변이가 아니라 diff 를 읽다 나왔다 — inputs.file('../CLAUDE.md') 다음 줄에
새 등록이 끼어서 withPropertyName('claudeMd')spec 파일에 붙었다.
up-to-date 는 안 깨져서 초록 밑에 있다.

오늘 배운 것 — 셋

1. 결정로그를 먼저 읽는다

#286#282--delete-branch 로 죽였다. 브랜치를 옛 head 로 되살려 reopen →
재타겟 → 다시 삭제로 복구했다. 그게 결정 9.1 에 이미 있었다(#81·#103 에서 두 번).

그리고 정세현이 #299 본문에 그 경고를 미리 써 뒀다 — 나는 하루 전에 밟았고 그쪽은
같은 함정을 문서에서 읽고 피했다. CLAUDE.md 가 "자기 영역을 건드리기 전에 해당 절을
먼저 본다"
를 적어 둔 이유가 이것이다.

2. 같은 규약을 적은 필드가 둘이면 그물도 둘이어야 한다

#299unmeasured·rulesVersion같은 규약("0 이어도 생략하지 않는다")으로
말하는데 단정은 앞의 것만 있었다. 그리고 뒤의 것이 더 나쁘다rulesVersion: 0
"파일을 안 지나온 룰" 이라는 뜻을 갖는 값이라, 생략되면 "이 필드 생기기 전 기록"
같아진다.

문면이 둘을 말하면 변이도 둘을 걸어 본다.

3. import 가 fixture 뒤에 돌면 caplog 이 통째로 빈다

#298 을 쓰다 걸렸다. app.main 을 테스트 함수 안에서 임포트하니 configure_logging()
이 conftest 뒤에 돌아 propagate=False 가 늦게 걸렸다.

stderr   WARNING app.main  F-DET-001 강제 통로 없음: …   ← 찍힌다
caplog   set()                                          ← 비었다

로그는 나오는데 캡처만 안 되니 테스트가 거짓으로 실패한다. 모듈 수준 임포트로 고쳤다.

팀이 내 지적을 넘어선 자리 둘

기록으로 남길 값이 있다.

#293 — 내가 "catch 를 좁혀라" 로만 적었는데, 그 결과로 isObject()
불필요해지는 것
까지 정리했다(path() 가 이미 MissingNode 를 낸다). 내 변이 A(가드
제거)가 통과하는 것은 봤지만 인지는 못 갔던 지점이다.

#297 — 내가 #294"계산이 안 잠긴다" 까지 봤는데 강희진이 계산 · 싣기 ·
담기
를 갈랐고, 정세현이 내기까지 더했다.

계산 틀림    unmeasuredItemCount() → 0     신호가 안 바뀐다
싣기 빠짐    GateResult 에 필드 없음        밖에서 못 잰다
담기 빠짐    appendGate 가 안 남긴다        감사 기록만 빈다          ← 내가 못 봤다
내기 빠짐    ReportService 가 안 낸다       스트림을 직접 열어야 한다   ← 내가 못 봤다

넷이 다 다른 실패다.

지금 열린 것

#298  내 PR — 승인 0건
#299  rulesVersion 단정          내가 요청 · 대기
#300  build.gradle 두 줄         내가 요청 · 대기
#288  3.27 철회된 근거 정정        내가 요청 · 대기 (10.62 만 고쳐졌다)
#297  승인 완료 — 머지 시 `--delete-branch` 빼야 한다 (#299 가 스택)
#293 #289  내 승인 완료 · 오준서
#290 #284 #234 · 배포 SSM 키

내가 셋을 막고 있고 내 것 하나가 막혀 있다. 리허설이 내일이니 #299·#300
지적이 작아서(단정 한 줄 · 위치 두 줄) 오늘 안에 닫힐 것 같고, #288 은 정세현이 지금
다섯 개를 동시에 굴리고 있어서 밀리는 것으로 보인다.

#280·#294 를 닫는 조건

#280  1) #282 ✅  2) #291 ✅  3) #286 ✅ + #293 대기
#294  1)2) c4ffbd0 ✅  3)4) #293 ✅  GateResult #297·#299 대기

#293 하나가 둘을 다 막고 있다(오준서 승인 대기). 들어오면 내가 둘 다 닫는다.

yoonjiseok pushed a commit that referenced this pull request Sep 2, 2026
`pr-review-guard.yml` · `pr-reviewer-label.yml` · `pr-author-assignee.yml`
→ `pr-review.yml` 한 파일 · 한 잡.

## 왜 — 분보다 결함 쪽이 크다

① 셋 다 실측 4초짜리인데 잡 단위 올림 과금이라 각각 1분씩 나갔다.
   실측 12.9분에 **과금 119분**. 합치면 약 40분이다.

② ❗**같은 판정을 두 파일이 각자 구현하면 어긋난다.** CLAUDE.md 가 두 번
   경고하고 실제로 네 번 났다(#90·#91 · #135/#140 · #180). 다섯 번째가
   이미 와 있었다 — 가드가 `reviewRequests` 로 판정하면서 그 값이 바뀌는
   `review_requested`·`review_request_removed` 를 **안 들었다.** 초록인 PR 에
   리뷰어를 새로 붙이면 라벨만 바뀌고 **가드는 낡은 초록으로 남았다.**

이제 「판정」 스텝이 사실을 한 번만 만들고, 커밋 상태와 라벨이 그 하나를
각자 표현한다. **두 표현이 갈릴 자리가 없다.**

## 지키기로 한 것 둘 (#276 코멘트) — 둘 다 지켰다

1. **트리거는 라벨 쪽 8종 합집합.** 가드 쪽 4종으로 좁히면 ②가 돌아오고
   라벨이 눌어붙는다(#135/#140).
2. **`#180` 의 스텝 분리 유지.** 판정은 `continue-on-error`, 커밋 상태는
   `always()` 로 **라벨보다 먼저** 쓴다 — 라벨이 죽어도 줄은 이미 갱신돼 있다.

## 라벨 쪽에 하나 보탰다 — 판정이 죽으면 라벨을 안 건드린다

라벨에는 가드의 `error` 같은 세 번째 값이 없다. 판정이 중간에 죽은 채로
목표가 비어 있으면 **라벨을 다 떼게 되고 그건 "전원 승인했다" 로 읽힌다** —
정확히 반대 뜻이다. 판정 끝에 찍는 표식(`verdict_ok`)이 없으면 물러난다.

## 실측 — 열린 PR 8건에 판정 로직을 그대로 돌려 현재 라벨과 대조했다

    PR    상태                         라벨(계산)              라벨(실제)      일치
    #305  승인 0건                     리뷰어 미배정           〃              ✅
    #300  승인 0건                     리뷰대기×2 · 리뷰중×1    〃              ✅
    #299  미승인 yoonjiseok             리뷰중: 윤지석          〃              ✅
    #298  변경요청 hd0rable             리뷰중: 강희진·정세현    〃              ✅
    #287  전원 승인                     (없음)                 〃              ✅
    #303  전원 승인                     (없음)                 〃              ✅
    #283  초안                          (없음)                 〃              ✅
    #270  머지됨                        (없음) · 상태 안 씀     〃              ✅

`bash -n` 으로 네 스텝의 셸 블록을 전부 문법 검사했고 YAML 파싱도 확인했다.

## 곁들여

`소유자 승인 여부` 커밋 상태 context 는 **그대로 뒀다** — 바꾸면 기존 PR 에
줄이 하나 더 생긴다. 팀 리뷰 요청은 판정할 수 없어 경고로 드러낸다(이 레포는
CODEOWNERS 가 전부 개인 로그인이고 팀 요청 이력 0건이라 지금은 안 걸린다).

CLAUDE.md · infra/README.md 의 옛 파일명 참조를 같이 고쳤다.


Claude-Session: https://claude.ai/code/session_01Korhp5asdqxA4bJ5h8jFgw

Co-authored-by: 오준서 <26485905+junseo2323@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/3 오전 — 리허설 당일. 밤새 들어온 것과 내가 본 것

★ 밤새 머지 (9/2 오후~밤)

#271 #272 #273   오준서 정체가 풀렸다 — 내 재설명이 화면에 붙었다
#293             #280 ③ 마지막 조각
#297 #299        GateResult 두 필드 + 기록·리포트가 담는다
#289 #287 #303 #306

#280·#294 를 오늘 아침 닫았다. 조건이 다 찼다.

❗다른 랩탑 세션이 내 PR 을 이미 고쳤다 — 중복 작업을 했다

#298 에 강희진 CHANGES_REQUESTED 가 어제 07:44 에 왔는데 이쪽 세션이 못 보고 있었다.
오늘 아침 읽고 고쳐서 커밋했더니 push 가 거부됐다 — 원격에 이미 커밋 둘이 있었다.

16e5a37 09-02 21:52  기동 경로를 실제로 태우고, 만료 조건을 기계가 보게 한다 (#298 리뷰 C·B·2)
75b60a8 09-02 21:44  의도된 정정을 사각으로 세지 않는다 (#298 리뷰)
b574e01 09-02 16:14  (원본)

그리고 원격이 내 접근보다 한 칸 더 갔다.

내가 한 것    _INTENTIONALLY_UNLINKED = {"VAR-PARTIAL-DEPOSIT-INSURANCE"}
원격          _UNLINKED_UNTIL = {항목: (근거, 빼는 조건)}

"의도적으로 링크 없음"영구히 그렇다고 읽힌다. 지금 상태는 "링크가 없기로
정했다"
가 아니라 "그 유형이 아직 없다" 다(결정 10.24). 앞엣것으로 적으면
지우는 사건이 안 온다(10.67).

내 로컬 커밋을 버리고 원격으로 리셋했다. git push 거부가 아니었으면 두 벌이 됐다.

교훈 — 다른 랩탑에서 세션이 돌고 있으면 작업 전에 git fetch 로 원격 브랜치를 먼저 본다.
#283 이 인계 노트인데 이쪽이 그걸 안 읽고 시작했다.

오늘 본 것 — 리뷰 넷 + 회신 둘

#284 회신   죽은 링크 지적 → products 교차 검사가 내 몫으로 새로 생겼다
#288 승인   내 정정 둘 반영 확인 · 2.14 는 정세현이 맞다(내 #268 코멘트가 근거)
#305 승인   원본 v1.1 이 들어왔다 + ❗넷째 갈림을 내가 찾았다
#304 승인   내가 #299 에 적은 사각을 닫았다 · 스캔 뿌리 변이를 내가 따로 걸었다
#308 신규   P6 인용에 절 번호 (내가 냄)

❗원본이 들어오자 넷이 갈렸다 — 하나는 성격이 다르다

①  P2 범위      우리 불변식이 게이트를 넣는데 조항엔 없다        요약 문제
②  P5 U4 예외   0.2절과 3절이 원본 안에서 갈린다               요약 문제
③  P6 두 자리   재설명은 0.2절 · 추출은 1절 F-EXT-002          요약 문제 → #308 로 고침
④  U2 보수 확정  ❗우리 구현이 조항과 다르다                    이유를 대야 한다

④가 심사에서 제일 위험하다. 명세 3절이 "실패 시 U2(황색)로 보수 확정" 을 요구하는데
우리는 502 다. 명세 안에서 P4 와 충돌하고 우리가 P4 를 골랐다(10.10). 답은 있는데 조항
옆에 없고
, 10.10 문면이 "경로가 없다" 로 시작해서 미구현처럼 읽힌다.
@gitIt-sehyeon 에게 한 줄 요청했다.

내가 근거를 한 절 잘못 알고 있었다

메모에 "confidence < 0.7 → 황색 강등, 단 U4 는 예외(P5)" 로 적고 그걸 P5 조항으로
알았다. 실제 P5 는 "무조건 황색 강등" 이고 U4 예외는 3절 F-SCR-001 이다.
#290 을 연 이유가 "P5 를 근거로 들려면 원본이 필요하다" 였는데, 들어오니 내가 틀렸다.

심사에서 P5 를 물으면 0.2절과 3절을 같이 인용해야 한다. 앞만 들면 우리가 위반으로 보인다.

오늘 배운 것

  • 다른 랩탑 세션과 겹친다. 작업 전 git fetch + 원격 브랜치 확인. #283 을 먼저 읽는다.
  • gh pr create 뒤 번호를 목록 첫 항목으로 잡지 않는다. 목록이 번호순이 아니라 리뷰어를
    #308 대신 #298 에 붙였다. 오준서가 리뷰어로 붙어서 가드가 그 승인까지 요구하게 됐고
    바로 뗐다. 생성 결과 URL 에서 번호를 읽는다.
  • 문면을 읽는 대조는 자기 설명문에 걸린다. #308 테스트가 "1절이다(0.2절이 아니다)"
    0.2절 인용으로 잡았다. 대비를 설명하는 줄은 인용이 아니다.
  • 변이가 안 잡히면 "그물을 더 걸어라" 가 아니라 "왜 안 잡히나" 를 먼저 본다.
    답이 "삼켜서" 일 수도 "애초에 아무 일도 안 해서" 일 수도 있고 고칠 곳이 반대다(fix(F-SCR-001): 서버가 ai-service 의 detail.code 를 읽는다 + 문면을 넓힌다 (#280 ③) #293).

지금 열린 것

#308  P6 절 번호            내 PR · 방금 냄
#298  #284 (c)             ❗강희진 CHANGES_REQUESTED 미해소 — 원격은 이미 고쳐졌다
#305  원본 v1.1            내 승인 · 정세현 대기 → 머지되면 #290 닫는다
#304 #300 #301             내 승인 완료
#307 #302                  아직 안 봄 (요청 없음)

내 차례는 없다. #298 이 강희진 재리뷰만 기다린다 — 어제 13:29 에 재리뷰 요청이
나갔다(CHANGES_REQUESTED 는 리뷰어가 다시 제출해야 풀린다).

다음에 할 것

1  #298 재리뷰 오면 머지
2  #305 머지되면 #290 닫기 (+ 넷째 갈림 기록은 이미 남겼다)
3  products 교차 검사      #284 에서 새로 생겼다 · 던지는 쪽이 맞다
4  #304 머지되면 #294 에 ⑥ 후속 한 줄
5  #284 (a) 유형 둘 · #234 ②   3주차

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/3 오전 (계속) — 리허설 전. 내 PR 셋이 전부 리뷰 대기

★ 정정 — 어제 인계 노트가 틀렸다

앞 코멘트에서 이슈 #311~#327리허설 결과로 읽었다. 아니다 — 정세현이
리허설 전에 화면을 훑어서 낸 것이고 리허설은 아직 안 했다.

CLAUDE.local.md 머리에 그 경고를 박았다. 교훈: 날짜·사건을 추론으로 잇지 않는다.
시각은 조회하면 나온다.

열린 내 PR 셋

#341  P5 인용에 절 번호               승인 0건 · 방금
#338  502 진단 키 갈래                ❗오준서 변경요청 — 세 번째 수정을 냈다
#308  P6 인용에 절 번호               정세현 재리뷰 대기 (구멍 둘 고침)

#338 — 내가 고치려던 결함을 한 층 아래에서 내가 다시 만들었다

diagnose_502"로그에서 llm_error(...) 를 찾아라" 로 안내를 썼다. 오준서가 잡았다.

app/llm_client.py   grep -c "log\."  →  0      아무것도 안 찍는다
llm_error(...)      question_gen 에만 있다      질문 폴백 경로다
질문 폴백            502 를 안 낸다             조용히 템플릿으로 내려간다

이 PR 이 "LlmNotConfigured 만 가리키면 사람이 그 자리에서 멈춘다" 고 적은 것과
정확히 같은 모양이다. 한 층 아래에 남아 있다.

고치다 한 층이 더 나왔다. 지적대로 "응답 본문의 detail 을 봐라" 로 바꿨는데 그것도
틀렸다 — GlobalExceptionHandler 가 고정 문면("채점 서비스에 연결할 수 없습니다")만 내고
ai-service 원문은 AiServiceException 에 갇혀 서버 로그까지만 간다.

세 번째로 ai-service 를 직접 찌르는 프로브를 넣고 실측했다.

502 · "LLM 호출 실패: Error code: 401 - Incorrect API key provided: sk-proj-…"
503 · "LLM_API_KEY 미설정"

세 번 다 같은 실수였다 — 문면을 쓸 때 그 자리를 안 열어 봤다. 안내 문면도 코드처럼
실행해 보고 써야 한다는 게 이 왕복의 결론이다.

#290 이 닫혔다 — 오준서가 #305 머지 직후

원본 v1.1 이 main 에 있다(23,955 바이트 · 0.2절 여섯 줄 축자).

요청한 것보다 나온 게 많았다.

①  P2 범위      우리 불변식이 게이트를 넣는데 조항엔 없다      #305
②  P5 U4 예외   0.2절과 3절이 원본 안에서 갈린다             #296 · #341
③  P6 두 자리   재설명 0.2절 · 추출 1절 F-EXT-002           #308
④  U2 보수 확정  ❗우리 구현이 조항과 다르다                  #331 이 10.10 에 실었다

심사 인용 지침 — 셋 다 두 절을 같이 든다. 한쪽만 들면 우리 구현이 조항 위반으로 보인다.

P4   0.2절("근거 없는 판정은 시스템 오류")  +  3절("실패 시 U2 로 보수 확정")
P5   0.2절("무조건 강등")                   +  3절("단, U4 는 예외")
P6   0.2절("재설명 생성 시")                +  1절 F-EXT-002("원문 스팬 동반")

내가 P5 근거를 한 절 잘못 알고 있었다. 메모와 코드 주석이 0.2절과 3절을 한 조항으로
뭉쳐서
적고 있었다. 원본이 없던 동안에는 확인할 방법이 아예 없었다 — 이 이슈가 왜
필요했는지가 그것으로 증명됐다.

남의 것 리뷰 — 오늘 여섯

#302  ❗MEASUREMENT_INVALID 을 배관 진단으로 보낸다 · 키 갈래 하나 빠짐 → #338 로 냈다
#304  내가 #299 에 적은 사각을 닫았다 · 스캔 뿌리 변이를 내가 따로 걸었다
#305  원본 전사 · 넷째 갈림을 내가 찾았다
#307  경로 집합이 같으면 라벨 어긋남은 안 잡힌다 (격리에 세 번 걸었다)
#309  검증 셋이 전부 LLM 을 안 탄다 — SSM 키가 어느 프로바이더인지 미확인
#339  폴백률을 "0 이 아니라 모른다" 로 적은 판단이 내 지적보다 안전하다
#331  10.10 정정 — 내가 요청한 것보다 완결적이다

❗리허설 전 마지막 미확인 — SSM 키

#309 가 SSM 넷을 "그대로 이관(길이 대조 완료)" 했는데 확인 목록이 ai-service 를
한 번도 안 지나간다
(/ · /api/products · /api/dashboard/heatmap · healthy).

즉 alpha 에서 채점이 되는지는 아직 아무도 확인한 적이 없다. #266 이 어제 정책을
gpt-5-mini 로 옮겼으니 옛 Gemini 키가 남아 있으면 키는 있는데 401 이다.

확인 수단은 #302 가 머지돼서 main 에 있다(scripts/walk_demo_session.sh). 누가 한 번
돌리면 그 자리에서 답이 난다.
#338 이 들어가면 막혔을 때 어디를 볼지도 안내에 있다.

다음에 할 것

# 무엇 상태
1 #341·#338·#308 머지 전부 리뷰 대기
2 #308 머지 후 P5 절 표기 가드를 그 파일에 얹는다 같은 파일이라 순서가 있다
3 #183 후속 — 짧은 조각 오탐 내 코드 · #324 로 시점이 가까워졌다
4 #284 (a) 루브릭 쪽 근거 확정됨 · 라이브러리는 정세현
5 F-DET-001 3단계(임베딩) · #234 3주차

내 담당 열린 이슈는 #284 하나고, 오늘 난 17건 중 내 담당은 0건이다.

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/3 05:30 — 리허설 전. 내 PR 셋 대기 · 라벨링이 움직이기 시작했다

내 PR 셋 — 전부 리뷰 대기

#341  P5 인용에 절 번호           승인 0건 (정세현·오준서 요청)
#338  502 진단 키 갈래            ❗오준서 변경요청 · 세 번째 수정 냈다
#308  P6 인용에 절 번호 + 대조     정세현 재요청했다 (02:23 수정 후 3시간 무응답)

#339 는 내가 막고 있었다 — 앞 코멘트에 "막지 않는다" 고 적었는데 COMMENTED
가드에 미승인으로 잡힌다. 승인해서 가드가 열렸다.

교훈: "막지 않는다" 는 말은 가드가 안 읽는다. 막지 않을 거면 APPROVE 를 낸다.

❗F-CMN-003 라벨링이 시작됐다 — 내가 배제된 구간이다

#324 마감이 9/7 10:00 이고 "사람 라벨만 없다" 로 서 있었는데 셋이 움직였다.

#343 [정세현]  AI 참조 라벨 40건 — 사람이 볼 양을 4건으로 줄인다
#345 [강희진]  라벨링 블라인드 작업지 — 닻을 손닿는 데서 뗀다
#339 [정세현]  실세션 지표 (내가 승인했다)

#343 의 판단이 정확하다.

eval/data/labels/ 에 두면 run_eval.py라벨러로 센다. "평가자 간 일치도 =
모델 점수의 상한"
"LLM 두 번 돌리면 얼마나 일관되냐" 가 되고, 그걸 "사람 라벨
기준 QWK"
로 제출물에 적으면 숫자가 틀린 게 아니라 표기가 거짓이 된다.

그리고 강희진이 자기 자격 상실을 스스로 적었다.

#343 리뷰에 적었듯 나는 쟁점 4건의 라벨러가 될 수 없다 — 그 PR 본문이 참조 등급을
표로 보여주고 나는 읽었다.

내 배제와 같은 논리다. 나는 프롬프트 당사자라 처음부터 라벨러가 아니고, 강희진은
등급을 읽어서 자격을 잃었다. 남는 라벨러가 누구인지가 #324 에서 정해진다 —
내가 관여할 자리가 아니고, 관여하면 그 독립성이 깨진다.

내가 이 구간에 낸 것은 파이프라인과 모델 예측 40건뿐이다(#279). 그게 맞는 경계다.

❗리허설 전 마지막 미확인 — 그대로다

#309  SSM 넷 "그대로 이관(길이 대조 완료)"
      확인 목록(/ · /api/products · /api/dashboard/heatmap · healthy)이
      ai-service 를 한 번도 안 지나간다
→ alpha 에서 채점이 되는지 아직 아무도 확인한 적이 없다

#266 이 어제 gpt-5-mini 로 옮겼으니 옛 Gemini 키가 남아 있으면 키는 있는데 401 이다.
확인 수단(scripts/walk_demo_session.sh)은 #302main 에 있다. 누가 한 번 돌리면
그 자리에서 답이 난다.

#338 이 들어가면 막혔을 때 어디를 볼지도 안내에 있다 — 그 PR 이 세 번 고쳐진 이유가
안내가 없는 자리를 가리키고 있었기 때문이다(로그 → 서버 응답 → ai-service 직접 프로브).

다음에 할 것

# 무엇 상태
1 #308 머지 → P5 절 표기 가드를 그 파일에 얹는다 같은 파일이라 순서가 있다
2 #341·#338 머지 리뷰 대기
3 #183 후속 — 짧은 조각 오탐 내 코드 · #324 로 시점이 가까워졌다
4 #284 (a) 루브릭 쪽 근거 확정됨 · 라이브러리는 정세현
5 F-DET-001 3단계(임베딩) · #234 3주차

내 담당 열린 이슈는 #284 하나. 오늘 난 17건 + 새 PR 셋 중 내 담당은 0건이다.

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/3 오후 — #338 2차 반영 · #341 리뷰 반영 · P5 가드 완성(PR 미개설)

#308 머지됨 (860faaa, main 438 passed)

정세현이 승인에서 자기가 통과한다고 잰 실험 둘을 재측정해 둘 다 빨강임을 확인했다.

#338 — 오준서 2차 반영, 재리뷰 대기

내 프로브가 alpha 에서 못 돌았다. 이 PR 의 네 번째 층이고 네 번 다 같은 실수였다 —
문면을 쓸 때 그 자리를 안 열어 봤다.

1차  "로그에서 llm_error 를 찾아라"     → 그 로거는 아무것도 안 찍는다
2차  "서버 응답 detail 을 봐라"          → GlobalExceptionHandler 가 고정 문면으로 덮는다
3차  "ai-service 를 직접 찔러라"         → alpha 는 ports 가 없고 토큰이 필수다
4차  컨테이너 안에서 · 토큰은 자기 환경변수에서   ← 반영

실측: ports:web 하나뿐 · SPHINX_REQUIRE_INTERNAL_AUTH: "1" · 헤더 없음 → 401,
있음 → 200. 표에 401 갈래를 얹었다(안 적으면 그것도 「키 문제」로 읽힌다 — 두 401 이
뜻이 완전히 다른데 숫자가 같다).

#341 — 정세현 지적 반영, 오준서 대기

인용한 절 제목이 실재하지 않았다. #305 가 21행을 「설계 원칙 (P1~P6) — 0.2절 전사」 로
두고 갈린 것 셋을 49행 하위 절로 뺐는데, 내 인용은 그 둘을 뭉친 옛 모양이었다.
이 PR 이 고치는 것과 같은 결함의 다른 층이다 — 근거처럼 생겼는데 그 자리에 그게 없다.

❗P5 절 표기 가드 — 완성했으나 PR 은 아직 안 냈다

브랜치 test/clause-reference-p5 (푸시됨, 288ab86). #341 이 머지된 뒤에 리베이스해서
낸다
— 지금 내면 #341 커밋이 diff 에 섞여 리뷰가 흐려진다.

P5 용 대조를 베끼지 않고 원칙을 표로 돌렸다(test_p6_clause_reference.py
test_clause_reference.py). 두 그물이 갈리면 어느 쪽이 참인지 알 수 없다.

_CLAUSE_TAGS   P5 → (0.2절, 3절, F-SCR-001)     뒤가 앞에 예외를 둔다
               P6 → (0.2절, 1절, F-EXT-002)     앞이 뒤보다 좁다

표를 합치면 안 된다 — P5 인용에 「1절」만 적어도 통과한다(그 원칙에 없는 절이다).

그리고 (다) 제목 실재 검사를 넣었다. 정세현이 #341 에서 잡은 그 결함은 절 번호
대조로는 안 잡힌다 — 번호는 맞고 제목이 틀렸다.
(가)~(나)가 통과하는 동안 살아 있었다.

변이 여섯 다 잡힌다(ⓐ 절 뗌 · ⓑ 남의 절 · ⓒ 3절 오인용 · ⓓ 낡은 제목 · ⓔ 명세 제목 변경 ·
ⓕ 기존 P6 그물). 복원 시 444 passed.

지금 막힌 것 — 둘 다 오준서

#338  guard failure  변경 요청 미해소 (junseo2323)   ← 반영 푸시 + 답글 완료
#341  guard failure  미승인 리뷰어 (junseo2323)      ← gitIt-sehyeon APPROVED

#341 이 들어가면 #290 을 닫는다(마지막 조각이었다). 그 다음 가드 PR.

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/3 (리허설 당일) — 오늘 한 것 전수

시각은 KST. 조회로 모았다(기억으로 적지 않는다 — 오늘 날짜·사건을 추론으로 이어서 한 번 틀렸다).

시간순

09:44  #280 닫음        게이트 분모 · seed · 로그 갈래 셋 다 해소
09:45  #294 닫음        네 조각 + GateResult 까지
09:49  #288 승인        (강희진) 3.27 정정
09:53  #305 승인        원본 명세가 레포에 들어왔다 ★ 오늘의 분기점
10:00  #308 냄          P6 인용에 절 번호
10:03  #304 승인        #299 rulesVersion 0 생략을 닫았다
10:12  #310 냄          products 교차 검사 (도달 불가 오해 링크)
10:36  #302 코멘트      MEASUREMENT_INVALID 을 배관 진단으로 보내는 문제 ②
10:44  #298 머지        #284 (c) 강제 범위 노출
10:49  #309 코멘트      ❗채점이 alpha 에서 되는지 아무도 안 쟀다
10:56  #307 코멘트      경로 집합이 같으면 라벨 어긋남은 안 잡힌다
10:59  #331 승인        U2 보수 확정을 10.10 에
11:01  #310 머지
11:23  #290 닫음        P4·P5·P6 전사 (원본이 들어왔다)
11:38  #338 냄          502 진단에 「키가 있는데 틀렸다」 갈래
11:53  #339 코멘트  →  14:17 승인 (내 COMMENTED 가 3시간 막고 있었다)
13:21  #341 냄          P5 인용에 절 번호
15:09  #308 머지        860faaa
15:11  #338 2차 반영    컨테이너 안 프로브 + 401 갈래
15:23  #349 냄          키가 프로바이더 교체를 안 따라왔으면 기동 때 말한다
15:35  #341 리뷰 반영   인용한 절 제목이 실재하지 않았다
18:12  #341 머지        52e8aee
18:15  #351 냄          절 표기 가드 (원칙 표 + 제목 실재)

머지된 내 것 — 넷

#298  #284 (c) 강제 범위 노출          10:44
#310  products 교차 검사               11:01
#308  P6 인용에 절 번호 (860faaa)      15:09
#341  P5 인용에 절 번호 (52e8aee)      18:12

열린 내 것 — 셋

#338  502 진단 갈래          ❗변경요청 미해소 (2차 반영 완료 · 오준서 재리뷰 대기)
#349  키·프로바이더 불일치 경고   정세현 대기
#351  절 표기 가드           정세현·오준서 리뷰 요청

닫은 것 — 셋

#280(게이트 분모 · seed · 로그 갈래) · #294 · #290(전사 + 갈린 것 넷)

남의 것 리뷰 — 아홉

승인      #288  #305  #304  #331  #339
코멘트    #302  #309  #307  (#339 는 코멘트 → 승인)

오늘 실제로 배운 것

★ 1. 원본 명세가 들어오자 내 근거가 한 절 틀린 것이 나왔다

#305 가 오늘의 분기점이다. 그 전에는 확인할 방법이 아예 없었다.

내 메모      "confidence < 0.7 → 황색 강등, 단 U4 는 예외(P5)"    ← 둘을 뭉쳤다
0.2절 P5     "신뢰도가 임계값 미만이면 **무조건** 황색 강등"
3절 F-SCR-001 "단, U4 판정은 신뢰도가 낮아도 강등하지 않는다"      ← U4 예외는 여기다

심사에서 P5 를 물으면 두 절을 같이 인용한다. 0.2절만 들면 "무조건 강등" 이라고
적힌 조항을 근거로 대면서 U4 를 강등하지 않는 구현을 보이는 셈이라 우리가 위반으로
보인다.
갈린 것 넷 중 ④(U2 보수 확정)는 #331 이 10.10 에 실었다.

★ 2. 안내 문면도 그 자리를 열어 보고 써야 한다 — #338 이 네 번 틀렸다

1차  "로그에서 llm_error 를 찾아라"     → 그 로거는 아무것도 안 찍는다 (grep -c "log\." → 0)
2차  "서버 응답 detail 을 봐라"          → GlobalExceptionHandler 가 고정 문면으로 덮는다
3차  "ai-service 를 직접 찔러라"         → alpha 는 ports 가 없고 토큰이 필수다
4차  컨테이너 안에서 · 토큰은 자기 환경변수에서

네 번 다 "거기 있을 것" 이라고 생각한 자리에 없었다. 코드에 거는 변이 역검증을
문면에는 안 걸었던 것
이 원인이다 — 문면의 변이는 그 명령을 실제로 쳐 보는 것이다.
오준서가 매번 실제로 재서(grep -c "log\."docker-compose.yml ports:TestClient)
잡아 줬다.

★ 3. 절 제목 인용은 제목이 바뀌면 조용히 끊긴다

#341 에서 내가 「설계 원칙 (P4~P6)」 을 가리켰는데 #305 가 그 제목을 갈랐다.

절 번호 대조로는 안 잡힌다 — 번호는 맞고 제목이 틀렸다. #308 의 (가)~(나)가
통과하는 동안 그 결함이 살아 있었다. #351 의 (다)가 그걸 잰다.

★ 4. 원칙마다 그물을 베끼지 않는다 — 단, 표를 합치지도 않는다

베끼면      두 그물이 갈리고, 갈리는 순간 어느 쪽이 참인지 알 수 없다
합치면      P5 인용에 「1절」만 적어도 통과한다 (그 원칙에 없는 절이다)

원칙을 키로 둔 표. 공회전 방지도 원칙마다 갈랐다 — 뭉치면 P5 인용이 전부 사라져도
P6 이 있는 동안 초록이다.

★ 5. 비밀을 손에 든 경고는 길이만 말한다

#349 가 그 사례다. 진단을 위해 값을 찍으면 그 줄이 CloudWatch 에 영구히 남는다.
프리픽스(sk-·AIza)를 박는 것도 값을 읽는 것이고 표기가 바뀌면 낡는다 — #338
길이로 간 이유가 이것이다. 전용 테스트로 문면에 키 값이 없는 것을 잠갔다.

★ 6. 경고 자리를 옮기기 전에 실측한다

#121"핸들러 붙기 전 경고는 lastResort 로 나간다" 를 적어 뒀다. 그대로 믿고
옮기려다 실측했다.

(root 핸들러 없음)  포맷 없는 맨 줄                       ← lastResort
(root 핸들러 있음)  ROOT|WARNING|app.config| LLM 키가 …   ← uvicorn 의 실제 모양

적힌 근거의 전제(root 핸들러가 없다)가 실행 환경과 달랐다. #121 이 막은 것은
관측을 켜는 함수가 자기 경고를 관측 밖으로 내보내는 것 이고 그 경우가 아니었다.
→ 옮기지 않고 형제 경고와 같은 자리에 뒀다(갈라 두면 어느 쪽이 규약인지 알 수 없다).

★ 7. 날짜·사건을 추론으로 잇지 않는다

이슈 #311~#327 17건이 몰린 것을 보고 "리허설이 돌았다" 로 읽었다. 실물은 정세현이
리허설 전에 화면을 훑어서 낸 것이다. 시각은 조회하면 나온다.

★ 8. 내 COMMENTED 가 남의 PR 을 3시간 막았다

#339"막지 않는다" 고 쓰면서 COMMENTED 로 냈다. 가드는 문면을 안 읽는다 —
사용자별 최신 상태만 본다. 막지 않을 생각이면 APPROVE 로 낸다.


❗리허설에서 제일 안 재진 것 — 채점이 alpha 에서 되는지

오늘 여러 번 짚었는데 아직 안 재졌다(#309·#338·#349 세 군데).

#309 체크리스트가 / · /api/products · /api/dashboard/heatmap 셋인데 셋 다
ai-service 를 안 지난다.
지금까지의 초록은 "채점이 된다" 를 한 번도 말한 적이 없다.

#266 이 base 를 OpenAI 로 갈았는데 키는 SSM 에 그대로다. base 쪽은 갈래가 없다
${LLM_API_BASE:-} 가 빈 값이고 빈 값은 config.py 에서 기본값(OpenAI)으로 되살아난다.
남는 변수가 키 하나다.

① SSM 키 길이   세 자리 → OpenAI · 두 자리 → 옛 Gemini 키    ← #349 가 기동 로그로 자동화
② 채점 한 번    #338 의 컨테이너 안 프로브                    ← ①이 맞아도 필요하다

경고가 안 뜨는 것이 「키가 맞다」 는 뜻은 아니다 — 길이만 맞는 남의 키이거나 만료일
수 있다. ①은 PR 을 기다릴 이유가 없다고 오준서에게 두 군데로 짚었다.

다음 세션이 이어갈 것

1  #338 머지            오준서 재리뷰 대기 (2차 반영은 15:11 에 올렸다)
2  #349 · #351 머지     리뷰 대기
3  #183 후속            짧은 조각 오탐 — 내 코드
4  #284 (a) 루브릭 쪽    근거 확정됨 · 라이브러리는 정세현
5  F-DET-001 3단계(임베딩) · #234 ②    3주차

오늘 난 이슈 중 내 담당은 0건이다. #324(채점 성능 QWK)가 제일 가깝지만 「사람
라벨만 없다」 이고 그 라벨링은 내가 프롬프트 당사자로 배제된 구간이다(#343·#345·
#350 이 정세현 쪽에서 진행됐다). 파이프라인·모델 예측 40건은 #279 로 이미 냈다.

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/4 아침에 볼 것 — 내 R 셋의 품질 층 (개인 메모)

어제 판단: 세 기능이 다 「돈다」인데 깊이가 MVP 선에 걸려 있다. 배선·계약은 다
섰으니(9/3 실측: 완료 8 · 부분 12) 남은 것은 품질이고, 그게 심사에서 실제로 보이는 층이다.

아래 셋은 내 파일 안에서 끝난다 — 남의 승인·배선을 안 기다린다.


① F-EXT-002 추출 — 지금이 왜 MVP 선인가

프롬프트  39줄. 규칙 7개. 전부 "원문을 그대로 가리켜라" 계열
출력      RiskItem 하나에 condition 하나 = quote 한 문장(최대 80자) + source_span
후처리    527줄 — cue 창 선택 · 표 셀 구제 · 스팬 원문 재계산 · 실패를 계약 모양으로

후처리가 프롬프트보다 13배 크다. 그게 옳은 설계였고(모델 출력을 그대로 안 믿는다) 그
덕에 결정론이 생겼다. 그런데 그 결과로 추출이 "한 항목 = 한 인용" 에 갇혀 있다.

무엇이 얕은가 — 셋

(a) 조건이 여러 문장에 걸치면 못 담는다. 프롬프트 규칙 5 가 "한 문장, 최대 80자" 다.
VAR-PARTIAL-DEPOSIT-INSURANCE 가 그 실물이다 — #53 이 짚은 대로 첫 문장에서 끊으면
뜻이 뒤집힌다.

"…보호되지 않습니다."                          ← 여기서 끊으면 비대상
"다만, … 최저사망지급금 … 에 한하여 … 보호됩니다"  ← 이어지는 문장이 범위를 정한다

지금은 루브릭을 촘촘히 써서 그 위험을 상쇄한다(그 파일 머리말). 즉 추출의 얕음을
루브릭이 메우고 있고, 그건 항목마다 사람이 손으로 해야 한다.

후속 인용(condition.continuation 또는 quote 복수)을 담을 그릇이 계약에 없다.
risk_item.schema.json 변경이라 강희진 승인이 필요하다. 오늘 초안을 내면 그게 시작이다.

(b) importance 를 추출이 안 정한다. 템플릿이 미리 박아 둔 값을 그대로 싣는다.
문서마다 어느 항목이 더 중한지가 다른데 그게 반영이 안 된다. 재현율 분모가 템플릿에
고정된 것과 같은 뿌리다(#26).

(c) 표는 구제하되 해석하지 않는다. #204 로 단위 선언을 넣었지만 그건 회피다 —
표 구조(행 머리글 · 열 머리글 · 단위 선언)를 읽지 않고 항목이 단위를 미리 적어 두는 것이다.
#175 에 적었던 "열 머리글을 스팬에" 가 실측에서 안 됐던 이유가 표를 구조로 안 보기 때문이다.

오늘 할 수 있는 것 (순서)

1. (a) 후속 인용 계약 초안 — proposals/ 에 쓰고 강희진 멘션        반나절
2. (a) 그릇이 열리기 전에도 되는 것: 인용이 "다만·단," 로 끝나면
       경고를 내는 검사. 뜻이 뒤집힌 인용을 로딩 시점에 드러낸다   2시간
3. (b) 문서에서 importance 단서(굵게·「」·"유의사항")를 세어
       템플릿 값과 다르면 경고. 값을 바꾸지 않고 어긋남만 드러낸다  반나절

2 번을 먼저 하는 게 맞다 — 계약을 안 건드리고, 지금 있는 위험(뜻 뒤집힌 인용)을
바로 잡는다. #298·#310 이 쓴 "조용한 실패를 로딩 시점으로" 와 같은 형태다.


② F-INT-002 되말하기 질문 — 단순한 이유가 구조에 있다

유형     situation · amount · condition  (셋)
프롬프트 51줄. 규칙 5개 + 유형 표
검사     정답 노출(수치 · 결론 문장 · 루브릭 조항) · 유형 화이트리스트 · 폴백

단순한 것이 검사 때문이 아니다 — 유형이 셋뿐이고 항목당 질문이 하나다.

무엇이 얕은가 — 셋

(a) 항목당 한 질문이라 유형이 안 돈다. SessionController:141askedTypes=[]
고정해서 보낸다 — 주석이 "MVP 는 항목당 질문 1개라 항목별 사용 유형 추적을 두지 않는다"
라고 적었다. 그래서 allowed 필터가 실질적으로 안 걸린다. 내가 만든 유형 회피 로직이
요청 경로에서 무력하다.

(b) 난이도가 없다. 같은 항목을 U3(미이해) 로 판정한 고객에게 재검증할 때, 원래
질문보다 쉬운 질문이 나가야 한다. 지금은 서버가 고정문항을 쓴다
(SessionService:306 switch) — 그리고 그 자리 주석이 스스로 "기획 7-4 우회 비용 상향을
만족하지 않는다. 사전에 확보하면 그대로 뚫린다"
고 적었다. 역이용 방지 주장의 반례가
코드에 있다.

(c) 폴백이 템플릿 고정문항이다. 26% 가 폴백이면 그 26% 는 F-INT-002 가 사실상 안 돈
것이다. #234·#280 ① 로 이제 관측·재현이 되니 진단이 가능하다.

오늘 할 수 있는 것

1. 폴백률 26% 진단 — dev set 한 번(seed 고정). 어느 항목·어느 유형에서 나는지    2시간
   → 원인이 (c) 인지 정답 노출 검사의 오탐인지 갈린다. #183 후속과 같은 자리일 수 있다
2. `?variant=reverify` 를 내 쪽에 만든다 — 난이도 낮춘 질문. 서버 배선은 강희진이지만
   **엔드포인트가 있으면 그쪽이 고정문항을 지울 수 있다**                        반나절
3. askedTypes 를 실제로 쓰는 경로 요청 — 서버가 세션의 사용 유형을 보내면 (a) 가 산다

2 번이 값이 크다. 지금 고정문항이 역이용 방지의 구멍이고, 그걸 메우는 문면은 내 몫이다.
서버 배선을 기다리지 않고 내 라우트를 먼저 열어 두면 그쪽이 붙일 것이 생긴다.


③ F-INT-004 재설명 — 확인할 것

#271 이 9/2 에 머지돼서 내 재설명이 전체 경로로 처음 돈다. 어제까지 단위 테스트와
dev set 으로만 검증된 상태였다.

확인 순서

1. 로컬 3서비스 띄우고 S-01~S-05 관통 — U4 판정 뒤 재설명 버튼
   scripts/walk_demo_session.sh 로도 된다 (내 #338 이 502 갈래를 가른다)
2. 나온 문면을 눈으로 본다. 아래 셋 중 어느 것인지
증상 원인 정상인가
3~5문장 · 비유 있음 · 수치는 원문뿐 정상 경로
원문 인용만 있는 짧은 문장 환각 수치 검사 3회 실패 → _minimal() ❗폴백. #238 로그에 남는다
"…확인하지 못했습니다" 그 항목이 extraction_failed ✅ 설계대로(#60 리뷰 ②)
502 MeasurementInvalid 또는 잘림 #281·#282 가 가른다

둘째 줄이 제일 나올 만하다. 재설명 프롬프트가 "비유를 쓴다. 다만 비유에 숫자를 넣지
않는다"
인데, 비유를 쓰면서 원문 수치를 옮기는 것이 실제로 어렵다 — fabricated()
3 회 다 걸리면 최소 설명으로 내려간다.

그리고 확인해야 하는 것 하나 더

cited_spans 가 실제로 채워지는지. _cited_spans수치를 하나라도 옮겼거나 조건
문면의 12자 조각을 인용
했을 때만 스팬을 남긴다. 비유 중심으로 쓰면 둘 다 아닐 수
있고
, 그러면 리포트에 근거가 안 남는다(P4 는 판정 쪽이라 안 걸리지만, 교부 문서에서
"이 설명의 근거" 가 빈다).

→ 관통해 보고 cited_spans 가 비면 그게 발견이다.


순서 제안

아침   ③ 관통 확인 (30분) — 리허설 뒤라 지금 상태를 알아야 나머지 판단이 선다
오전   ② 1번 폴백률 진단 (2시간) — 관측이 열렸고 재현 가능하다
오후   ① 2번 "다만·단," 경고 (2시간) → ① 1번 계약 초안 (반나절)

③ 을 먼저 두는 이유는 재설명이 실제로 어떤 문면을 내는지 모르는 상태에서 ①②를
고치면 우선순위를 잘못 잡을 수 있다는 것이다. 폴백이 대부분이면 ③이 1순위가 된다.

세 건 다 내 파일 안에서 끝나고, 계약 변경이 필요한 것은 ① 1번 하나다(강희진 승인).

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

F-DET-001 3단계 임베딩 — 적용 방안 (실측 기반, 2026-09-03)

결론부터: 내 메모의 원안이 틀렸다. "오해 8종 패턴을 미리 임베딩 → 코사인 + 임계값"
으로 적어 뒀는데 실측에서 안 된다. 대신 대조 앵커(pro/anti margin) 가 된다.


① 원안 반증 — 임베딩도 부정을 못 가른다

text-embedding-3-small(1536차원)로 패턴 하나에 대한 코사인을 쟀다.

M09  패턴 "주식처럼 팔고 싶을 때 팔면 되는 거 아닌가요"
  0.976  오해 원본
  0.924  어미 변형
  0.560  어미 변형2   "그냥 주식처럼 팔면 되는 거 아니에요?"
  0.621  ❗정답        "주식처럼 팔 수 없다고 들었어요"      ← 변형2 보다 높다
  0.542  ❗정답2       "상장이 안 돼서 못 판다면서요"
  0.152  무관

M10  0.716 어미변형  ~  0.663 ❗정답(부정)                  ← 0.053 차이

M09 는 임계값이 존재할 수 없다. 어미변형2(0.560)를 잡는 임계값은 정답(0.621)을 먼저
잡는다. M10 은 0.68 근처에서 갈리는데 표본 4건에 기댄 폭이라 못 쓴다.

이유가 구조적이다 — 임베딩은 주제 를 잡고 입장 을 못 잡는다. 부정은 주제를 안
바꾼다. #203 에서 n-gram 이 못 가른 것과 같은 실패이고 원인만 다르다(그건 어미가
잘려서, 이건 부정이 벡터를 안 옮겨서).

→ 내 메모의 "2차는 LLM 보다 임베딩" 항목에 이 반증을 적어야 한다. 그대로 두면
다음에 그 문장을 근거로 착수한다.

② 되는 것 — 대조 앵커 (pro/anti margin)

절대 유사도를 버리고 어느 쪽에 더 가까운가를 본다.

margin = max(cos(발화, 오해패턴)) - max(cos(발화, 이해패턴))
M09                                   pro     anti    margin
  오해 원본                           0.976   0.593   +0.382
  어미변형                            0.924   0.584   +0.339
  어미변형2                           0.560   0.444   +0.116
  ❗정답                              0.621   1.000   -0.379
  ❗정답2                             0.542   0.781   -0.239
  무관                                0.152   0.281   -0.129

M10
  오해 원본                           0.989   0.382   +0.607
  어미변형                            0.716   0.628   +0.088
  ❗정답(양보)                        0.464   0.887   -0.423
  ❗정답(부정)                        0.664   0.679   -0.016
  무관                                0.209   0.355   -0.146

부호가 정확히 갈린다. 오해·변형 전부 양수(+0.088 ~ +0.607), 정답·무관 전부 음수
(-0.016 ~ -0.423). 어미변형2 가 절대값으로는 정답보다 낮았는데(0.560 < 0.621) 상대
비교에서는 뒤집힌다
— 그게 이 설계의 요점이다.

여유가 좁다. 최소 양수 +0.088, 최대 음수 -0.016 → 간격 0.104. 표본 11건이라
이 폭을 임계값으로 쓰면 안 된다. margin > 0 만 쓰고 크기는 해석하지 않는다.

③ 필요한 데이터 — 이해 발화(anti)가 없다

지금 misconceptions.yamlpatterns(오해)만 있다. anti 앵커가 필요하다.

- id: M09-NO-LISTING
  patterns: ["주식처럼 팔고 싶을 때 팔면 되는 거 아닌가요"]
  counter_patterns:                       # ← 새 필드
    - "주식처럼 팔 수 없다고 들었어요"
    - "상장이 안 돼서 못 판다고 하셨죠"

데이터는 정세현 소유다. 그리고 요청 근거가 좋다 — 위 표가 "이게 없으면 3단계가
원리상 안 된다"
를 보인다. 9종 × 2건이면 18건이고, dev set 정답 대조군 5건이 이미
그 성격이라 출발점이 있다.

대안: app/rubrics/*.yamlrequired_elements 를 anti 로 쓸 수 있다 — 그건
"이해로 인정되려면 언급돼야 하는 것" 이라 정의상 이해 발화에 가깝다. 내 파일이라
정세현을 안 기다린다.
먼저 이걸로 재보고, 되면 데이터 요청 없이 간다.

④ 배선 설계

1단계 pattern   부분열 일치 → 1.0            결정론. 그대로 둔다
2단계 ngram     containment ≥ 0.62           그대로 둔다
3단계 embedding margin > 0 인 유형만          ← 새로. 1·2 가 못 잡은 것만 본다

1·2 를 안 건드린다. 그 둘이 결정론이고 감사에서 셀 수 있는 것이라, 임베딩은
미분류 후보에만 얹는다(unclassified_candidate 가 지금 그 자리를 표시한다).

def match(text, product_type="ELS"):
    ...  # 1·2 단계 그대로
    if not matches and _embedding_enabled():
        matches = _embedding_stage(norm, product_type)   # stage="embedding"

재현성 (P2)

  • 패턴·counter 임베딩은 미리 계산해 파일로 커밋한다data/misconception_library/
    옆에 embeddings.jsonl(유형ID · 문면 · 벡터 · 모델명 · 차원). 라이브러리 version
    올라가면 재생성하고, 불일치를 로딩 시점에 터뜨린다(assert_* 계열).
  • 발화 임베딩만 런타임 호출이다. 항목당 1회. #280 에서 seed 로도 안 된 채점과
    달리 임베딩은 같은 입력·같은 모델이면 같은 벡터다 — 그건 재봐야 한다(아래 ⑥).
  • 임계값이 margin > 0 하나뿐이라 튜닝 가능한 숫자가 코드에 안 남는다. 이게 원안보다
    나은 점이다 — 심사에서 "임계값을 어떻게 정했나" 를 안 물린다.

폐쇄망 (llm_client docstring 요구)

base_url 주입이 이미 되니 임베딩도 같은 어댑터를 지난다. 다만 모델명이 하드코딩되면
안 된다
LLM_EMBED_MODELconfig.py 에 열고 #266 때처럼 3개만 갈아 옮길 수
있게 한다. 온프레미스는 bge-m3 같은 다국어 모델이 후보다(한국어 부정 처리는 재봐야 한다).

⑤ 비용

미리 계산   9종 × (패턴 11 + counter 18) ≈ 29건 · 1회      무료 수준
런타임      발화 1건당 15토큰 (실측)                        채점 1회보다 훨씬 싸다
호출 시점   1·2 단계가 놓친 것만 → 지금 dev set 기준 14/24

⑥ 착수 전에 재야 하는 것 — 셋

1. 임베딩이 결정론인가 — 같은 입력 3회가 바이트 단위로 같은가
   ❗#280 에서 seed 2회 동일을 보고 "결정론" 이라 적었다가 3회에서 갈렸다.
     2회는 표본이 아니다. 이번엔 3회 이상 재고 문면에 적는다
2. rubrics 의 required_elements 를 anti 로 써도 부호가 갈리는가
   → 되면 정세현 데이터 요청이 없어진다
3. dev set 24건 전수에서 오탐 0 인가 — 특히 정답 대조군 5건
   (UNDERSTOOD-BASELINE · KNOCKIN-UNDERSTOOD · VAR-PRINCIPAL-UNDERSTOOD ·
    VAR-RATIO-UNDERSTOOD · PARROTED-RUBRIC-CLAUSE)

3 번이 게이트다. 3단계가 오탐을 내면 apply_misconception_floor 가 U4 를 확정하고
게이트가 RED 가 된다 — #203 에서 정세현이 "stage=pattern 1.000 은 LLM 이 되돌릴 수
없는 확정 경로"
라고 적은 그 위험이 3단계에도 있다. 오탐 1건이라도 나오면 착수하지
않는다.

⑦ 순서

0. (30분) ⑥-1 결정론 3회 측정 · ⑥-2 rubrics anti 대체 가능성
1. (2시간) 미리 계산 스크립트 + embeddings.jsonl + 로딩 시점 불일치 검사
2. (2시간) _embedding_stage 배선 — 1·2 를 안 건드리고 미분류에만
3. (1시간) ⑥-3 dev set 전수 · 오탐 0 확인. 나오면 여기서 멈춘다
4. (1시간) 변조 검증 — anti 를 지우면 정답이 잡히는지 / margin 부호를 뒤집으면

단, F-CMN-003 라벨이 0건이라 "개선됐다" 를 잴 수가 없다. 결정론 10/24 → N/24 는
말할 수 있지만 그게 재현율 개선인지는 공식 평가셋으로만 나온다. 순위는 그대로 뒤쪽이
맞고
, 이 문서는 착수할 때 바로 쓰기 위한 것이다.

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

F-EXT-002 에 검색 스택(청킹 · 하이브리드 · RRF · 리랭킹) 적용 방안

전제부터 — 이 스택은 재현율을 올리는 게 아니라 내릴 수 있다.

지금        문서 전체(13~21k자)를 프롬프트에 통째로 넣는다   extraction.py:525
            → 검색 재현율이 구조적으로 1.0 이다. 못 찾으면 그건 LLM 이 못 본 것
검색 넣으면  top-k 청크만 넣는다
            → 검색이 놓친 청크의 항목은 LLM 이 볼 기회조차 없다

즉 이 변경의 이득은 재현율이 아니라 정밀도·설명가능성·비용이다. 그걸 먼저 못 박아야
착수 판단이 선다 — 안 그러면 "검색 붙였는데 성적이 내려갔다" 로 끝난다.


① 지금 무엇이 아픈가 — 검색으로 풀리는 것만 골라낸다

증상 검색 스택이 푸나
CUE_CONTAINMENT_MIN = 0.35 가 계약 정답 26건 중 6건 거부 (#127) 직접 겨냥한다
표 셀이 자연어 cue어휘가 하나도 안 겹친다 (코드 주석) ✅ 하이브리드의 정확한 용도
그래서 항목 성격에 따라 기준을 자동으로 바꾸는 분기가 붙어 있다 ✅ 리랭커가 그 분기를 없앤다
조건이 여러 문장에 걸치면 못 담는다 (#53 뜻 뒤집힘) ❌ 계약(그릇) 문제다. 검색 무관
importance 를 추출이 안 정한다 ❌ 별개
실행마다 결과가 다르다 (#229) ⚠️ 일부 — 청크가 줄면 흔들림도 줄지만 근본은 #280

아픈 것 셋이 정확히 이 스택의 자리다. 그리고 셋이 한 뿌리다 — "어느 문면이 이 항목의
조건인지"
cue 문자열 겹침 하나로 판별하고 있고, 그 지표가 표에서 죽는다.

② 청킹 — 페이지가 아니라 조항·표 단위

파서가 페이지 단위로 준다(pages[].text). 페이지는 청크가 아니다 — 한 페이지에 관계없는
조항이 여럿이고, 표는 페이지를 걸친다.

경계 후보 (우선순위)
  1. 「」 · 숫자 조항 머리("5. 중도상환에 대한 사항")   ← 공시문서가 실제로 쓰는 구조
  2. 표 상단 선언("(단위 : 원, %)") ~ 표 끝              ← #204 가 만난 그 구조
  3. 빈 줄 2개 이상
  4. 그래도 넘치면 문장 경계로 400~600자 슬라이딩(겹침 100자)

스팬 항등식을 깨면 안 된다. pages[page].text[start:end] == condition.value_text
P6 의 근거이므로, 청크는 원문 오프셋을 들고 다녀야 한다(page · start · end).
청크를 정규화하거나 재조립하면 그 항등식이 깨지고 추출이 통째로 무의미해진다. 이게 이
설계에서 제일 조심할 자리다.

③ 하이브리드 — 두 검색기가 서로의 사각을 받는다

질의 = 템플릿 항목의 cue + name        (수치 없음 — cue 에 숫자를 금지해 뒀다)

키워드   기존 containment 재사용. 자연어 조건에서 강하다
dense    text-embedding-3-small(1536). 표 셀·어휘 불일치에서 강하다

표 셀이 이 조합의 존재 이유다. 주석이 적은 그대로 "표 셀은 순수 수치라 자연어 cue 와
어휘가 하나도 안 겹친다"
— 키워드가 0 이 되는 자리를 dense 가 받는다. 반대로 dense 는
#203·오늘 실측에서 보듯 주제만 잡고 세부를 못 가르므로 수치가 든 조건은 키워드가 낫다.

④ RRF — 여기서는 융합이 실제로 값을 한다

F-DET-001 에서 RRF 를 권하지 않은 이유는 두 신호가 같은 방향으로 틀려서였다(부정을
둘 다 못 본다). 여기는 다르다 — 두 신호가 서로 다른 자리에서 죽는다. 그러면 순위 융합이
실질이다.

RRF(d) = Σ 1/(k + rank_i(d))        k=60 (관례값)

점수 정규화가 필요 없는 게 요점이다. containment(01)와 코사인(-11)을 같은 축에 올리려면
스케일을 정해야 하는데, RRF 는 순위만 쓴다. 임계값이 하나 줄어드는 것이고 그게
#204·#127 에서 배운 것과 같은 방향이다(임계값은 실측에 묶고, 없앨 수 있으면 없앤다).

⑤ 리랭킹 — cue 임계값과 그 자동 분기를 대체한다

RRF 상위 k(=8~12)를 (항목, 청크) 짝으로 다시 본다.

지금   best_cue < 0.35 이면 "cue 판별이 이 항목에 안 통한다" 고 보고 수치 비율로 갈아탄다
        → 임계값 하나 + 분기 하나 + 그 분기가 옳은지 아무도 못 잼
리랭킹  이 청크가 이 항목의 조건인가 를 짝으로 판단 → 순위만 낸다

모델 선택이 팀 결정에 걸린다. "모든 LLM 호출을 단일 모델로" 이고 config.py 가 정책
밖이면 경고를 낸다. 두 갈래다.

(a) 전용 리랭커(bge-reranker-v2-m3 등)   품질 높다. 팀 결정 재검토 + 폐쇄망엔 오히려 유리
(b) gpt-5-mini 로 순위만 매긴다           결정 안 건드린다. 대신 #280 의 비결정성을 물려받는다

(b) 로 시작하는 게 맞다 — 정책을 안 건드리고, 되면 (a) 로 옮기는 근거가 실측으로 생긴다.
llm_client 어댑터가 이미 base_url 주입이라 (a) 로 갈 때 코드가 안 바뀐다(#266
증명했다).

⑥ pgvector — 지금은 아니다

F-DET-001   벡터 29개   → 파일(embeddings.jsonl) 이 맞다
F-EXT-002   문서당 수백 청크 · 문서 종수가 늘면 수천  → 그때 값이 있다

다만 MVP 는 H2 이고 영속 계층은 강희진 영역이며 #37 컨테이너 규약이 미결이다.
1차는 인메모리 + 미리 계산한 파일로 간다 — 문서 종수가 2 종이라 그걸로 충분하고,
인프라 변경을 데모 전에 넣을 이유가 없다. pgvector 는 "문서가 N 종을 넘으면" 을 조건으로
적어 두고 넘어간다.

⑦ 측정 — 착수 전에 이걸 먼저 만든다

이 스택의 진짜 위험은 재현율 손실이고, 그걸 재는 도구가 지금 없다.

있는 것   contracts/samples/*.json 의 _expected_risk_items 26건 (정답 스팬 포함)
          conftest.REAL_CASES 가 실문서 2종을 파싱해 샘플과 함께 준다
없는 것   recall@k 를 재는 것 — 정답 스팬을 담은 청크가 top-k 에 들어오는가

순서가 이것이다.

0. recall@k 측정기를 먼저 만든다 (LLM 호출 0회 — 검색만 잰다)      2시간
   정답 스팬(page·start·end)이 어느 청크에 들어가는지는 계산이다
1. 청킹만 붙이고 recall@k 를 본다. k=8 에서 26/26 이 아니면 청킹을 고친다  2시간
2. 하이브리드 + RRF. recall@8 이 유지되는지 확인                    3시간
3. 리랭킹 (b). top-3 정밀도가 오르는지                              2시간
4. 그 다음에야 추출 프롬프트를 top-k 로 바꾼다                       2시간

4 번을 마지막에 두는 것이 핵심이다. 0~3 은 기존 경로를 안 건드린다 — 검색을 옆에
붙여 재기만 하므로 언제 멈춰도 손실이 없다. recall@k 가 26/26 이 안 되면 4 번을 하지
않는다.

⑧ 이 스택이 안 푸는 것 — 같이 적어 둔다

조건이 여러 문장에 걸침(#53)   계약에 후속 인용 그릇이 필요하다. 검색 무관
importance 자동 판정            별개
실행 간 비결정성(#229·#280)     청크가 줄면 흔들림이 줄 수는 있으나 근본은 파라미터 쪽이고
                               #281 에서 파라미터로는 안 된다는 것이 실측으로 나왔다
F-EXT-003 재현율 숫자           측정기가 0건이라 "개선됐다" 를 공식적으로 못 쓴다

마지막이 제일 걸린다. #127 의 6/26 은 내가 계약 정답으로 잰 숫자이고, 그건 eval/
공식 수치가 아니다. 이 스택으로 6/26 을 0/26 으로 만들어도 심사에서 인용할 근거는
F-EXT-003 이 서야 생긴다
— 그건 정세현 몫이고 구현 0건이다.

그래서 순위는 여전히 #283 어제 메모의 ①②③ 뒤다. 다만 ⑦-0(recall@k 측정기)은
F-EXT-003 의 분자를 재는 코드와 상당 부분 같다 — 그걸 내가 만들어 두면 정세현이
가져다 쓸 수 있고, 그러면 두 병목이 한 번에 준다. 거기서 시작하는 게 값이 크다.

yoonjiseok pushed a commit that referenced this pull request Sep 3, 2026
RRF 까지는 순위 융합이고, *"이 문면이 이 항목의 조건인가"* 는 짝을 함께 보는 모델만 한다.
F-DET-001 실측이 그 근거다 — 임베딩이 오해 문장과 그 부정을 **0.560 vs 0.621 로 뒤집어
놨다**(주제는 같고 입장만 다르다).

## ★ 실측 — 리랭킹이 recall@1 을 두 배 이상 올린다

ELS 계약 정답 13건 · 청크 55개.

    RRF 만        recall@1  4/13    recall@3  11/13
    RRF+리랭킹     recall@1  9/13    recall@3  12/13

**앞 커밋에서 이득이 작다고 적은 것이 이 단계가 없어서였다.** 융합은 후보를 모으고
리랭커가 고른다.

## ❗그런데 게이트를 못 넘었다 — 그리고 지표가 흔들린다

`#283` 방안에 *"`recall@k` 가 26/26 이 안 되면 추출 프롬프트를 top-k 로 바꾸지 않는다"* 고
적어 뒀다. **12/13 이므로 안 바꾼다.** 그리고 재실행하니 11/13 이었다 — 리랭커가
비결정적이라(`#281`) **지표 자체가 회차마다 다르다.**

놓친 둘을 보니 **둘 다 청킹 경계 문제**이고 순위 문제가 아니다.

    ELS-EARLY-REDEMPTION-CONDITION   정답 청크 30, 가져온 것 31·32·33  ← 인접 청크
    ELS-ISSUER-CREDIT-RISK           정답 청크 45 가 문장 중간에서 시작한다
                                     ("따른 위험 파생상품적 성격을…" — 앞이 잘렸다)

→ 다음 할 일은 리랭커 튜닝이 아니라 **청킹 경계와 이웃 청크 포함**이다. 인접 청크를
같이 넘기면 첫째는 그대로 구제된다.

## 설계에서 지킨 것 넷

**① 순위만 받는다 — 점수를 안 받는다.** 점수를 받으면 그 숫자가 임계값이 되고
*"0.7 은 어떻게 정했나"* 를 답해야 한다. RRF 를 순위 융합으로 둔 것과 같은 이유다.

**② 후보가 `top_n` 이하면 안 부른다.** 순위를 바꿀 여지가 없는데 부르면 **비결정성만
들인다.** 호출 절약이 아니라 그게 이유다.

**③ 모델이 낸 번호를 그대로 안 믿는다.** 범위 밖·중복을 걸러낸다 —
`_pin_item_id`·`_drop_llm_misconception_type`(F-SCR-001)과 같은 층이다.

**④ 리랭커가 죽으면 RRF 순위로 되돌아가고 로그를 남긴다.** 이 단계는 순위를 *개선* 하는
것이라 검색이 같이 죽으면 안 된다. 그리고 **조용히 폴백하지 않는다** — 로그가 없으면
리랭킹이 꺼진 채로 도는 것을 아무도 모른다(`#238` 과 같은 이유).

`client=None` 이면 RRF 까지만 돈다 — `recall@k` 측정과 테스트가 LLM 없이 돌아야 하고,
리랭커가 정책·쿼터에 걸리는 날에도 검색은 돌아야 한다.

## 비결정성을 문면에 박았다

`rerank` docstring 이 쓰는 자리를 셋으로 가른다.

    루브릭 생성 · 커버리지 검사   ✅ 사람이 승인한다. 흔들려도 사람이 본다
    F-EXT-002 추출 프롬프트 입력   ⚠️ 실행마다 top-k 가 달라진다 → #280 이 그 자리다
    F-SCR-001 채점                ❌ 쓰지 않는다

## 변조 검증

| 변조 | 잡히나 |
|---|---|
| 범위 검사 제거 (모델 출력을 그대로 믿음) | ✅ |
| 폴백 로그 제거 (조용히 꺼짐) | ✅ |
| 후보 적을 때도 리랭커 호출 | ✅ |
| `client=None` 인데 리랭커 호출 | ✅ 2건 |

457 passed (+6).
yoonjiseok pushed a commit that referenced this pull request Sep 3, 2026
## ❗먼저 — 내가 "증상을 덮는 것" 이라고 한 판단이 틀렸다

`Chunk` 는 페이지 하나 + 오프셋을 든다. `pages[page].text[start:end] == text` 가 P6 ·
1절 F-EXT-002 의 근거이므로 **여러 페이지를 걸친 청크는 그 항등식을 만족할 수 없다.**

그런데 공시문서는 문장이 페이지를 걸친다.

    페이지 첫 청크 15개 중 **10개가 문장 중간에서 시작한다**  (계약 샘플 실측)

항등식이 크로스 페이지를 금지하는 이상 **이웃 포함이 그 제약 안에서의 정답**이다.

## 그런데 실측이 절반만 맞았다 — 그것도 적는다

    top-3 만        recall 12/13
    top-3 + 이웃1   recall 12/13     ← 안 올랐다

거리를 재니 이유가 명확했다.

    ELS-EARLY-REDEMPTION   정답 30, 가져온 것 31·32·33   거리  1  → 구제한다 ✅
    ELS-ISSUER-CREDIT-RISK 정답 45, 가져온 것 6          거리 39  → 원리상 못 닿는다 ❌

뒤엣것은 **적중 근처에 정답이 없다** — 검색이 아예 다른 데를 짚었다. 정답 청크가 문장
중간에서 시작해서(`"따른 위험 파생상품적 성격을…"`) 질의와 어휘·주제가 둘 다 안 맞는다.

**즉 이웃 포함은 순위 밀림을 구제하고 페이지 경계 문제는 구제하지 못한다.**
반경을 늘려 39 를 덮으려면 청크 79개를 넣는 것이고 그러면 문서 전체와 같다 — 이 모듈이
존재하는 이유가 없어진다. 그래서 **한계를 늘리는 것으로 풀지 않고 테스트로 못 박았다.**

남은 길은 둘이다. 청크가 스팬 목록을 들거나(항등식을 조각별로 만족), 파서가 페이지 경계
문장을 이어 주거나(`parsing.py` · 정세현). `#283` 에 남긴다.

## ❗그물이 런타임 값을 안 재고 있었다

`test_neighbors_cannot_reach_a_far_answer` 를 처음에 `span=1` 로 명시해서 썼더니
**`NEIGHBOR_SPAN = 40` 변조가 그 테스트를 안 지나갔다**(다른 테스트가 우연히 잡았다).

→ 기본 상수를 읽게 고쳤다. **그물은 런타임이 쓰는 값을 재야 한다** — 오늘 `#304`
정규식·`#352` 예외에서 내가 지적한 것과 같은 모양이고, 이번엔 내 테스트가 그랬다.

## 변조 검증

| 변조 | 잡히나 |
|---|---|
| 이웃을 안 냄 | ✅ 2건 |
| 중복을 안 지움 | ✅ |
| `NEIGHBOR_SPAN = 40` (반경으로 덮으려 함) | ✅ (고친 뒤) |

461 passed (+4).
yoonjiseok pushed a commit that referenced this pull request Sep 3, 2026
## ★ 게이트를 넘었다

    청킹 v1 (page,start,end 하나)     top-3  12/13   + 이웃  12/13
    청킹 v2 (스팬 목록 · 이 커밋)      top-3  11/13   + 이웃  **13/13**

`#283` 방안에 *"`recall@k` 가 26/26 이 안 되면 추출 프롬프트를 top-k 로 바꾸지 않는다"* 고
적어 뒀다. ELS 13건 전건이 되었고, **3회 반복에서 다 13/13 이다** — 리랭커가 한 번 실패해
RRF 로 폴백한 회차에도 유지됐다(비결정성 아래서도 선다).

## 무엇이 문제였나

공시문서는 문장이 페이지를 걸친다. 계약 샘플 실측:

    페이지 첫 청크 15개 중 **10개가 문장 중간에서 시작**

`Chunk` 가 `(page, start, end)` 하나였으므로 그 문장은 **어느 청크에도 온전히 없었다** —
검색을 어떻게 고쳐도 못 찾는다. `ELS-ISSUER-CREDIT-RISK` 가 그 실물이었고, 이웃
포함으로도 안 됐다(정답이 적중과 **거리 39**).

## 항등식을 조각별로 만족시킨다

    "".join(pages[s.page].text[s.start:s.end] for s in spans) == chunk.text

**P6 · 1절 F-EXT-002 근거가 안 약해진다** — 조각마다 원문을 그대로 가리킨다. 페이지를
걸친 조건이 한 청크에 온전히 들어오고, 그 청크의 `spans` 가 둘이 된다.

`page`·`start`·`end` 는 **첫 조각**을 가리키는 유도 속성으로 남겼다. 대부분의 청크가
조각 하나라 호출부가 그대로 쓰고, 여러 조각을 다루려면 `spans` 를 명시적으로 봐야 한다.

## 병합 판정 — 조항머리를 함께 본다

앞 페이지가 문장 종결로 끝나지 않고 **뒤 페이지가 조항머리로 시작하지 않으면** 갈린 것으로
본다. 조항머리를 같이 보는 이유: 앞 페이지가 제목으로 끝나면(마침표가 없다) 종결 검사만
으로는 늘 "갈렸다" 가 된다 — **실측으로 그 오탐이 9건이었다.**

앞 페이지의 **끝** 청크와 뒤 페이지의 **첫** 청크만 합친다. 중간 청크를 합치면 조건이
아닌 것까지 끌어온다.

    ELS  청크 55 → 45 · 페이지 걸친 것 10
    VAR  청크 82 → 73 · 페이지 걸친 것  9

## 그물을 같이 고쳤다

항등식 테스트를 **조각별**로 바꿨다. 그리고 `test_some_chunks_cross_a_page_boundary` 를
새로 뒀다 — 이 단정이 없으면 **스팬 목록만 만들고 병합이 안 도는 상태가 전건 초록**이고,
그러면 이 커밋이 무의미하다.

463 passed (+2).
@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/4 — 채점 품질로 넘어간 날

main   #368 까지 (138721f) · ai-service 521 passed
머지    #338 · #351 · #349 · #352 · #368        (오늘 다섯)
대기    #366 강희진 · #358 강희진 · #378 정세현

오늘 한 것 — 채점 로직 세 겹

#366  U1 문턱 (u1_requires) + 오해를 세기보다 먼저 본다     미탐 16.7% → 11.1% · 오탐 그대로
#368  채점 임계값 여섯을 선언 파일로 (머지됨)                동작 안 바뀜
#378  dev set 에 반말·평서체 + U2·U3 + 픽스처 규약          프로덕션 무변경

❗임베딩을 재고 접었다 — 기록이 값이다

#356(미탐) 을 임베딩으로 풀려고 했고 실측에서 떨어졌다. 사용자가 "정반대 뜻이
0.621 은 말이 안 된다"
고 의심해서 전수 감사를 했다.

구현 검증   자기 자신 +1.0000 · 부호 반전 -1.0000 · 노름 0.9999   ← 코드는 정확하다
바닥값      무관한 문장 쌍 10개  +0.123~+0.236 (평균 0.158)        ← 0 이 아니다

기준 "원금은 지켜지는" (오해 패턴)
  +0.660  "원금이라는 말이 무슨 뜻인가요"     ← 1등이 「모르겠다」는 질문이다
  +0.644  "원금은 보장됩니다"        같은 뜻
  +0.623  "원금은 보장되지 않습니다"   ❗정반대
  +0.621  "원금이 손실될 수 있다는 건 이해했습니다"  ❗정반대
  +0.571  "원금 손실은 없습니다"      같은 뜻 ← 정반대보다 낮다

임베딩은 「무엇에 관한 말인가」를 재고 「참인가」는 안 잰다. 3-large 가 더 나빴던
것도 같은 이유다. #364 에서 강희진이 바이그램으로 잰 것과 같은 벽이다 —
"예금자보호는 된다" 가 조건 "예금자보호가 된다" 에 0.71 로 붙는다.

기록: ai-service/tools/tune_embedding_threshold.py(미머지 · #352 에서 걷어냈다).

❗❗제일 큰 발견 — 표본이 종결어미로 라벨을 흘린다 (#377)

종결어미를 신호로 쓰려고 재다가 신호가 너무 깨끗해서 의심했고, #354 방법(내용을
안 보는 프로브)을 걸었다.

발화 끝 6자만 본다. 루브릭·조건·내용 전부 안 본다.
   판정 19/51 (37%) · 그중 맞힘 18/19 = 95% · 기준선 63%

U1 7건이 예외 없이 -네요(3) · -라는/다는 거죠(4) 두 형태에만 있고
그 두 형태에 U4 는 0건 — 합의 표본에서 U1↔U4 가 종결어미로 완전히 분리된다

#354위치 누설과 다른 축이라 섞어도 안 없어진다. 그리고 뿌리가 화법 폭
이다(eval 69/70 · 내 dev set 23/24 가 존댓말) — 반말은 라이브러리·LLM 둘 다 잘 되는데
표본에 한 건도 없었다.

→ 화법을 넓히는 것이 누설 대책이므로 자연스러움과 누설 차단이 같은 방향이다.
내 dev set 은 #378 로 고쳤고(96% → 74%), eval 표본은 정세현 몫으로 넘겼다.

남의 PR 리뷰 여섯

#361 CHANGES_REQUESTED   ❗matchedMisconceptions 가 escalate 유형을 안 거른다
                          → M08-TYING 이 질문 생성 프롬프트로 가고 질문은 판매자 화면에 뜬다
                            scoring.py:462 가 reason 에서 막아 둔 우회가 다시 열린다
#364 APPROVED            그 PR 의 데이터가 (b) 를 부결시킨다 — 70건 적중 1건이 오탐
#370 CHANGES_REQUESTED   CONSISTENCY_GRADES 의 U2 는 게이트를 못 바꾼다(R-04 가 R-05 앞)
                          → 강희진이 U1 로 좁혔다
#371 APPROVED            #366 머지 뒤 "리포트 v2 ↔ 코드 v3" 틈을 짚었다(별건 제안)
#372 APPROVED            캡이 셋 되면서 「값이 서로 다르다」의 한계 — 넷째는 자리가 없다
#374 APPROVED ×2         결정로그. 10.82(#367) · 10.83(#369) 내 것 대조

❗내가 낸 사고 하나

커밋 안 한 임베딩 작업 283줄이 git add -A#352 에 쓸려 들어갔다. 커밋 메시지도
PR 본문도 명부 대조 얘기뿐이었고, 테스트도 CI 도 아무것도 안 물었다 — 잡은 것은
정세현 리뷰다. 걷어냈고 원인을 적었다: "무엇을 커밋하는지 안 보고 썼다."

오늘 두 사람이 자기 리뷰를 정정했다

정세현   #368 승인의 "배선 둘 다 따라왔다" → 웜업 없이 재서 틀렸다. 승인 유지
강희진   #368 리뷰의 "대조 테스트가 없다" → #336 이 그것이다. 지적은 유지

둘 다 결론은 유지하고 근거만 고쳤다. 그 정정에서 검증 3층이 갈렸다 —
일관성(#336) / 정확성(내 테스트) / 동작(웜업).

다음

1  #366 머지 → #367 (ELS-LOSS-SIMULATION 요소 쪼개기). min_echo_bigrams() 하한이 움직인다
2  #358 · #378 머지
3  #377 이 닫히면 종결어미 레이어를 다시 본다 — 지금 만들면 누설을 코드로 굳힌다
4  #284 (a) 루브릭 — 선언 46 ↔ 강제 16 의 간격
—  alpha 채점 확인은 여전히 안 됐다 (#278 열림). AWS 접근이 필요해 내 손 밖이다

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/4 저녁 — 채점 품질 구간 마감

main   #381 까지 (13a3ecb) · ai-service 728 passed

CLAUDE.local.md 는 gitignore 라 랩탑 간에 안 넘어간다. 오늘 핵심은 아래에 옮긴다.

오늘 머지된 내 것 — 여덟

#338 502 진단 (4차 리뷰까지)   #351 절 표기 가드   #349 키·프로바이더 경고
#352 fixtures 그물             #368 임계값 선언 파일   #358 검색 스택
#366 U1 문턱 + 오해 우선        #378 dev set 화법·등급 폭

열린 것 — 둘

#379  강제 여부를 루브릭 파일이 말한다 (#284 c)   강희진만 (정세현 APPROVED)
#385  오해 탐지 여섯 방법 측정 기록               정세현 리뷰 요청

★★ 본체 — 여섯 방법을 다 재고 다섯이 떨어졌다

기록: ai-service/tools/MISCONCEPTION-DETECTION.md(#385). 숫자·재현은 거기 있다.

LLM 한 콜 (#366)     미탐 11.1% · 오탐 4.7% · 1콜      ✅ 기성 부품의 천장
쌍별 LLM             미탐 10.5% · 오탐 12.5% · 2.6콜   ❌ 오탐이 네 배
임베딩                정반대 +0.623 · 같은 뜻 +0.571    ❌
바이그램 (#364)        70건 적중 1건, 그게 오탐          ❌
기성 NLI (KLUE)       전수 모순율 24%                  ❌
NLI 양방향 + 정렬      커버리지 17% · P5 반대 오류 1건    ❌

다섯이 떨어진 이유는 하나다 — 닮음을 재고 있었다. 오해는 닮음이 아니라
「반대되는 믿음」이고, 우리 오해의 절반이 정도·수량사·범주 축이라 세 방법 어디에도
안 걸린다.

❗하루에 같은 함정 네 번

작은 표본 → 전수에서 조건이 바뀌면 무엇을 잰 건지 알 수 없다.

자기정정      미결 규칙(#363)을 프롬프트가 먼저 정했다
「상쇄 금지」   5건 4/5 → 전수 미탐 2→3
쌍별 1차      프로브→전수에서 시스템 프롬프트에 한 줄
NLI          4쌍 0.999 → 전수 24% (가설 술어를 손으로 맞춰 줬다)

❗내가 낸 사고 — 283줄이 남의 리뷰 대상에 섞였다

커밋 안 한 임베딩 작업이 git add -A#352 에 들어갔다. 테스트도 CI 도 안 물었고
잡은 것은 정세현 리뷰
다. → 경로를 적어 스테이징하고 git show --stat 을 본다.

다음

1  #379 · #385 머지
2  #386  ❗alpha 채점 확인 — 오준서 담당으로 냈다. 도구는 다 들어갔고 실행만 남았다
3  #377 이 닫히면 종결어미 레이어 (kiwipiepy 확인 완료)
4  #284 (a)(b) — 소형 모델. 반박 21개(tools/condition_counters.py)가 씨앗
—  #367 은 재측정 음성 — 안전하지만 값이 안 측정된다

공모전 관점 정리

채점 정밀도는 이미 목표를 넘었다(QWK 0.884 vs 0.750 · U4→U1 0건). 남은 위험은
정밀도가 아니라 「돌아가는가」 하나이고 그게 #386 이다.

오늘 측정 작업의 실질 가치는 정밀도가 아니라 「왜 임베딩·NLI·유사도를 안 쓰나」에
답할 근거
다 — 심사에서 물으면 쓰이고 안 물으면 안 쓰인다. 그 보험은 다 샀다.

몰랐던 근거 하나

proposal.md:419  "외부 LLM API를 그대로 호출하는 구조는 재위탁 문제를 일으킨다.
                  국내 인프라와 전용 배포를 전제로 설계한 이유다."

내 메모에는 "온프레미스 교체 가능하게 base_url 주입" 만 있고 왜 필요한지가 없었다.
호출 비용 · 결정론 · 망분리가 한 문제이고 도메인 소형 모델이 그 셋의 공통 답이다.

@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/4 오후 ~ 9/5 — 승인 넷을 밀었고 F-DET-001 3단계가 났다

main   3da6b2b · ai-service 847 · eval 68
내 것   #398 859(배선까지) · #397 856 · #390 849
❗CI    9/4 13:23 부터 전면 정지 — **계정 결제**(#394). 그 뒤로 실행 0

머지한 넷 — 전부 로컬 시험 머지로 결과를 먼저 봤다

706da5d  #387  종결어미 누설 측정 스크립트 (정세현)   → #388 의 전제
c469324  #396  링크 조건이 둘이 아니라 셋이다         → main 빨강 해소
13a9395  #388  누설 수치 정본 — 내 57%·26% 정정      4파일 +83
3da6b2b  #391  차감이 두 층이 아니라 세 층 + #392     3파일 +75

#297 에서 PR 화면 디프와 머지 결과가 달랐던 전례 때문에 전부 git merge --no-commit
으로 확인하고 밀었다.
--subject 도 전부 줬다 — #379wip: 제목으로 남은 자리다.

#391 을 밀기 전에 #388 이 인용한 누설 수치가 안 흔들리는지 재측정했다(34행 · 56% · 65% 그대로). 두 PR 이 같은 dev set 파일에 걸려 있어 순서가 중요했다.

❗내가 낸 수치가 틀렸다 — #387#388

#38595% 를 철회하면서 그 숫자를 베껴 간 자리 셋을 안 고쳤고, 내가 대신 적어 넣은
값 둘도 틀렸다
(정세현이 #387 에서 찾음).

정세현 라벨 70쌍   기준선 34%   54%  (1.6배)   ← 내가 #385 에 적은 것은 57%
dev set 34행       기준선 56%   65%  (1.2배)   ← 내가 적은 것은 26%

dev set 값은 방향이 반대였다. 26%"누설을 없앴다" 로 읽히는데 실측은 기준선의
1.2배로 여전히 누설이다. 원인이 Counter.most_common동률 삽입순 의존이고, 내가
#385 를 쓸 때 쓴 계산이 정확히 그 꼴이었다.

백분율을 적을 때 그 값을 내는 스크립트를 같이 적는다. #388 의 새 가드가 그것이다.

❗정세현이 #391 에서 선행 결함을 찾았다 (#392)

내 요소 ① 이 보증비용 의 차감 대상을 원문과 반대로 적고 있었다. 원문 대조했고 지적이
맞다. 그리고 내 오류가 지적보다 넓었다.

p13·p15  "납입한 보험료에서 계약체결비용 및 계약관리비용을 차감한 후 특별계정으로 투입"
p12      "최저사망지급금 보증비용은 … 연금계약 계약자적립액에서 차감됩니다"
p10      "계약체결·계약관리비용이란 … **보험료 중 일정비율을 책정**한 것"

「보험료 중 일정비율로 책정」과 「보험료에서 차감」을 내가 뭉갰다. 오탐 방향이라
원문대로 맞게 말한 고객이 U2 로 떨어진다.

고치다 한 번 더 틀렸다 — 문면을 "보증비용 2종" 으로 줄였더니 정작 #392 가 근거로 든
p12 문장이 덮임 0.24 로 임계(0.25) 아래가 됐다. 원문 이름 둘을 실으니 0.54 로 올라가고
p13·p15 도 같이 덮였다. 사각 73 → 65.

요소는 채점 기준이면서 동시에 앵커다. 문면을 고칠 때 그게 무엇을 덮고 있었는지 재고 고친다.

#395 리뷰 — 트립와이어가 울려도 조치하면 안 되는 경우가 있다

정세현이 #284 (a) 를 여는 근거를 찾아왔다(상품요약서 p2, 인용이 축자로 실재하는 것 대조).
내 트립와이어가 울렸다. 승인했지만 「남은 셋」의 1번(링크 걸기)을 보류했다.

"보험료 전액이 예금자보호 대상은 아니라고 하셨죠"   ← 맞는 말 (부정문)
   → M11  ngram 0.650   → 링크까지 걸고 돌리니  U1 → U4

#57 이 변액에서 M02 를 뺀 그 실패가 유형 ID 만 바뀌어 돌아왔다. 패턴을 줄여도
0.625 로 임계 위고, 점수가 최댓값이라 패턴을 더하면 오탐이 올라가기만 한다.

내 격리 계산이 런타임과 달랐다textsim 직접 호출은 0.500, 실물 매처는 0.625.
그래서 #396 의 헬퍼는 매처를 인자로 받는다.

#396 — 조건이 둘에서 셋이 됐다

(1) 변액을 덮는 유형이 생긴다
(2) 인용 가능한 근거를 가진다
(3) ❗부분적으로 참인 발화와 갈린다      ← 빠져 있었다

전 판은 (1) 만 보고 "링크를 걸라" 고 지시했다. 그대로 했으면 실패를 되살렸다.
unlinked_until.reason"stage=pattern 이라 안전" 문면도 틀렸다 — floor 는 stage
안 읽는다(정세현 지적).

내 새 그물에 내가 막으려던 구멍이 있었다 — 모집단을 비우는 변조가 전건 초록이었다
({} == set(())). 크기 단정을 더해 고쳤다.

★ F-DET-001 3단계 — 원안이 틀렸고 실측이 세 번 자리를 밀었다 (#397·#398)

대조 앵커가 일반화 안 됐다 — 내 #283 결론이 틀렸다

#283 에서 "임베딩은 안 되고 대조 앵커는 된다" 로 닫았는데 표본이 2유형 11건이었다.

                오해            맞음               간격
M09   +0.379 +0.116   -0.379 -0.620              +0.104   ✅
M11   +0.288 +0.164   ❗+0.051 ❗+0.170            -0.006   ❌ 겹친다

M09 에서 됐던 이유는 오해와 정답의 「내용」이 달라서였다. M11 은 같은 명제의 부정만
다르다 — anti 를 고객 화법 부정문으로 바꾸니 더 나빠졌다(3/10).

같은 실패를 세 번 쟀다: n-gram(#203) · 임베딩(#283) · 대조 앵커(9/5).
주제를 재는 어떤 수단으로도 극성은 안 갈린다.

그래서 3단계는 「빼는 층」이다

1·2단계가 만든 후보에만 극성을 직접 묻는다. 후보를 만들지 않으므로 stage 는 그대로 둔다.

holds 만            1/9 · 0/9 · 0/9      ← 회차마다 갈린다
holds AND polarity  0/9 · 0/9 · 0/9      ← 3회 동일

갈린 회차가 polarity="negative" 인데 holds=True 라는 자기모순이었다. "모델 출력을
그대로 믿지 않는다"
한 응답 안에서 적용하는 자리다. 덕분에 오해 문장을 데이터로 안
만들어도 된다 — 매칭된 패턴을 그대로 쓴다(claim 필드를 만들면 되지만 그 파일은 정세현 소유).

❗배선 2차가 위험했다 — 초록인데 LLM 을 부르고 있었다

1차  match() 안 · 채점 클라이언트 공유   30 failed
2차  라우트에서 주입                    856 passed 인데 **4초 → 17초**
3차  판정 직전 · 같은 클라이언트         859 passed · 4.32초

전건 초록이라 그대로 낼 뻔했다. 배선 전 브랜치와 시간을 비교해서 실제 호출임을 확인했다.
초록은 「LLM 을 안 불렀다」를 증명하지 않는다. --durations 로 잰다.

자리가 판정 직전인 이유가 둘 — 채점 호출 여야 #281 의 seed 배선이 안 밀리고,
apply_misconception_floor 이어야 오탐을 막는다.

판단 하나를 뒤집었다

/internal/misconception 은 게이트를 안 태운다. 처음엔 "두 경로가 다르면 감사에서
갈린다"
로 둘 다 걸었는데, 갈리는 게 아니라 재는 것이 다르다.

/misconception  "어느 패턴과 겹치는가"   결정론적 측정 · 조회
/score          "오해가 있는가"          판정 입력 · floor 가 U4 확정

#393 을 중복으로 닫았다 — 원인은 계정 결제

정세현의 #394 가 같은 분(13:33)에 올라왔고 원인까지 확정했다.

The job was not started because recent account payments have failed
or your spending limit needs to be increased.

내가 못 꺼낸 문면이다. logs 만 두드리다 404(BlobNotFound)만 보고 "짚이는 것" 으로
남겼는데, 잡이 안 뜬 경우 로그는 애초에 없고 사유는 check-runs/<job>/annotations 에 있다.

그 밖에 — #382 는 전원 승인인데 가드가 낡아 막혀 있다

07:18 마지막 커밋 → 07:37 강희진 승인(가드가 여기서 멈춤) → 08:19·09:01·12:32 승인 셋 더
mergeStateStatus = DIRTY   충돌 1파일(AggregateService.java) · main 보다 11커밋 뒤

CLAUDE.md 가 적어 둔 그 경로다(충돌 상태면 pull_request_review 이벤트가 유실된다).
오준서에게 알렸다 — 충돌을 풀어 푸시하면 synchronize 로 저절로 낫는다.

#389 는 내가 #388 브랜치 위에서 갈라서 닫고 #390 으로 다시 냈다(2파일).

다음

❗#394  CI 계정 결제 — 오준서. 모든 것의 병목
❗#386  alpha 채점 미확인 — 공모전 남은 위험 하나
 #398→#397  스택 리뷰 (정세현) · #390 (강희진)
 #284 (a)   게이트가 조건 (3) 을 실제로 푼다. 링크는 **판정을 바꾸는 변경**이라 별 PR —
            조건 (3) 재측정 + 트립와이어 문면 갱신을 같이

yoonjiseok pushed a commit that referenced this pull request Sep 5, 2026
③(keep 방향)을 공식 코퍼스로 쟀는데 **측정이 안 된다** — 합의 U4 19건에서 1·2단계가 후보를
0건 만든다. 게이트가 탈 입력 자체가 없다.

그래서 dev set 의 30/30 keep 을 "미탐 0" 으로 읽으면 안 되고 「잴 자리가 없다」가 맞다.
표본이 10건이라는 것도 같이 적었다 — #283 에서 11건으로 방법을 확정했다가 M11 에서 무너진
전례가 있고, 그 자기 인용이 이 숫자의 무게를 재게 한다.

정세현 진단을 문면에 넣었다: 원인은 임계값이 아니라 **패턴의 화법 폭**이다. 패턴이 데모
대본 한 줄에서 나왔고 조정례의 화법 폭이 아니라서, 같은 오해를 한 겹 돌려 말하면 떨어진다.

  데모 발화  "은행에서 파니까 원금은 보장되는 거죠"        pattern 1.00
  els-0004   "그래도 은행 창구에서 파는 건데, 최소한…"      ngram  0.179

#377(표본의 화법 폭)과 같은 뿌리, 반대 방향이다. 임계값을 내리면 #203 이 잡은 오탐이
돌아오므로 답이 아니다 — 데이터는 정세현 소유이고 #284 로 갔다.

❗숫자를 한 번 틀렸다가 고쳤다. sample_id 로만 dict 를 만들어 67/18 로 읽었는데, 같은
sample_id 가 두 항목으로 채점돼 있어 3건이 덮였다. 키는 (sample_id, item_id) 다 —
run_eval 과 같은 51/19 가 나온다. 그래서 build_polarity_sample.py 가 run_eval 의
aligned·load_labelers 를 그대로 부르는 설계가 맞다(정세현).

Refs #397 · #284 · #377 · #283
yoonjiseok added a commit that referenced this pull request Sep 5, 2026
* feat(F-DET-001): 3단계는 「더 잡는 층」이 아니라 「잘못 잡은 것을 빼는 층」이다 — 극성 게이트

docstring 이 3단계를 "임베딩 유사도로 붙일 예정" 이라 적어 뒀는데 실측으로 반증됐다.
같은 실패를 세 번 쟀다 — 한국어는 부정·양보가 어미에 붙어서 오해와 그 부정은 주제가 같고,
주제를 재는 수단은 전부 같은 곳에서 무너진다.

  #203  n-gram        어간까지만 자른 조각이 오해와 부정을 못 가른다
  #283  임베딩 코사인  M09 에서 정답(0.621)이 어미변형(0.560)보다 높다
  9/5   대조 앵커      M09 는 갈리는데(간격 +0.104) M11 은 겹친다(-0.006)

대조 앵커가 M09 에서 됐던 이유는 오해와 정답의 **내용**이 달라서였다. M11 은 같은 명제의
부정만 다르다 — pro·anti 앵커가 둘 다 같은 주제라 margin 이 잡음(±0.05)이 된다.

그래서 극성을 직접 묻는다. 1·2단계가 만든 후보만 검사하고, 후보를 만들지는 않는다.

❗두 필드가 합의할 때만 남긴다. holds 만 보면 비결정적이었다 — 같은 입력 3회 중 1회가
polarity="negative" 인데 holds=True 라는 자기모순으로 갈렸다.

  holds 만            1/9 · 0/9 · 0/9
  holds AND polarity  0/9 · 0/9 · 0/9

덕분에 오해 문장을 데이터로 안 만들어도 된다 — 매칭된 패턴을 그대로 쓴다. 명제형 문장을
쓰면 holds 만으로도 3회 0/9 였지만 라이브러리에 새 필드가 필요하고 그 파일은 정세현 소유다.

게이트가 죽으면 후보를 남긴다(P5 0.2절 — 미탐이 과탐보다 비싸다). client=None 이면
3단계가 아예 안 돈다 — 기존 호출자 둘의 동작은 그대로다.

변조 넷으로 역검증: 합의 규칙 제거 2 failed · 실패 시 삭제 1 · 게이트 미호출 5 ·
라벨을 오해 문장으로 1.

Refs #284 · #283 · #203 · #395

* fix(F-DET-001): 극성 게이트 로그에서 고객 발화를 뺀다 — type_id 로 되짚는다 (#397 리뷰 ①)

정세현 지적. 로그 네 줄이 utterance[:40] 을 싣고 있었고, 실패 경로만이 아니라 **정상 경로도
후보마다 매번** INFO 로 남았다.

결정 4.8 이 폴백 로그에 누출 조각을 허용한 근거는 'QuestionRequest 에 고객 발화 필드가 아예
없고 조각의 출처가 상품문서·루브릭' 이었다. 여기는 그 근거가 통째로 없다 — 싣는 것이 고객
발화 자체다. P3 마스킹은 성명·주민번호를 지우는 것이지 발화를 지우는 게 아니고, 원문 보존
정책(F-GTE-004)은 evidence/ 에만 걸리므로 로그로 나가면 정책 밖에 사본이 하나 생긴다.

type_id 로 바꿨다 — '어느 발화였나' 는 세션ID·항목ID 로 되짚는 것이 원래 경로다.

Refs #397

* docs(F-DET-001): 3단계가 임계 경로를 지난다는 것을 문면에 적는다 — 약속을 낮추고 잰 값을 붙인다 (#397 리뷰 ②)

docstring 이 "데모 발화가 2단계까지에서 잡혀야 한다. LLM 에 의존하면 임계 경로가 비결정적이
된다" 고 적어 뒀는데, 이 층이 생기면서 그 문장이 거짓이 됐다(정세현 지적).

ngram 단계에만 걸어 결정론을 지키는 안을 냈다가 실측으로 철회했다 — 패턴을 축자로 담은
부정문이 pattern 1.00 으로 잡히고 게이트가 3/3 으로 뺀다. **부정하는 발화일수록 패턴을
축자로 담는다**(부정이 어미에 붙어 앞부분이 그대로 남는다). 그 자리를 빼면 이 층을 만든
이유가 없어진다.

❗공식 코퍼스에서는 이 층이 아예 안 돈다 — 합의 U4 19건에서 1·2단계 후보가 0건이다
(pattern 0 · ngram 0, 최고 점수 0.02~0.28 vs 임계 0.62). 그래서 dev set 의 30/30 keep 을
"미탐 0" 으로 읽으면 안 된다. **「잴 자리가 없다」이지 「안전하다」가 아니다** — dev set 은
패턴에서 유도된 표본이라 후보가 잘 생기는 쪽으로 치우친다.

그 0건은 이 파일보다 넓은 사실을 말한다: 강제되는 라이브러리 9종이 공식 코퍼스에서 한 번도
발동하지 않는다. 오해 판정은 지금 전적으로 LLM 이 하고 floor 는 패턴을 그대로 담은 발화에서만
운다 — #284 가 가리키는 공백이다.

Refs #397 · #284

* docs(F-DET-001): 3단계가 실측 코퍼스에서 한 번도 안 돈다는 것을 문면에 적는다 (#397 리뷰 ③)

③(keep 방향)을 공식 코퍼스로 쟀는데 **측정이 안 된다** — 합의 U4 19건에서 1·2단계가 후보를
0건 만든다. 게이트가 탈 입력 자체가 없다.

그래서 dev set 의 30/30 keep 을 "미탐 0" 으로 읽으면 안 되고 「잴 자리가 없다」가 맞다.
표본이 10건이라는 것도 같이 적었다 — #283 에서 11건으로 방법을 확정했다가 M11 에서 무너진
전례가 있고, 그 자기 인용이 이 숫자의 무게를 재게 한다.

정세현 진단을 문면에 넣었다: 원인은 임계값이 아니라 **패턴의 화법 폭**이다. 패턴이 데모
대본 한 줄에서 나왔고 조정례의 화법 폭이 아니라서, 같은 오해를 한 겹 돌려 말하면 떨어진다.

  데모 발화  "은행에서 파니까 원금은 보장되는 거죠"        pattern 1.00
  els-0004   "그래도 은행 창구에서 파는 건데, 최소한…"      ngram  0.179

#377(표본의 화법 폭)과 같은 뿌리, 반대 방향이다. 임계값을 내리면 #203 이 잡은 오탐이
돌아오므로 답이 아니다 — 데이터는 정세현 소유이고 #284 로 갔다.

❗숫자를 한 번 틀렸다가 고쳤다. sample_id 로만 dict 를 만들어 67/18 로 읽었는데, 같은
sample_id 가 두 항목으로 채점돼 있어 3건이 덮였다. 키는 (sample_id, item_id) 다 —
run_eval 과 같은 51/19 가 나온다. 그래서 build_polarity_sample.py 가 run_eval 의
aligned·load_labelers 를 그대로 부르는 설계가 맞다(정세현).

Refs #397 · #284 · #377 · #283

* feat(F-DET-001): 극성 게이트가 무엇을 했는지 센다 — 0건과 「모른다」를 가른다 (#398 리뷰 ①②)

정세현 지적. #160 에서 내가 세운 규칙의 **반대 방향**이었다.

  > 조용히 등급만 바뀌면 감사 시점에 왜 U4 였는지 설명할 수 없다

U4 가 「안 된」 경우에도 똑같다.

  floor 가 울면   reason 에 상향 사실 · misconception_type   → evidence 에 남는다
  게이트가 빼면   평범한 U1~U3 · 필드 없음 · INFO 한 줄       → 아무 데도 안 남는다

로그는 evidence 가 아니다(ADR-003 — append-only · 해시 체인 · 정규화 직렬화). evidence 에
넣는 것은 계약 변경이라 이 PR 에서 안 한다 — 대신 계량기를 둔다. 집계·리포트는 #326·#327
에서 정세현이 붙인다(그쪽 몫이라 자리만 연다).

❗not_run 이 dropped == 0 과 다른 것이 요점이다. shadow.ShadowMeter.failed 와 같은 자리이고
결정 5.40("못 잰 값은 0 이 아니라 「모른다」로 적는다") 이다. 게이트가 조용히 영구히 안 도는
경로가 둘인데(LLM 예외 · 클라이언트가 model_cls 를 안 지킴) 둘 다 후보를 남기므로 판정만
보면 게이트가 없는 것과 구별되지 않는다 — ②가 지적한 그것이다.

자기모순(holds=True 인데 polarity 가 긍정이 아님)을 따로 센다. 실측에서 3회 중 1회 나왔고,
그 비율이 오르면 프롬프트가 흔들리는 신호다.

발화를 안 담는다 — #397 리뷰 ①에서 로그의 발화를 뺀 것과 같은 이유다(P3 · F-GTE-004 보존
정책 밖에 사본이 생긴다). 테스트가 by_type 키가 유형ID 인 것을 잠근다.

변조 셋: not_run 미기록 2 failed · 자기모순 미분리 1 failed · 계량기에 발화 담기 2 failed.

Refs #398 · #397 · #160 · #326 · #327 · 결정 5.40

---------

Co-authored-by: 윤지석 <yunjiseok@yunjiseog-ui-MacBookPro.local>
yoonjiseok added a commit that referenced this pull request Sep 5, 2026
* feat(F-DET-001): 3단계는 「더 잡는 층」이 아니라 「잘못 잡은 것을 빼는 층」이다 — 극성 게이트

docstring 이 3단계를 "임베딩 유사도로 붙일 예정" 이라 적어 뒀는데 실측으로 반증됐다.
같은 실패를 세 번 쟀다 — 한국어는 부정·양보가 어미에 붙어서 오해와 그 부정은 주제가 같고,
주제를 재는 수단은 전부 같은 곳에서 무너진다.

  #203  n-gram        어간까지만 자른 조각이 오해와 부정을 못 가른다
  #283  임베딩 코사인  M09 에서 정답(0.621)이 어미변형(0.560)보다 높다
  9/5   대조 앵커      M09 는 갈리는데(간격 +0.104) M11 은 겹친다(-0.006)

대조 앵커가 M09 에서 됐던 이유는 오해와 정답의 **내용**이 달라서였다. M11 은 같은 명제의
부정만 다르다 — pro·anti 앵커가 둘 다 같은 주제라 margin 이 잡음(±0.05)이 된다.

그래서 극성을 직접 묻는다. 1·2단계가 만든 후보만 검사하고, 후보를 만들지는 않는다.

❗두 필드가 합의할 때만 남긴다. holds 만 보면 비결정적이었다 — 같은 입력 3회 중 1회가
polarity="negative" 인데 holds=True 라는 자기모순으로 갈렸다.

  holds 만            1/9 · 0/9 · 0/9
  holds AND polarity  0/9 · 0/9 · 0/9

덕분에 오해 문장을 데이터로 안 만들어도 된다 — 매칭된 패턴을 그대로 쓴다. 명제형 문장을
쓰면 holds 만으로도 3회 0/9 였지만 라이브러리에 새 필드가 필요하고 그 파일은 정세현 소유다.

게이트가 죽으면 후보를 남긴다(P5 0.2절 — 미탐이 과탐보다 비싸다). client=None 이면
3단계가 아예 안 돈다 — 기존 호출자 둘의 동작은 그대로다.

변조 넷으로 역검증: 합의 규칙 제거 2 failed · 실패 시 삭제 1 · 게이트 미호출 5 ·
라벨을 오해 문장으로 1.

Refs #284 · #283 · #203 · #395

* feat(F-DET-001): 극성 게이트를 판정 직전에 건다 — 배선 (#397 후속)

게이트를 `apply_misconception_floor` **바로 앞**에 건다. 자리가 여기인 이유가 둘이다.

  ① 채점 호출 **뒤**여야 한다 — 앞에 두면 게이트가 첫 LLM 호출이 되고 #281 이 고정한
    "첫 시도는 설정 seed 그대로" 가 밀린다. 실제로 그렇게 짰다가 세 테스트가 갈렸다.
  ② floor **앞**이어야 한다 — 거기서 U4 가 확정되고 오탐의 값이 거기서 발생한다.

`match()` 에서 게이트를 떼어 `apply_polarity_gate()` 로 갈랐다. `escalate` 를 다시 계산한다 —
게이트가 M08-TYING 후보를 빼면 그 신호도 같이 사라져야 한다.

❗**세 번 자리를 옮겼고 다 실측이 밀었다.**

  1차 `match()` 안 · scoring 클라이언트 공유   30 failed — 스텁이 model_cls 를 안 지킨다
  2차 라우트에서 주입                          856 passed 인데 **4초 → 17초**.
                                              라우트 테스트가 실제 LLM 을 불렀다
  3차 판정 직전 · 같은 클라이언트               859 passed · 4.32초

응답 타입이 PolarityVerdict 가 아니면 게이트가 안 돈 것으로 보고 후보를 남긴다(P5 0.2절).
주입 스텁이 그 경로라 단위 테스트가 LLM 을 안 부른다.

❗`/internal/misconception` 은 게이트를 안 태운다. 그 엔드포인트가 답하는 질문은
"이 발화가 어느 패턴과 겹치는가" 라는 결정론적 측정이고, 기획서 5절이 재현성을 그 성질로
설명한다. 게이트는 판정 입력에만 건다.

test_scoring.py 의 두 단정이 스텁 호출을 전부 세고 있었다 — schema_name 으로 채점 호출만
세게 고쳤다. 뜻이 "재판정 횟수" 이므로 그게 원래 의도다.

변조: 배선 끊기 2 failed · 게이트를 앞으로 1 failed(전체에서는 5).

Refs #397 · #284 · #281

* fix(F-DET-001): 극성 게이트 로그에서 고객 발화를 뺀다 — type_id 로 되짚는다 (#397 리뷰 ①)

정세현 지적. 로그 네 줄이 utterance[:40] 을 싣고 있었고, 실패 경로만이 아니라 **정상 경로도
후보마다 매번** INFO 로 남았다.

결정 4.8 이 폴백 로그에 누출 조각을 허용한 근거는 'QuestionRequest 에 고객 발화 필드가 아예
없고 조각의 출처가 상품문서·루브릭' 이었다. 여기는 그 근거가 통째로 없다 — 싣는 것이 고객
발화 자체다. P3 마스킹은 성명·주민번호를 지우는 것이지 발화를 지우는 게 아니고, 원문 보존
정책(F-GTE-004)은 evidence/ 에만 걸리므로 로그로 나가면 정책 밖에 사본이 하나 생긴다.

type_id 로 바꿨다 — '어느 발화였나' 는 세션ID·항목ID 로 되짚는 것이 원래 경로다.

Refs #397

* docs(F-DET-001): 3단계가 임계 경로를 지난다는 것을 문면에 적는다 — 약속을 낮추고 잰 값을 붙인다 (#397 리뷰 ②)

docstring 이 "데모 발화가 2단계까지에서 잡혀야 한다. LLM 에 의존하면 임계 경로가 비결정적이
된다" 고 적어 뒀는데, 이 층이 생기면서 그 문장이 거짓이 됐다(정세현 지적).

ngram 단계에만 걸어 결정론을 지키는 안을 냈다가 실측으로 철회했다 — 패턴을 축자로 담은
부정문이 pattern 1.00 으로 잡히고 게이트가 3/3 으로 뺀다. **부정하는 발화일수록 패턴을
축자로 담는다**(부정이 어미에 붙어 앞부분이 그대로 남는다). 그 자리를 빼면 이 층을 만든
이유가 없어진다.

❗공식 코퍼스에서는 이 층이 아예 안 돈다 — 합의 U4 19건에서 1·2단계 후보가 0건이다
(pattern 0 · ngram 0, 최고 점수 0.02~0.28 vs 임계 0.62). 그래서 dev set 의 30/30 keep 을
"미탐 0" 으로 읽으면 안 된다. **「잴 자리가 없다」이지 「안전하다」가 아니다** — dev set 은
패턴에서 유도된 표본이라 후보가 잘 생기는 쪽으로 치우친다.

그 0건은 이 파일보다 넓은 사실을 말한다: 강제되는 라이브러리 9종이 공식 코퍼스에서 한 번도
발동하지 않는다. 오해 판정은 지금 전적으로 LLM 이 하고 floor 는 패턴을 그대로 담은 발화에서만
운다 — #284 가 가리키는 공백이다.

Refs #397 · #284

---------

Co-authored-by: 윤지석 <yunjiseok@yunjiseog-ui-MacBookPro.local>
@yoonjiseok

Copy link
Copy Markdown
Contributor Author

9/5 — CI 가 살아나고 실문서 흐름이 하루에 섰다. F-DET-001 3단계 완료

main   b0798fe+ · ai-service 939 · eval 76
CI     ✅ **레포를 공개로 전환하자 #394(계정 결제) 해소** — 공개 레포는 Actions 무료
라이브 채점  ✅ alpha 200 확인 (#386, 오준서 03:34) · prompt_version=v3 · P4 섰다
prod   ❌ demo-* 0개 — 데모에서 쓰는 건 여기다 (10.68)

하루에 팀이 25건 넘게 밀었다. 내 몫은 아래 넷이고 나머지는 리뷰였다.

내 PR 넷이 나갔다

#397 04:27  극성 게이트 (F-DET-001 3단계)
#423 04:34  게이트를 판정 직전에 배선
#418 04:15  내 텍스트 자산 NFC 그물
#425 04:57  VAR-PARTIAL 에 M11 링크 → **#284 가 3주 만에 닫혔다**
#426 05:49  종결어미 누설이 나빠지면 빨개진다 (#377 ①)

★ F-DET-001 3단계 — 원안이 틀렸고 실측이 세 번 방향을 밀었다

#283 의 앞 코멘트에서 내가 "임베딩은 안 되고 대조 앵커는 된다" 로 닫았다.
그 결론이 틀렸다. 표본이 2유형 11건이었다.

                오해            맞음               간격
M09   +0.379 +0.116   -0.379 -0.620              +0.104   ✅
M11   +0.288 +0.164   ❗+0.051 ❗+0.170            -0.006   ❌ 겹친다

M09 에서 됐던 이유는 오해와 정답의 「내용」이 달라서였다(팔 수 있다 ↔ 상장이 안 됐다).
M11 은 같은 명제의 부정만 다르다. anti 를 고객 화법 부정문으로 바꾸니 더 나빠졌다(3/10).

같은 실패를 세 번 쟀다: n-gram(#203) · 임베딩(#283) · 대조 앵커(9/5).
주제를 재는 어떤 수단으로도 극성은 안 갈린다.

그래서 3단계는 「빼는 층」이다

1·2단계가 만든 후보에만 극성을 직접 묻는다. 핵심은 두 필드 합의 규칙이다.

holds 만            1/9 · 0/9 · 0/9      ← 회차마다 갈린다
holds AND polarity  0/9 · 0/9 · 0/9      ← 3회 동일

갈린 회차가 polarity="negative" 인데 holds=True 라는 자기모순이었다 —
"모델 출력을 그대로 믿지 않는다"한 응답 안에서 적용하는 자리다. 덕분에 오해 문장을
데이터로 안 만들어도 됐다(매칭된 패턴을 그대로 쓴다).

❗배선 자리를 세 번 옮겼다 — 2차가 위험했다

1차  match() 안 · 채점 클라이언트 공유   30 failed
2차  라우트에서 주입                    856 passed 인데 **4초 → 17초** ← 라우트 테스트가 실제 LLM 호출
3차  판정 직전 · 같은 클라이언트         859 passed · 4.32초

2차는 전건 초록이라 그대로 낼 뻔했다.초록은 「LLM 을 안 불렀다」를 증명하지 않는다.
--durations 로 잰다.

리뷰에서 받은 지적 — 셋 다 내 규칙의 반대편이었다

#397 ① 로그가 고객 발화를 싣는다      → type_id 로 바꿈. 전수 grep 0
#398 ① 게이트가 뺐다는 사실이 안 남는다 → PolarityMeter. **#160 에서 내가 세운 규칙의 반대 방향**
#398 ② not_run 이 0건과 같아 보인다   → **#364 에서 내가 넣게 한 record_failure() 를 내가 잊었다**
#425   「걸려 있는 것」과 「도는 것」은 다르다 → 게이트 실패 회차에 U4 확정. 실측 재현 후 문면

#425 가 특히 아프다. 게이트를 P5 방향으로 fail-open 하게 만든 것이 나인데, 그 선택이
링크와 만나면 오탐을 만든다
는 것을 못 봤다 — 두 결정이 각자 맞고 합치면 성질이 바뀐다.

❗내가 낸 수치가 또 틀렸다 (#421)

sample_id 키:  총 67 · 합의 U4 18   ← 내가 적은 것
(id,item) 쌍:  총 70 · 합의 U4 19   ← 정본

같은 발화의 다른 항목 라벨 3건이 접혔다. 내가 "코퍼스 67건" 이라 적은 것이 이미
증상이었다(실제 70건). #388 에서 세운 "재현 스크립트의 출력을 옮겨 적는다"내가
손으로 읽어서
어겼다.

다만 정본 19건으로 재도 후보 0건이라 결론은 유지된다 — 수치는 틀렸고 판단은 맞았다.

#410 MySQL — 내 방어선의 범위가 드러났다

10.2.1 이 내 _canonical()"유일한 방어선" 으로 지목했는데, 그것이 막는 것은 대조이지
저장이 아니다.

NFD 입력 → 저장될 utterance_quote: NFD ❗ (len 6 → 15, 눈으로는 같다)

파이프라인 전수(25파일)가 NFC 라 방아쇠는 안 당겨져 있다 → 승인하고 #418사실을
제약으로
바꿨다. @Lob 결함(tinytext 255B)이 내 채점이 지나는 트랜잭션이었다는 것도
그 PR 의 수확이다 — #386 이 어제 첫 200 을 냈는데 MySQL 이었으면 500 이었다.

오늘 낸 실수 — 브랜치·백업이 넷

① #389 를 #388 브랜치 위에서 갈랐다
② NFC 그물이 #398 브랜치 위에 얹혔다
③ git checkout -B 가 미커밋 변경을 날렸다 (테스트 파일은 백업이 없어 다시 씀)
④ 메모를 슬라이스로 고치다 1559줄 → 480줄 (cp 백업에서 복구)

브랜치를 옮기기 전에 커밋하거나 cp 백업을 뜬다. checkout -B-b 와 다르다.
그리고 리뷰는 명명된 로컬 브랜치에 고정한다 — 다른 세션이 main 을 움직이면 detached
HEAD 가 밀려서 파일이 사라진 것처럼 보인다(세 번 겪었다).

남은 것

❗prod        demo-* 0개 — 데모에서 쓰는 건 여기다
#410 · #420  내 변경요청 대기 (canonical_version 이 V1__init.sql 에 없다)
#409         model.jsonl v2 → v3 재생성 (정세현)
#377 · #367  내 이슈, 미해소
#439         강희진 PR — #435(내 담당) 를 고친다. 리뷰 대기
#436         ELS-MATURITY-LOSS-CONDITION 추출 실패가 S-04 를 막는다 (내 담당, 새 건)

@gitIt-sehyeon

Copy link
Copy Markdown
Contributor

@yoonjiseok — 인계 노트 머리의 이 줄만 정정한다. 내일 누가 이걸 읽고 prod 를 세우려 할 수 있어서 남긴다(노트에 리뷰는 안 단다).

prod   ❌ demo-* 0개 — 데모에서 쓰는 건 여기다 (10.68)

10.68 의 앞부분만 인용됐고 뒷부분이 그 문장을 뒤집는다.

데모에서 쓰는 것은 prod 다질문이 사라졌다(#360). 데모를 alpha 개방 모드로 가기로 정하면서 prod 를 안 세운다(7.44) — demo-* 태그를 밀 대상 자체가 없다(IAM 역할·EC2·SSM 전부 0건 실측). 즉 "한 번도 안 돌았다" 가 결함이 아니라 의도한 상태가 됐다.

#360 은 어제 05:52 에 머지됐다. 7.44 도 같이 서 있다.

데모는 alpha 개방 모드로 간다 — prod 는 안 세운다. 역할 차단은 로컬 compose(잠금이 기본값) 로 따로 보여준다. 심사위원 무로그인 관람이 우선이고, 개방 모드와 역할 차단 시연은 서로 배타적이다.

prod ❌결함이 아니라 결정이다. 세울 대상이 없고 세울 이유도 없다.

그래서 오늘 alpha 에서 한 것이 데모 대상이 맞다

내가 오늘 alpha 에 실추출을 돌렸고(ELS 13 · 변액 10), 그게 데모에서 쓰는 그 환경이다. 만약 prod 가 대상이었으면 그 작업이 전부 헛것이 될 뻔했다.

같이 적어 둘 것 하나 — 역할 차단 시연은 alpha 에서 안 된다. 개방 모드가 모든 방문자를 seller-01 로 만들고 /api/dashboard/…compl-01 을 실어 주므로 "SELLER 가 집계에 접근 → 차단" 장면이 성립하지 않는다. 7.44 가 그걸 로컬 compose(잠금 기본값) 로 따로 보여주기로 정해 뒀다. 리허설 시나리오에 그 갈래가 들어가 있는지 @junseo2323 이 확인해 주면 좋겠다.

나머지 노트 내용은 오늘 내가 본 것과 같다. #284 3주 만에 닫힌 것 축하한다 — (a) 의 조건 셋 중 (3)이 네가 오늘 만든 층이었다.

@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 9/2 작업 인계 — 리허설 전날 상태와 이어갈 것 [개인 노트 · 리뷰 불필요] 작업 인계 — 9/6 데모 경로 실측 (10회차) Sep 5, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 9/6 데모 경로 실측 (10회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 9/6 데모가 실물이 됐다 (11회차) Sep 5, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 9/6 데모가 실물이 됐다 (11회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 9/6 저녁 (12회차) Sep 5, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 9/6 저녁 (12회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 9/6 밤 (13회차) Sep 5, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 루브릭 자동화 ① 머지, 남은 건 prod (16회차) [개인 노트 · 리뷰 불필요] 작업 인계 — #409 의 0번이 채워졌다, 남은 건 prod (17회차) Sep 6, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — #409 의 0번이 채워졌다, 남은 건 prod (17회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 질문 폴백 93%→20%, 남은 건 prod (18회차) Sep 6, 2026
yoonjiseok added a commit that referenced this pull request Sep 6, 2026
* fix(F-DET-001): 극성 게이트가 «지금 믿는 것» 을 먼저 적고 판정한다 — 정정 발화가 U4 에서 빠져나온다 (#503)

## 증상 (alpha 재현)

    ① "은행에서 파는 거니까 원금은 지켜지는 거죠."                       → U4 ✅
    ② 재설명
    ③ "아, 예금자보호가 안 되는 상품이군요. 발행사가 잘못되면 원금을 못 받을 수 있다…"
                                                                     → ❗U4 (모델은 U1 로 봤다)

사유 문면: "…정확히 말했고 … 이해했다고 진술했기 때문. (오해 라이브러리 매칭 [ngram 0.7143])"
→ apply_misconception_floor 가 끌어올렸다. 재설명 뒤 고객이 고쳐 말해도 빠져나올 수 없었다.

## 기전

    1·2단계  «예금자보호가 «안» 되는» ↔ 패턴 «예금자보호 되는 줄»  ngram 0.714
             문자 바이그램은 「안」을 못 본다 (한국어 부정은 어간을 안 바꾼다)
    3단계    극성 게이트가 이걸 빼야 하는데 holds=True·positive → 유지 → floor → U4
             이 층은 정확히 이걸 막으려고 만든 것이다 (#397)

## 무엇을 고쳤나 — 두 가지, 둘 다 필요조건이다

    ① PolarityVerdict(BaseModel) → (Strict)
       additionalProperties:false 가 생겨 llm_client 가 strict:true 를 켠다 (#490 과 같은 뿌리).
       BaseModel 이면 모델이 스키마를 최선노력으로만 따른다.
    ② belief: str 를 **첫 필드**로 + 시스템 프롬프트에 "먼저 고객이 «지금» 믿는 것을 한 문장으로
       적고(고쳐 말한 것은 빼고), 그 다음 그 문장이 오해 문장과 같은 주장인지로 holds 를 정한다"
       구조화 출력은 필드를 순서대로 채우므로 이 한 단계가 판정 절차가 된다.

## 실측 (gpt-5-mini · 2026-09-06) — 무엇이 고쳤고 무엇이 아닌가

    문제 발화 (기대 False)     BaseModel         N=3   3/3 오판
                              Strict 만         N=3   0/3 → ❗N=10 6/10 오판   (3회는 운이었다)
                              Strict + belief   N=10  0/10
                              + 부정어 힌트      N=10  0/10                    (더한 것 없음)

    실물 match(client=) 끝까지 · 8케이스 × N=10 · 총 80회
      V2(이것)                 6/80 오판  — 정정·부정·범위제한·#395 M11 오탐·M02·M09 전부 0/10
      V4(+반문을 주장으로 지시)  12/80 오판 — M11 반문 0/10 이 되지만 정정 발화 4/10·M09 8/10 이 되돌아옴

    프롬프트에 「동사 앞 부정」 지시를 더한 것: 4/5 ↔ 4/5 로 실패를 옮길 뿐.
    임계값: 진짜 오해 최저 0.727 vs 이 오탐 0.714 — 1.3% 차이라 못 가른다.
    라벨(«예금자보호 오인»)을 오해 문장으로: 명제가 아니라 전부 True — 더 나쁘다.

## ❗잔여 — 정직하게

    진짜 오해 M11 반문형 «이것도 예금처럼 전액 보호되는 거 아닌가요»  (기대 holds=True)
      옛 게이트  10/10 오판 (전부 뺀다 — 미탐, P5 0.2절 방향)
                 ← #425 가 M11 을 링크할 때 게이트 없는 매처로만 재서 아무도 못 본 자리
      이것       6/10 오판 — 줄었지만 안 닫혔다
    회귀가 아니라 기존 미탐이고, 반문 지시(V4)로는 실패가 옮겨간다. 라이브러리에 명제형 claim 이
    생기면 다시 잰다 (#503 후속). docstring 에 표로 적었다.

## 그물

    test_the_verdict_schema_is_strict_eligible        Strict · required={belief,holds,polarity} · belief 가 첫 필드
    test_the_system_prompt_asks_for_the_current_belief_first   프롬프트가 지시를 든다 (필드와 한 벌)
    test_structured_output_strict EXPECTED             PolarityVerdict False → True (실제로 보내 봤다)
    변조 4/4  ⓐ BaseModel 되돌림 2 failed · ⓑ belief 제거 8 failed · ⓒ belief 마지막 필드 1 failed
              ⓓ 프롬프트 지시 제거 1 failed

    ❗belief 는 고객 발화에서 유도된 문장이다 — 로그에 싣지 않는다 (#397 ① · P3).

## docs/proposal.md — 이 기능에 맞춰 세 곳

    §4 핵심 엔진·오해 탐지   "오해는 「고쳤다」로 끝나야 한다" — 정정 발화가 빠져나오는 경로 한 줄
    §5 생성형 AI의 역할      "LLM 의미 유사도" → 실제 3단계(패턴 → n-gram → 극성만 판정·빼기만).
                            임베딩은 극성을 못 가른다는 실측으로 채택하지 않았다고 적음 (#283)
    §5 오판 처리 표          이해→오해 오판 행의 방어 장치에 극성 게이트 추가
    docs/ 는 정세현 소유 — 리뷰 요청.

## 검증

    ai-service 1040 passed (+1) · eval 84 · LLM 호출 없음(스텁이 belief 를 채운다)
    alpha 재현 세션: ad6243e9 (①②③ 그대로)

관련: #503 · #397 · #490(strict 의 뿌리) · #395·#425(M11) · #363(자기정정 축) · P5 0.2절 · P3

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(기획서): MVP 에서 실제로 쓴 공시문서 2건을 적는다

§5 [활용 데이터] 가 «수집처» 목록만 들고 있어서, 실제로 무엇을 쓴 문서인지가 문서
어디에도 없었다. 심사에서 «어떤 문서로 돌렸나» 를 물으면 답할 자리가 필요하다.

    ELS   간이투자설명서   16쪽 13,233자   이해항목 13(필수 10)   금투협 전자공시
    변액  상품요약서      18쪽 20,581자   이해항목 10(필수 7)    생보협 공시실

전부 실측이다 — 계약 샘플(parsed_*_sample.json)의 쪽·글자 수, alpha 의 risk-items 조회,
화면 표기는 GET /api/products 응답이다.

세 줄을 같이 적었다.
- 텍스트 레이어가 있어 OCR 없이 위치까지 짚는다 → P6(원문 인용) 이 성립하는 이유
- 변액 운용설명서는 «정답지 대조에만» 쓴다 — 상품요약서 하나로는 10종을 못 덮는다(ADR-007).
  런타임이 읽는 것은 2건이고 그 구별이 없으면 문서 수가 어긋나 보인다
  (ProductRiskItems:36-37 이 그 매핑)
- 가명 처리(A증권·B생명)는 화면에 실제로 그렇게 나간다

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(기획서): 「제출 전 5~10건 확인」을 MVP 범위 2건으로 고친다

미이행 계획이 현재형으로 남아 있었다 — 실제 문서는 2종이다. #505(v1.2)가 미구현을
미구현으로 적은 것과 같은 기준으로 맞춘다.

    전  "제출 전 동일 유형 문서를 5~10건 실제로 내려받아 파서의 형식 편차 대응 범위를 확인한다"
    후  "MVP 범위는 위 2건이다 … 파서는 이 두 문서의 표 구조에 맞춰 고쳐 왔으므로 다른 발행사
        서식에서의 형식 편차는 아직 재지 않았다 — … 넓히는 것은 다음 단계다"

❗«아직 재지 않았다» 를 적은 것이 요점이다. 파서를 이 두 문서에 맞춰 고쳐 온 것이 사실이고
(#452 표 칸 순서 · #458 같은 y 로 합쳐 온 칸 가르기), 그 사실을 안 적으면 «신상품에도 바로
붙는다»(§4)가 서식 편차까지 검증된 것으로 읽힌다. §4 는 «상품유형 템플릿» 축의 주장이고
여기는 «발행사 서식» 축이라 다른 말이다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: 윤지석 <yunjiseok@yunjiseog-ui-MacBookPro.local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 질문 폴백 93%→20%, 남은 건 prod (18회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 제출 뒤 실데이터 전환, 숫자 정정 다섯 (19회차) Sep 7, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 제출 뒤 실데이터 전환, 숫자 정정 다섯 (19회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰가 내 그물의 구멍을 찾아온 날 (20회차) Sep 7, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰가 내 그물의 구멍을 찾아온 날 (20회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 「고쳤다고 적힌 것이 실제로 안 고쳐지는」 형태를 다섯 번 봤다 (21회차) Sep 8, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 「고쳤다고 적힌 것이 실제로 안 고쳐지는」 형태를 다섯 번 봤다 (21회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 여섯이 머지됐고, 빨간 main 의 원인을 찾았다 (22회차) Sep 8, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 여섯이 머지됐고, 빨간 main 의 원인을 찾았다 (22회차) [개인 노트 · 리뷰 불필요] 작업 인계 — #562 착지, 내 이슈 제안이 반쪽이었다 (24회차) Sep 9, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — #562 착지, 내 이슈 제안이 반쪽이었다 (24회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 큐 0→6, 내 지적이 답 없이 머지됐다 (25회차) Sep 9, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 큐 0→6, 내 지적이 답 없이 머지됐다 (25회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 일곱, 내가 두 번 틀렸다 (26회차) Sep 9, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 일곱, 내가 두 번 틀렸다 (26회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 열하나, 중복 이슈를 냈다 (27회차) Sep 9, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 열하나, 중복 이슈를 냈다 (27회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 내 추론이 우연히 맞았다 (28회차) Sep 9, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 내 추론이 우연히 맞았다 (28회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 큐 0, 배정 이슈 일곱 (29회차) Sep 10, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 큐 0, 배정 이슈 일곱 (29회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 「받는 쪽」을 엔드포인트로 셌다 (30회차) Sep 10, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 「받는 쪽」을 엔드포인트로 셌다 (30회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 내가 뗀 이슈를 다음 PR 에서 했다 (31회차) Sep 10, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 내가 뗀 이슈를 다음 PR 에서 했다 (31회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 내 PR 둘 머지, #474 를 추적 이슈로 다시 굴렸다 (32회차) Sep 11, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 내 PR 둘 머지, #474 를 추적 이슈로 다시 굴렸다 (32회차) [개인 노트 · 리뷰 불필요] 작업 인계 — #456 을 냈고 내 판단 둘이 리뷰에서 뒤집혔다 (33회차) Sep 11, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — #456 을 냈고 내 판단 둘이 리뷰에서 뒤집혔다 (33회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 셋, #613 에 설계 질문 하나가 열려 있다 (34회차) Sep 11, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 셋, #613 에 설계 질문 하나가 열려 있다 (34회차) [개인 노트 · 리뷰 불필요] 작업 인계 — #613 반영, #617 새로 냄, 계약 하나를 물었다 (35회차) Sep 11, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — #613 반영, #617 새로 냄, 계약 하나를 물었다 (35회차) [개인 노트 · 리뷰 불필요] 작업 인계 — PR 셋 열림, 리뷰가 내 숫자 오류를 두 번 잡았다 (36회차) Sep 11, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — PR 셋 열림, 리뷰가 내 숫자 오류를 두 번 잡았다 (36회차) [개인 노트 · 리뷰 불필요] 작업 인계 — #617 머지, 리뷰가 내 오류를 세 번 잡았다 (37회차) Sep 11, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — #617 머지, 리뷰가 내 오류를 세 번 잡았다 (37회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 코드는 origin 브랜치 둘에 있다 · #617 머지 (38회차) Sep 11, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 코드는 origin 브랜치 둘에 있다 · #617 머지 (38회차) [개인 노트 · 리뷰 불필요] 작업 인계 — #619 머지 · 계약 승인 받음 · #613 만 남았다 (39회차) Sep 14, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — #619 머지 · 계약 승인 받음 · #613 만 남았다 (39회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 계약 승인 → 선행 #624 가 왔다 · #613 은 한 사람 (40회차) Sep 14, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 계약 승인 → 선행 #624 가 왔다 · #613 은 한 사람 (40회차) [개인 노트 · 리뷰 불필요] 작업 인계 — #625 승인(#598 닫힘) · #624 변경요청 · #613 은 여전히 (41회차) Sep 14, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — #625 승인(#598 닫힘) · #624 변경요청 · #613 은 여전히 (41회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 넷 · 심사 근거 #630 · 내 PR 은 그대로 (42회차) Sep 14, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 넷 · 심사 근거 #630 · 내 PR 은 그대로 (42회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 넷 · 심사 근거 #630 · #491 필드 누출 (43회차) Sep 14, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 리뷰 넷 · 심사 근거 #630 · #491 필드 누출 (43회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 조용한 회차. 답 둘만 냈다 (44회차) Sep 14, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 조용한 회차. 답 둘만 냈다 (44회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 내가 승인한 PR 이 내 문장을 낡게 만든다 (45회차) Sep 15, 2026
@yoonjiseok yoonjiseok changed the title [개인 노트 · 리뷰 불필요] 작업 인계 — 내가 승인한 PR 이 내 문장을 낡게 만든다 (45회차) [개인 노트 · 리뷰 불필요] 작업 인계 — 조용함. #625 에 내 파일 두 줄이 걸려 있다 (46회차) Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants