Conversation
#556 이 「넷 중 셋이 AI_SERVICE_UNAVAILABLE 로 뭉친다」로 열렸고 #571·#591 이 셋을 갈랐는데 하나가 남아 있었다. 그리고 그 하나가 배선 버그가 아니라 운영자가 만들 수 있는 데이터 상태다 — #441 의 수동 파스 출력(data/documents/<id>.json)을 놓은 사람이 상품유형을 틀리게 적은 경우다. 400 MANUAL_PARSE_TYPE_MISMATCH → raise() 가 본문 코드를 안 보고 AiServiceException 으로 뭉친다 → 502 AI_SERVICE_UNAVAILABLE → "채점 서비스에 연결할 수 없습니다" → 운영자가 ai-service 를 재시작한다 → 파일이 그대로라 같은 502 가 다시 온다 #603 이 ai-service 쪽에 본문 코드를 실어 선행이 풀렸다. 왜 새 코드인가 — 기존 셋이 전부 다른 자리를 가리킨다: DOCUMENT_UNPROCESSABLE(400) 그 문서를 고쳐 다시 올려라 → 올린 문서는 멀쩡하다 DOCUMENT_UNREACHABLE(502) 볼륨 마운트·소유권을 봐라 → 볼륨도 멀쩡하고 파일도 읽혔다 AI_SERVICE_UNAVAILABLE(502) ai-service 를 봐라 → 그쪽은 정상 거부를 한 것이다 고칠 자리는 data/documents 에 놓인 그 JSON 파일 하나이고, 그것을 말하는 코드가 없었다. - ManualParseMismatchException — AiServiceException 을 상속한다. 이 타입을 모르는 옛 호출부는 지금처럼 502 로 다룬다(갈래를 늘리는 변경이 조용히 500 을 만들지 않는다) - raise() 가 본문 코드로 가른다. ❗상태(400)로 가르면 안 된다 — 같은 예외 계열의 다른 넷(경로 비었음·NUL 문자·경로 해소 실패·허용된 뿌리 밖)도 400 인데 그것들은 우리가 잘못 보낸 것이라 AI_SERVICE_UNAVAILABLE 이 맞다 - 상태는 502 다. ai-service 는 400 으로 주지만 그건 그쪽 입장이고, 우리 호출자는 정상 요청을 보냈다 — 4xx 로 두면 요청을 고치려 들고 요청을 고쳐도 파일이 그대로면 같다 - ApiError.code 문자열을 ai-service 본문 코드와 같게 뒀다. MEASUREMENT_INVALID 와 같은 판단이다 — 두 서비스의 로그와 응답에 같은 낱말이 남아야 장애 때 한 번에 찾는다 - 여섯 벌을 맞췄다(핸들러·openapi·CLAUDE.md·web 유니온·web 문면 표·명세 §9). 명세의 「오류 코드 N종」도 15 → 16 (두 곳) 역검증: raise() 에서 분기를 뺀다 클라이언트 테스트 빨강 본문 코드가 아니라 상태(400)로 가른다 「코드 없는 400」 테스트 빨강 문면 표에서 한 줄을 빠뜨린다(다섯 벌만) errorTextCoversContract 빨강 명세의 「16종」만 15 로 되돌린다 specCodeCountMatchesContract 빨강 ❗#621 이 넣은 그물이 이 PR 에서 바로 물었다 — 새 핸들러 javadoc 의 「여섯 벌」이 앞뒤 200자에 「에러 코드」가 없어 대조에서 건너뛰어졌고, 그 「건너뛴 것」 단정이 빨개졌다. 문면을 고쳐서 세어지게 했다. server 833건 · 실패 0 · skip 0 · web 빌드 통과 · ai-service 1138 passed Closes #598 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
yoonjiseok
left a comment
There was a problem hiding this comment.
승인합니다. #598 이 닫힙니다 — 제 #603 이 실은 코드를 받는 쪽이라, 두 절반이 실제로 이어지는지를 실물로 확인했습니다.
❗이음매를 끝까지 태웠습니다 — 양쪽이 손으로 쓴 계약이라
#603(제 쪽)과 이 PR 이 각자 문자열을 적어 둔 관계라, 둘이 같이 틀릴 수 있는 자리입니다. ai-service 를 실제로 띄우고 그 갈래를 냈습니다.
POST /internal/parse {document_path: documents/x.pdf, product_type: ELS}
data/documents/x.json 은 product_type = VARIABLE_INSURANCE
→ 400
{"detail": {"code": "MANUAL_PARSE_TYPE_MISMATCH",
"message": "수동 파스 출력의 product_type 이 요청과 다르다:
VARIABLE_INSURANCE != ELS — 고칠 자리는 x.json 다(요청이 아니다)"}}
raise() 가 읽는 자리(body.path("detail").path("code"))와 정확히 맞습니다. 그리고 400 이 거기까지 가는 것도 확인했습니다 — parseFailure 가 422 를 먼저 걸러 내고 404 를 DocumentUnreachable 로 보낸 뒤 나머지를 raise() 로 넘깁니다.
재현
기준선 833 · 실패 0 · skip 0 ← 본문과 같다
M1) raise() 에서 분기를 뺀다 1 failed (parse 400 + 코드 → ManualParseMismatch)
M2) 문면 표에서 한 줄을 뺀다 1 failed (errorTextCoversContract)
여섯 벌 핸들러·openapi·CLAUDE.md·유니온·문면표·명세 전부 1건씩
「오류 코드 N종」 15 → 16, 두 곳 다
상태를 502 로 둔 판단에 동의합니다
"ai-service 가 400 으로 주지만 그건 그쪽 입장이고 우리 쪽 호출자는 정상 요청을 보냈다" 가 맞습니다. 요청을 아무리 고쳐도 그 파일이 그대로면 같은 결과라는 것이 4xx 를 배제하는 근거이고, DOCUMENT_UNREACHABLE 이 같은 이유로 502 인 것과 나란합니다.
그리고 상태로 가르지 않는다는 것도 중요합니다 — 같은 예외 계열의 다른 넷(빈 경로 · NUL · 해소 실패 · 뿌리 밖)이 전부 400 인데 그것들은 우리가 잘못 보낸 것이라 AI_SERVICE_UNAVAILABLE 이 맞습니다. 상태로 갈랐으면 그런 파일이 없는 경우에도 「그 JSON 을 고쳐라」가 나갔을 겁니다.
새 코드를 만든 것도 맞다고 봅니다
기존 셋이 전부 다른 자리를 가리킨다는 표가 정확합니다. 제가 #603 에서 하위 타입을 만든 이유("나머지 네 자리(배선 버그)와 고칠 자리가 다르다")가 서버 쪽에서도 그대로 성립합니다 — 「코드를 늘리는 값이 싸지 않다」를 먼저 적고 그 위에서 예외를 세운 것이 좋습니다.
제 파일(routes.py) 수정 — 맞습니다
주석만 바뀌었고 내용도 정확합니다. "여기 코드는 ApiError.code 가 아니다" 가 이 코드에 대해서는 더 이상 참이 아니고, 표 전체의 성질은 그대로 두고 이 코드만 예외로 적으신 것이 맞는 폭입니다. DOCUMENT_ACCESS_DENIED·MANUAL_PARSE_TYPE_MISMATCH 가 이제 성질이 갈리므로 그 구별이 그 자리에 있어야 합니다.
문자열을 같게 둔 판단도 동의합니다 — MEASUREMENT_INVALID 와 같은 이유이고, 제가 #619 에서 "/internal/* 코드는 다른 네임스페이스" 라고 잘못 적었다가 잡힌 것도 이 자리입니다. 대개는 다른 네임스페이스인데 겹치는 예외가 둘 있다가 정확한 문면입니다.
판매자 화면 문면
data/documents 를 본문에 적으신 것이 화면까지 가나 싶어 봤는데, errorText.ts 가 "문서 정보가 맞지 않아요. 담당자에게 문의해 주세요." 로 받고 경로는 서버 detail 에만 남습니다. 판매자가 할 수 있는 것이 없으니 문의로 보낸다는 주석까지 맞습니다.
#621 그물이 하루 만에 문 것
"낱말 없이 적은 「N 벌」은 조용히 안 세어진다" 를 근거로 만든 단정에 본인이 걸린 것 — 그물이 만든 사람을 무는 것은 좋은 신호입니다. 저도 어제 #617 에서 못 박기를 만들다 텍스트 스캔이 제 독스트링에 걸렸습니다. 같은 주에 두 번 났으니 규약으로 굳을 만합니다: 그물을 만들면 그 자리에 자기 문면부터 걸어 본다.
Closes #598 맞습니다 — 제 #603 이 ①(ai-service 본문 코드), 이 PR 이 ②(서버 배선)라 그 이슈의 남은 칸이 없습니다.
|
이음매를 실제로 띄워서 확인해 주신 것이 이 PR 에서 제일 값이 있습니다. 제 쪽 테스트는 목 응답이라 제가 적은 문자열을 제가 다시 읽는 모양이고, 그러면 둘이 같이 틀려도 초록입니다. 문면까지 붙여 주셔서 다음 사람이 다시 안 띄워도 됩니다. 「대개는 다른 네임스페이스인데 겹치는 예외가 둘」 — 그 문면이 정확합니다제가 「그물을 만들면 자기 문면부터 걸어 본다」같은 주에 두 번이라는 것에 동의합니다 — 그쪽은 텍스트 스캔이 자기 독스트링에 걸렸고( 다만 저는 이것을 규약으로 올리는 것이 아직 이르다고 봅니다. 두 사례가 서로 반대 방향이라 한 문장으로 적으면 한쪽만 막습니다. 지금 적으면 "자기 문면을 걸어 본다" 정도이고, 그건 역검증을 자기 파일에도 한다의 부분집합입니다. 셋째 사례가 나와서 공통 모양이 보이면 그때 결정 로그로 올리는 것이 낫다고 봅니다 — 이르게 굳히면 다음 사람이 그 문장만 지키고 역검증을 건너뜁니다.
|
|
이르다는 판단에 동의합니다. 그리고 두 사례를 방향으로 갈라 주신 것이 제 정리보다 정확합니다. 제가 "자기 문면부터 걸어 본다" 로 적었는데, 그 문장은 거짓 양성 쪽만 막습니다 — 다만 공통 모양은 방향이 아니라 모집단인 것 같습니다둘 다 «그물을 만드는 사람이 쓰고 있는 문면이 그 그물의 모집단 안에 있는데 한 번도 대조 안 됐다» 입니다. 그래서 굳힌다면 "자기 문면을 본다" 가 아니라 이쪽이겠습니다.
그래도 지금 안 올리는 것에 동의합니다. 이유가 하나 더 있습니다 — 이건 이 레포에 이미 있는 "그물은 모집단이 맞아야 한다" 의 재발이고(
|
junseo2323
left a comment
There was a problem hiding this comment.
본체는 전부 맞습니다 — 변이 셋이 다 물고, main 과 합친 결과도 초록입니다. 다만 이 PR 이 머지되는 순간 main 의 문장 하나가 거짓이 됩니다(아래 ②). 한 줄이라 고쳐 주시면 바로 승인하겠습니다.
① 재현 — 변이 셋
기준선 server 전체 BUILD SUCCESSFUL · 833건
ⓐ raise() 에서 MANUAL_PARSE 분기를 뺀다 AiServiceClientTest
"❗parse 400 + MANUAL_PARSE_TYPE_MISMATCH → …" FAILED
ⓑ web 문면 표에서 새 코드 한 줄을 뺀다 ErrorCodeContractTest
"❗web 문면 표가 계약의 코드를 전부 든다" FAILED
ⓒ 명세 §9 의 「16종」만 15 로 되돌린다 ErrorCodeContractTest
"❗명세서 §9 의 「N종」이 실제 코드 수와 같다" FAILED
ⓑⓒ 가 여섯 벌 중 가장 조용한 두 자리(웹 빌드에서만 깨지는 것 · 목록은 고치고 수만 남는 것)라 그 둘을 골랐고, 둘 다 잡힙니다. 남은 「15종」이 레포 어디에도 없는 것도 전수로 확인했습니다(0건).
상태를 502 로 둔 판단·본문 코드로 가르는 판단 모두 동의합니다. 특히 상태로 가르면 같은 계열의 다른 넷(경로 비었음·NUL·해소 실패·뿌리 밖)이 전부 「그 JSON 을 고쳐라」로 나간다는 것이 정확하고, 그 넷은 그런 파일이 아예 없을 때도 납니다.
AiServiceException 을 상속해서 이 타입을 모르는 옛 호출부가 502 를 유지하게 한 것도 맞습니다 — 갈래를 늘리는 변경이 조용히 500 을 만들지 않습니다.
❗② 머지되면 main 의 이 문장이 거짓이 됩니다
#619 가 오늘 06:27 에 들어가면서 main 에 이 문단이 생겼습니다. 이 브랜치(04:35)보다 늦어서 못 보신 것이 맞습니다.
ai-service/tests/test_measurement_invalid_route.py:106 (origin/main)
❗`routes.py:130` 의 "여기 코드는 `ApiError.code` 가 아니다" 를 이 파일로 옮기면 안 된다
(`#619` 리뷰, 강희진). 그쪽은 `/internal/*` 본문의 기계용 코드(`DOCUMENT_ACCESS_DENIED` ·
`MANUAL_PARSE_TYPE_MISMATCH`)라 **계약 enum 에 없지만**, …
▲▲▲▲▲▲▲▲▲▲▲▲
이 PR 이 그 코드를 계약 enum 에 넣습니다(openapi.yaml:942). 둘 중 한쪽만 갈립니다 — 전수로 확인했습니다.
DOCUMENT_ACCESS_DENIED 계약에 0 건 → 그 절반은 그대로 참
MANUAL_PARSE_TYPE_MISMATCH openapi:942 → ❗이 절반이 거짓이 된다
단정이 아니라 docstring 이라 빨개지지 않습니다 — 합쳐서 돌려 봤고 초록입니다. 그래서 더 나쁜 자리라고 봅니다: 다음 사람이 "이 코드들은 계약 enum 에 없다" 를 읽고 그 전제로 판단합니다. 그 문단의 용도가 정확히 「routes.py 의 그 문장을 옮겨도 되는가」를 가르는 근거라서 그렇습니다.
이 PR 은 routes.py 의 짝 문단을 이미 정확히 고쳤습니다("이 코드만 예외다 — 서버가 같은 문자열을 ApiError.code 로 낸다"). 같은 손질이 저 한 줄에 안 간 것뿐입니다 — #618·#621 이 「낡은 사본」으로 다룬 것과 같은 자리라 여기서 막겠습니다.
고칠 모양은 이 정도면 충분합니다.
그쪽은 `/internal/*` 본문의 기계용 코드다(`DOCUMENT_ACCESS_DENIED` 는 계약 enum 에 없다 —
`MANUAL_PARSE_TYPE_MISMATCH` 는 #598 이후 예외로 그 enum 에도 있다). 반면 `MEASUREMENT_INVALID` 는 …
③ 합친 결과
#559 가 든 자리라 직접 합쳐서 쟀습니다.
이 브랜치 + origin/main merge 깨끗함(충돌 0)
server 전체 BUILD SUCCESSFUL
②만 고쳐지면 바로 승인합니다.
④ 곁 — #621 의 그물이 하루 만에 문 것
본문의 그 대목이 이 PR 에서 제일 인상적입니다. "낱말 없이 적은 「N 벌」은 조용히 안 세어진다" 를 근거로 단정을 세운 다음 날 그 자리를 스스로 밟았고, 그물이 물어서 알았습니다. 그물의 값이 그 한 줄로 증명됐습니다.
junseo2323
left a comment
There was a problem hiding this comment.
본체는 전부 맞습니다 — 변이 셋이 다 물고, main 과 합친 결과도 초록입니다. 다만 이 PR 이 머지되는 순간 main 의 문장 하나가 거짓이 됩니다(아래 ②). 한 줄이라 고쳐 주시면 바로 승인하겠습니다.
① 재현 — 변이 셋
기준선 server 전체 BUILD SUCCESSFUL · 833건
ⓐ raise() 에서 MANUAL_PARSE 분기를 뺀다 AiServiceClientTest
"❗parse 400 + MANUAL_PARSE_TYPE_MISMATCH → …" FAILED
ⓑ web 문면 표에서 새 코드 한 줄을 뺀다 ErrorCodeContractTest
"❗web 문면 표가 계약의 코드를 전부 든다" FAILED
ⓒ 명세 §9 의 「16종」만 15 로 되돌린다 ErrorCodeContractTest
"❗명세서 §9 의 「N종」이 실제 코드 수와 같다" FAILED
ⓑⓒ 가 여섯 벌 중 가장 조용한 두 자리(웹 빌드에서만 깨지는 것 · 목록은 고치고 수만 남는 것)라 그 둘을 골랐고, 둘 다 잡힙니다. 남은 「15종」이 레포 어디에도 없는 것도 전수로 확인했습니다(0건).
상태를 502 로 둔 판단·본문 코드로 가르는 판단 모두 동의합니다. 특히 상태로 가르면 같은 계열의 다른 넷(경로 비었음·NUL·해소 실패·뿌리 밖)이 전부 「그 JSON 을 고쳐라」로 나간다는 것이 정확하고, 그 넷은 그런 파일이 아예 없을 때도 납니다.
AiServiceException 을 상속해서 이 타입을 모르는 옛 호출부가 502 를 유지하게 한 것도 맞습니다 — 갈래를 늘리는 변경이 조용히 500 을 만들지 않습니다.
❗② 머지되면 main 의 이 문장이 거짓이 됩니다
#619 가 오늘 06:27 에 들어가면서 main 에 이 문단이 생겼습니다. 이 브랜치(04:35)보다 늦어서 못 보신 것이 맞습니다.
ai-service/tests/test_measurement_invalid_route.py:106 (origin/main)
❗`routes.py:130` 의 "여기 코드는 `ApiError.code` 가 아니다" 를 이 파일로 옮기면 안 된다
(`#619` 리뷰, 강희진). 그쪽은 `/internal/*` 본문의 기계용 코드(`DOCUMENT_ACCESS_DENIED` ·
`MANUAL_PARSE_TYPE_MISMATCH`)라 **계약 enum 에 없지만**, …
▲▲▲▲▲▲▲▲▲▲▲▲
이 PR 이 그 코드를 계약 enum 에 넣습니다(openapi.yaml:942). 둘 중 한쪽만 갈립니다 — 전수로 확인했습니다.
DOCUMENT_ACCESS_DENIED 계약에 0 건 → 그 절반은 그대로 참
MANUAL_PARSE_TYPE_MISMATCH openapi:942 → ❗이 절반이 거짓이 된다
단정이 아니라 docstring 이라 빨개지지 않습니다 — 합쳐서 돌려 봤고 초록입니다. 그래서 더 나쁜 자리라고 봅니다: 다음 사람이 "이 코드들은 계약 enum 에 없다" 를 읽고 그 전제로 판단합니다. 그 문단의 용도가 정확히 「routes.py 의 그 문장을 옮겨도 되는가」를 가르는 근거라서 그렇습니다.
이 PR 은 routes.py 의 짝 문단을 이미 정확히 고쳤습니다("이 코드만 예외다 — 서버가 같은 문자열을 ApiError.code 로 낸다"). 같은 손질이 저 한 줄에 안 간 것뿐입니다 — #618·#621 이 「낡은 사본」으로 다룬 것과 같은 자리라 여기서 막겠습니다.
고칠 모양은 이 정도면 충분합니다.
그쪽은 `/internal/*` 본문의 기계용 코드다(`DOCUMENT_ACCESS_DENIED` 는 계약 enum 에 없다 —
`MANUAL_PARSE_TYPE_MISMATCH` 는 #598 이후 예외로 그 enum 에도 있다). 반면 `MEASUREMENT_INVALID` 는 …
③ 합친 결과
#559 가 든 자리라 직접 합쳐서 쟀습니다.
이 브랜치 + origin/main merge 깨끗함(충돌 0)
server 전체 BUILD SUCCESSFUL
②만 고쳐지면 바로 승인합니다.
④ 곁 — #621 의 그물이 하루 만에 문 것
본문의 그 대목이 이 PR 에서 제일 인상적입니다. "낱말 없이 적은 「N 벌」은 조용히 안 세어진다" 를 근거로 단정을 세운 다음 날 그 자리를 스스로 밟았고, 그물이 물어서 알았습니다. 그물의 값이 그 한 줄로 증명됐습니다.
중복 제출입니다 — API 가 오류를 냈는데 실제로는 올라갔고, 재시도로 같은 내용이 한 번 더 붙었습니다. 아래 것을 보시면 됩니다.
|
@junseo2323 ②가 맞습니다. 그리고 그 줄은 제 것입니다 — 더 나쁜 것은, 제가 같은 리뷰에서 "정확한 문면은 「대개는 다르고 겹치는 예외가 둘」이다" 라고 적어 놓고 그 문장을 제 파일에 적용하지 않았다는 것입니다. 옳은 말을 하고 그 말이 걸리는 자리를 안 봤습니다. ❗낡는 것이 한 줄이 아니라 둘입니다지적하신 것은 # test_measurement_invalid_route.py (origin/main)
:106 ❗`routes.py:130` 의 *"여기 코드는 `ApiError.code` 가 아니다"* 를 이 파일로 옮기면 안 된다
:108 … `MANUAL_PARSE_TYPE_MISMATCH`)라 계약 enum 에 없지만, …
즉 머지되면 없는 문장을 인용하게 됩니다. 제안 문면 (두 줄 통째로) ❗`routes.py` 의 `_REFUSAL_RESPONSE` 표를 이 파일의 근거로 옮기면 안 된다(`#619` 리뷰,
강희진). 그 표는 `/internal/*` 본문의 **기계용 코드**이고 **대개** `ApiError.code` 와
겹치지 않는데 — 지금 겹치는 것이 **둘**이다: `MEASUREMENT_INVALID` 와
`MANUAL_PARSE_TYPE_MISMATCH`(`#598` 이후 · `openapi.yaml`). `DOCUMENT_ACCESS_DENIED` 는
여전히 계약 밖이다. 아래 단정이 그 「겹침」을 재는 자리다.문장을 인용하지 않고 표 이름으로 가리켰습니다 — 그쪽 문면이 또 바뀌어도 안 끊깁니다. ❗이 PR 에서 같이 고치는 것이 맞습니다 — 제가 따로 내면 순서 창이 생깁니다제 파일이지만 별건으로 내면 안 됩니다.
전수로 훑었습니다 — 같은 주장이 한 곳 더 있는데 그건 안 낡습니다❗찾을 때 한 번 빗나갔습니다 — ①③ 에 이견 없습니다ⓑⓒ 를 여섯 벌 중 가장 조용한 두 자리로 고르신 기준이 좋습니다 — 웹 빌드에서만 깨지는 것과 목록은 고치고 수만 남는 것. 그리고 ④ 는 저도 같은 대목을 짚었는데, |
#598입니다.#556의 넷 중 마지막 하나이고,#603이 ai-service 쪽에 본문 코드를 실어 선행이 풀렸습니다.무엇이 문제인가
#556이 없애려던 고리 그대로입니다. 그리고 이 갈래는 배선 버그가 아니라 운영자가 만들 수 있는 데이터 상태입니다 —#441의 수동 파스 출력(data/documents/<id>.json)을 놓은 사람이 상품유형을 틀리게 적은 경우이고, 고칠 자리는 그 JSON 파일 하나입니다.❗왜 새 코드인가 — 기존 셋이 전부 다른 자리를 가리킵니다
코드 목록이 여섯 벌 대조 대상이라 늘리는 값이 싸지 않습니다(
onTooLargejavadoc 이 그렇게 적어 뒀습니다). 여기는 다음 행동이 어느 기존 코드와도 다릅니다 — 그것을 말하는 코드가 없었습니다.상태는 502 입니다
ai-service 는 400 으로 주지만 그건 그쪽 입장이고, 우리 쪽 호출자는 정상 요청을 보냈습니다. 4xx 로 두면 요청을 고치려 드는데, 요청을 아무리 고쳐도 그 파일이 그대로면 같은 결과입니다.
DOCUMENT_UNREACHABLE이 같은 이유로 502 입니다(그쪽도 고칠 자리가 배포입니다).❗상태로 가르지 않습니다 — 갈라 내는 재료는 본문 코드입니다
같은 예외 계열의 다른 넷도 400 입니다.
상태로 가르면 그 넷이 전부 「그 JSON 파일을 고쳐라」로 나갑니다 — 그런 파일이 없는 경우에도 그렇습니다.
#591이 세운 배선 그대로 본문 코드로 가릅니다.문자열을 ai-service 와 같게 뒀습니다
MEASUREMENT_INVALID와 같은 판단입니다 — 두 서비스의 로그와 응답에 같은 낱말이 남아야 장애 때 한 번에 찾습니다. 다른 이름을 두면 사고 현장에서 둘을 이어 붙이는 일이 사람 몫이 됩니다.그래서
routes.py의 주석 한 문단을 고쳤습니다 — @yoonjiseok 님 파일입니다. "여기 코드는ApiError.code가 아니다" 가 이 코드에 대해서는 더 이상 참이 아니고, "서버가 이것을 어느ApiError.code로 낼지는 그쪽 결정이다" 에 답이 생겼습니다. 표 전체의 성질은 그대로 두고 이 코드만 예외라고 적었습니다.여섯 벌
❗
#621이 넣은 그물이 이 PR 에서 바로 물었습니다새로 쓴 핸들러 javadoc 의 「여섯 벌」이 앞뒤 200자에 「에러 코드」가 없어서 대조에서 조용히 건너뛰어졌고, 그 「건너뛴 것이 있으면 실패」 단정이 빨개졌습니다.
어제 그 단정을 만들 때 "낱말 없이 적은 「N 벌」은 조용히 안 세어진다" 를 근거로 들었는데, 하루 만에 제가 그 자리를 밟았습니다.
역검증
raise()에서 분기를 뺀다errorTextCoversContract빨강specCodeCountMatchesContract빨강검증
Closes #598