fix: 고친 자리에 같은 버그를 다시 넣었고, 게이트가 관측 창을 덮었다
한글 수사의 뒤 경계가 세는 말 다음의 조사를 낱말의 일부로 봤다. 「다섯 개다」·「다섯 건을」· 「여섯 장이」가 전부 안 걸린다. 아라비아 숫자 쪽에서 같은 이유로 「500행」·「5개다」를 놓쳤던 것을 고쳤는데, 그 고침을 한글로 옮기면서 다시 넣었다. 회귀가 초록이었던 건 시험 문구가 전부 조사 없이 끝나서다. 뒤 경계를 풀었더니 채택된 편집 둘이 새로 막혔다. 「여덟 자리 → 여덟 곳」이다. 숫자가 안 바뀌었고 세는 말이 바뀌었다 — spatial-metaphor 를 고치는 정상 편집이다. 그래서 잡는 것을 수사로 좁히고 세는 말은 문맥으로만 본다. 대안도 긴 것부터로 정렬했다. 대조군을 주변이 바뀌는 쌍으로 다시 짰다. 같은 문자열은 어떤 검사기든 조용해서 대조가 되지 않는다. 그 대조군이 없었으면 위 오탐을 못 봤다. 그리고 저장 게이트가 그림 붙은 기록을 전부 막고 있었다. 저장소의 그림에 종류 표시가 하나도 없어서 그림이 붙으면 무조건 경고가 하나 붙는다. 게이트가 틀린 게 아니라 그 경고가 어느 기록에 대한 정보도 아니다 — 모든 기록에 걸리는 경고는 어느 기록에 대해서도 아무 말을 하지 않는다. 저장소 전체의 미비는 세고 보고하되 저장을 막지 않는다. 조용히 빼지도 않는다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4vKjQo9KKBBokzxqXLCfk
This commit is contained in:
co-authored by
Claude Opus 5
parent
20c8535169
commit
16cbe141a0
@@ -122,11 +122,54 @@ class KoreanNumeralTest(unittest.TestCase):
|
||||
with self.subTest(before=before):
|
||||
self.assertTrue(cp.compare(before, after)["errors"])
|
||||
|
||||
def test_counting_words_that_are_not_numbers_are_left_alone(self):
|
||||
"""대조군. 「하나뿐」·「둘 다」는 수가 아니다. 세면 정상을 막는다."""
|
||||
for text in ("하나뿐이다", "둘 다 맞다", "한편으로는 그렇다"):
|
||||
with self.subTest(text=text):
|
||||
self.assertEqual([], cp.compare(text, text)["errors"])
|
||||
def test_a_particle_after_the_counter_does_not_hide_the_change(self):
|
||||
"""세는 말 뒤에는 거의 항상 조사가 붙는다.
|
||||
|
||||
뒤를 `(?![가-힣])` 로 막으면 그 자리가 전부 안 걸린다. 아라비아 숫자 쪽에서
|
||||
`(?![\w.-])` 때문에 `500행`·`5개다` 를 놓쳤던 것과 같은 모양이고, 그 고침을
|
||||
한글로 옮기면서 다시 넣었다. **회귀 문구가 전부 조사 없이 끝나서 초록이었다.**
|
||||
"""
|
||||
for a, b in (("증거는 다섯 개다.", "증거는 여섯 개다."),
|
||||
("실험 다섯 건을 돌렸다", "실험 여섯 건을 돌렸다"),
|
||||
("그림 여섯 장이 있다", "그림 일곱 장이 있다"),
|
||||
("스무 곳을 봤다", "서른 곳을 봤다"),
|
||||
("두 번째다", "세 번째다")):
|
||||
with self.subTest(a=a):
|
||||
self.assertTrue(cp.compare(a, b)["errors"], f"{a} → {b} 를 놓쳤다")
|
||||
|
||||
def test_a_long_numeral_is_matched_by_rule_not_by_luck(self):
|
||||
"""대안을 짧은 것부터 두면 `열다섯` 이 `열` 로 먼저 걸려 실패한다."""
|
||||
self.assertTrue(cp.compare("열다섯 개다", "열여섯 개다")["errors"])
|
||||
|
||||
def test_changing_only_the_counter_is_not_a_number_change(self):
|
||||
"""`여덟 자리 → 여덟 곳`. 숫자가 안 바뀌었다.
|
||||
|
||||
채택된 편집이고 `check_prose` 의 spatial-metaphor 를 고치는 정상 편집이다.
|
||||
「수사+세는 말」을 한 덩어리로 잡으면 이것이 수치 변경으로 읽힌다 — 되돌리면
|
||||
이 회귀가 잡는다.
|
||||
"""
|
||||
res = cp.compare("여덟 자리를 목록으로 확정하고", "여덟 곳을 목록으로 확정하고")
|
||||
self.assertEqual([], [x for x in res["errors"] if x["kind"] == "한글수사"])
|
||||
|
||||
def test_controls_where_the_surrounding_text_changes(self):
|
||||
"""대조군은 **주변이 바뀌는 쌍**이어야 한다.
|
||||
|
||||
같은 문자열은 어떤 검사기든 조용하다 — 「입력이 없으면 출력도 없다」를 보일 뿐이고
|
||||
검사기가 무엇을 보는지는 말해 주지 않는다. 이 대조군이 없었으면 「수사+세는 말」을
|
||||
한 덩어리로 잡던 첫 후보의 오탐을 못 봤다.
|
||||
"""
|
||||
for a, b in (("한편으로는 그렇다", "한편으로는 아니다"),
|
||||
("하나뿐이다", "하나뿐이라고 적었다"),
|
||||
("세종대왕이 만들었다", "세종대왕이 반포했다"),
|
||||
("한계가 있다", "한계가 뚜렷하다"),
|
||||
("두 번째 줄을 본다", "두 번째 칸을 본다"),
|
||||
("네트워크 경계를 본다", "네트워크 계층을 본다"),
|
||||
("개발자 한편의 글", "개발자 한편의 기록"),
|
||||
("세 곳을 봤다", "세 곳을 다시 봤다")):
|
||||
with self.subTest(a=a):
|
||||
res = cp.compare(a, b)
|
||||
self.assertEqual([], [x for x in res["errors"] + res["warnings"]
|
||||
if x["kind"] == "한글수사"], f"{a} → {b} 오탐")
|
||||
|
||||
|
||||
class UnsourcedVoiceTest(unittest.TestCase):
|
||||
@@ -135,7 +178,9 @@ class UnsourcedVoiceTest(unittest.TestCase):
|
||||
BEFORE = "피드 아이템을 엔티티로 조회한 뒤 메모리에서 DTO로 옮기는 코드다."
|
||||
|
||||
def test_added_first_person_experience_is_surfaced_as_a_warning(self):
|
||||
after = ("처음에는 조인 한 번으로 가져올 거라고 믿었다. "
|
||||
# 시험 문구에 수사를 넣지 않는다. `한 번` 을 넣었더니 한글수사 규칙이 옳게 걸렸고,
|
||||
# 이 시험이 보려는 것(1인칭 검출)과 섞였다
|
||||
after = ("처음에는 조인으로 가져올 거라고 믿었다. "
|
||||
"팀에서는 다른 의견이 많았지만 나는 조회 방식을 먼저 보자고 했다.\n\n"
|
||||
+ self.BEFORE)
|
||||
res = cp.compare(self.BEFORE, after)
|
||||
|
||||
Reference in New Issue
Block a user