Opus 5, Sonnet 5, Fable 5 모델은 파일을 읽지 않고도 수정할 수 있음
Opus 5, Sonnet 5, and Fable 5 do not need to read files to edit them
핵심 요약
Claude Code의 최신 모델들이 파일을 읽지 않고도 수정할 수 있게 변경되면서, 기존 테스트 코드가 덮어씌워지는 문제가 발생하고 있습니다.
- 파일 읽기 강제 해제 — 5 시리즈 모델들은 파일을 읽지 않고도 쓰기/수정 작업이 가능함
- 테스트 덮어쓰기 문제 — Fable 모델이 기존 테스트를 인식하지 못하고 새로운 테스트를 작성하며 코드를 망가뜨림
- 의도된 변경 가능성 — 모델의 성능 향상을 위해 검증 과정을 생략한 것으로 추측됨
- 임시 해결책 — PreToolUse 훅을 사용하여 쓰기/수정 전 파일 읽기 여부를 강제로 검증함
Claude Code의 Write 및 Edit 도구에서 파일 읽기 강제는 항상 핵심적인 규칙이었음. Claude는 파일을 수정하기 전에 반드시 먼저 읽어야만 했거든. Write 도구가 파일을 읽기 전까지는 쓰기 권한을 막아버리는 걸 본 적 있을 거야.
최근에 이 규칙에서 5-family 모델들은 제외되도록 바뀌었음. 하네스(harness)가 모델이 5-family에 속하는지 확인하고, 맞으면 읽기 과정 없이 바로 쓰기나 수정을 진행하게 만드는 거지. 이 강제 조치를 건너뛰면서 나타난 가장 큰 부작용은 테스트 파일이 다 날아가는 현상인데, 특히 Fable 쓸 때 심함. 작업 중에 새 테스트를 작성해야 할 때, Fable이 기존 테스트를 싹 다 밀어버리고 새로 써버리는 거임. Fable이 다른 소스에서 이미 어떤 테스트가 있는지 알고 있다고 착각할 때 이런 현상이 특히 두드러짐.
왜 이런 일이 벌어지나 싶어서 Fable, Opus, Sonnet한테 파일을 읽지 않고 바로 쓰라고 시켜봤는데, 전부 다 성공했음(심지어 얘네들도 Write 도구 문서에는 안 된다고 적혀 있는데 왜 되는지 의아해하더라). Opus가 bun 파일을 파헤쳐 본 결과는 이거임:
let state = ctx.readFileState.get(path);
if (!state || state.isPartialView) {
let guardSkipped = !state // never read
&& !isNotebook(path) // extname !== ".ipynb"
&& !I6t(model) // model NOT in enforcement set
&& XCt(WriteTool, path, ctx); // reading it was auto-allowed anyway
log("tengu_write_tool_not_read_hypothetical", { wouldHaveResult, guardSkipped, modelBucket });
if (!guardSkipped)
return { result: false, message: "File has not been read yet. Read it first before writing to it.", errorCode: 2 };
return { result: true }; // ← guard skipped, write proceeds
}
The deciding term is I6t:
function I6t(e) { return rs_.has(Ba(e)) }
function Ba(e) { return e.replace(/\[1m\]$/i, "") }
rs_ = new Set(["claude-opus-4-6","claude-haiku-4-5","claude-opus-4-5","claude-opus-4-1",
"claude-opus-4-0","claude-sonnet-4-5","claude-sonnet-4-0",
"claude-3-7-sonnet","claude-3-5-sonnet","claude-3-5-haiku"]);
Opus가 "이건 난독화된 코드에서 추론한 거라... 상위 레벨에 보고할 때 너무 의존하지 마"라고 경고하긴 했으니 적당히 걸러 들어야겠지만, 어쨌든 의도적인 변경으로 보임. 내 생각엔 얘네가 모델들을 학습시킬 때 코드를 날려 먹지 않도록 충분히 훈련했다고 판단해서 체크 과정을 뺀 거 같음(토큰 입력값 줄이려는 목적도 있을 거고). 근데 우리가 겪어본 바로는 이 모델들이 그 정도 수준까지는 안 됨.
만약 이게 의도적인 변경이라면, Write 도구 설명에는 여전히 가드가 작동한다고 적혀 있으니까 최소한 모델한테 제공되는 문서 컨텍스트조차 업데이트 안 한 셈이지.
우리는 현재 세션에서 Write나 Edit 도구를 호출하기 전에 Read 작업이 있었는지 명시적으로 확인하는 PreToolUse 훅을 만들어서 이 문제를 우회하고 있음.
혹시 다른 사람들도 이런 문제 겪은 적 있는지 궁금하네.

