Repository navigation
fix(nunchi): isolate claude synthesis from the node harness and reserve '기록 없음' for whole-answer refusals (#2531) - #2532
Merged
Conversation
…ve '기록 없음' for whole-answer refusals (#2531) The 2026-10-26 weekly bench failed on every node (unanswered 58-93%, was 13-20%). Two causes compounded: - `claude -p` synthesis ran with no isolation, so it inherited CLAUDE.md, SessionStart memory injection, the ccc-report output style, hooks, tools and MCP. Answers became full reports that quoted session constraints and ran live lookups. Pass the judge-batch #2245 flag set (--safe-mode, --tools "", --disallowedTools mcp__*, --strict-mcp-config, --permission-mode dontAsk, --no-session-persistence); the prompt stays argv[2]. - #2473 told dialectic to write '기록 없음' whenever it had nothing to cite. Wiki/MemPalace evidence has no [#id], so correct answers grew partial "기록 없음" clauses and bench.sh graded them UNANSWERED. A shared NO_RECORD_RULE now reserves '기록 없음' for "no evidence at all" and gives partial gaps the wording '근거에 포함되지 않음', asserted to stay clear of NO_RECORD_RE. id-less excerpts may be used without a citation. Tests: nunchi.test.sh pins the isolation flags, argv[2] prompt and the partial-gap wording (223/223); asof-why 31/31, state-aware 10/10, bench 74/74, conflict-sweep 33/33; validate-harness static PASS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…artial-gap wording there (#2531) A 15-question live bench of the first commit (gwakga, real DB + haiku) brought unanswered from 10/10 to 0/10, but graded two negative controls FABRICATED: q45/q48 refused correctly ("…는 근거에 포함되지 않음.") using the partial-gap phrase as their conclusion, which bench.sh did not read as a refusal. - bench.sh: is_refusal() checks only the lead block (leading markdown headings plus the first content line) against NO_RECORD_RE or the new PARTIAL_GAP_RE (default "근거에 포함되지 않"). Used for the nunchi layer, the Wiki layer and negative-control grading. A gap phrase deeper in the body is not a refusal, so a correct answer with a partial gap stays ANSWERED and a fabricated conclusion stays FABRICATED. - nunchi.py NO_RECORD_RULE: the first line must be a one-sentence conclusion; '기록 없음' leads it when the core of the question has no evidence. - tests: bench.test.sh +4 (partial gap ANSWERED, heading+refusal, gap-worded negative CORRECT-REJECT, body-only gap FABRICATED); nunchi.test.sh pins PARTIAL_GAP_RE against PARTIAL_GAP_PHRASE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
실측: 곽가 15문항 부분 bench (실제
|
| 10-26 공식 (main) | 1차 커밋 4a897fc4 |
2차 커밋 9f7b455b |
|
|---|---|---|---|
| 양성 미답변 | 10/10 | 0/10 | 2/10 (20%) |
| nunchi / wiki 답변 | 0 / 0 | 7 / 3 | 4 / 4 |
| 음성 올바른 거부 | 5/5 | 3/5 | 5/5 |
| fabrication | 0 | 2 (q45·q48) | 0 |
| 게이트 | FAIL | FAIL (fabrication) | PASS |
| "확정 사실" 보고서 형식 흔적 | 다수 | 0 | 0 |
| backend | claude | claude 20/20 | claude |
- 1차 커밋의 fabrication 2건은 실제로는 올바른 거부였다. 지어낸 IP·엔드포인트는 없었다. q45 "주유(juyu)의 Tailscale IP는 근거에 포함되지 않음.", q48 "Supermemory의 활성 엔드포인트(주소/URL) 정보는 근거에 포함되지 않음." 모델이 부분 공백용 문구를 결론에 썼는데 bench가 이를 거부로 읽지 못했다. 2차 커밋은 이를 고친다: 결론 줄 판정(
is_refusal) + 결론 첫 줄 규칙. 2차 실측에서 q45·q48은 첫 줄을기록 없음.으로 시작했다. - 2차에서 남은 미답변 2건은 정직한 거부다. q5(현재 HEAD)는 이전엔 하네스 도구로 라이브
git을 조회해 답했지만, 격리 후엔 "근거에 해시 없음"이라고 답한다. 의도한 변화다. q13은 MemPalace 발췌에 본문이 없는 실제 회수 공백이다. - 15문항은 표본이다. 48문항 전체 회복은 머지·self-update 후 다음 정기 bench(2026-11-02 11:07 KST)에서 확인한다.
CI
- 1차 head
4a897fc4:validate-harness-shard (4)가 실패했다. 원인은scripts/phone-browser-mcp.test.sh의(e) SIGKILLed wrapper: reaper removed its forward + state1건이다. 이 PR과 무관한 파일이다. 같은 base3a0ed3de의 main CI는 성공했고, 로컬 재실행 2/2가 통과(73/73)해 타이밍 flake로 분류한다. - 2차 head
9f7b455b에서 CI가 다시 돌고 있다.
🤖 Generated with Claude Code
seoseo-ai
approved these changes
Oct 26, 2026
seoseo-ai
left a comment
Collaborator
There was a problem hiding this comment.
Approved after exact-head validation and fresh operator authorization using the relay-held seoseo-ai credential.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2531
무엇 / 왜
2026-10-26 정기 bench에서 플릿 전 노드가 unanswered 58
93%로 게이트 FAIL했다(지난주 1320%). 원인 두 가지가 겹쳤다(상세는 #2531).합성
claude -p가 노드 하네스를 상속했다. CLAUDE.md, SessionStart 메모리 주입, ccc-report output style, hooks, 도구, MCP가 그대로 들어가 답변이 보고서 형식으로 부풀었다. 세션 제약을 인용하고 라이브git조회까지 했다.→ judge-batch #2245와 같은 격리 플래그를 붙인다:
--safe-mode --tools "" --disallowedTools mcp__* --strict-mcp-config --permission-mode dontAsk --no-session-persistence.--safe-mode는 OAuth 로그인을 유지한다. prompt는 계속 argv[2]에 둔다(variadic 옵션 앞이어야 하고, 테스트 stub이$2로 읽는다).feat(nunchi): recall --as-of, [#id] citation footer and
whyprovenance (#2464 제안 3, #2466) #2473 프롬프트가 부분 '기록 없음'을 유도했다. "인용할 근거가 없으면 '기록 없음'"이라는 지시 때문에,[#id]가 없는 Wiki/MemPalace 근거로 정답을 내면서도 "기록 없음" 절이 붙었다. bench.shNO_RECORD_RE는 이런 답을 미답변으로 셌다.→ 공통
NO_RECORD_RULE을 만든다. '기록 없음'은 근거가 전혀 없을 때만 쓰고, 부분 공백은근거에 포함되지 않음(NO_RECORD_RE에 걸리지 않음을 테스트로 고정)으로 적는다. id가 없는 발췌는 인용 없이 써도 된다. dialectic과 synthesize(Wiki 계층) 양쪽에 적용한다.bench 거부 판정을 결론 줄 기준으로 바꾼다(2차 커밋, nunchi/bench: 10-26 플릿 전 노드 unanswered 58~93% FAIL — dialectic 부분 '기록 없음' 지시(#2473) + claude -p 하네스 상속 #2531 제안 3). 1차 실측에서, 결론에 부분 공백 문구를 쓴 올바른 거부 2건이 FABRICATED로 판정됐다.
is_refusal()은 lead block(앞쪽 마크다운 제목 + 첫 내용 줄)만NO_RECORD_RE또는PARTIAL_GAP_RE(근거에 포함되지 않)와 대조한다. nunchi 계층, wiki 계층, 음성 대조군 판정에 모두 쓴다. 프롬프트에는 "첫 줄은 결론, 핵심이 없으면 '기록 없음'으로 시작" 규칙을 넣는다. 게이트 임계값(≤40%, fabrication hard fail)은 바꾸지 않았다.영향 범위
dialectic은 세션 recall 경로이기도 하다. 합성 호출에서 도구, MCP, 하네스 주입이 빠지는 것은 의도한 변화다(근거 밖 정보 혼입과 도구 실행 차단).2.1.305이며--safe-mode를 지원한다. 미지원 CLI라면 claude 후보가 exit≠0으로 실패하고 codex/piri로 넘어간다. 이 경우 backend-health에 degraded로 드러난다(조용히 실패하지 않음).검증
nunchi.test.sh224/224,bench.test.sh78/78(결론 줄 판정 +4),stale-bench8/8.nunchi.test.sh신규(1차): 신규 항목: 격리 플래그,--tools "",mcp__*, argv[2] prompt, 부분 공백 문구가 NO_RECORD_RE를 피하는지, 구 지시문 제거.asof-why31/31,state-aware10/10,conflict-sweep33/33.validate-harness.shstatic phase PASS. shellcheck는 기존과 같은 SC2016 info만 있다.🤖 Generated with Claude Code