受け取った回答と実際が違う - 項目ごとに突き合わせる
한국어 원문으로 표시합니다.
목표
현장에 들어가기 전 받은 인테이크 답변 9칸을 그 고객사의 실제 시스템에서 잰 값과 대조한다. 판정 규칙을 파일로 굳히고, 정확히 일치·범위 안·불일치·답이 없음·확인 불가 다섯 가지로 판정하는 대조기를 만들고, 어긋난 칸마다 다시 물어볼 질문을 기계가 만들어 내게 한다.
왜 중요한가
인테이크 답변은 고객의 기억이고 시스템은 사실이다. 답을 적은 사람은 대개 3년 전에 그 시스템을 설치한 사람이고, 그 뒤로 보존 기간이 줄었고 연동이 하나 더 붙었고 백업 주기가 바뀌었다. 답변을 그대로 전제로 삼은 계획은 착수하자마자 무너진다. 그래서 대조는 눈이 아니라 규칙으로 한다. 칸마다 어떻게 비교할지를 먼저 정해 파일에 적어 두면, 2주 뒤에 같은 명령을 다시 돌려 그 사이 무엇이 바뀌었는지 볼 수 있다. 눈으로 한 대조는 다시 돌릴 수 없다. 가장 중요한 것은 모르는 칸을 모른다고 적는 것이다. 확인하지 못한 칸을 일치로 적으면 아무도 그 칸을 다시 보지 않고, 불일치로 적으면 고객과 쓸데없이 다툰다. 답이 없는 칸과 확인할 수 없는 칸은 따로 세어 목록으로 남긴다. 채점기는 여러분이 적어 낸 문구를 믿지 않는다. 임시 디렉터리에 채점기가 만든 답변과 사실을 차려 놓고, 매번 다른 값으로 여러분의 대조기를 실제로 실행해 판정과 요약을 직접 계산한 값과 대조한다.
단계
- /root/intake/gen_site.py 를 만들어 실행해 /root/intake/answers.json(9칸)과 /root/intake/site/(버전 파일·설정·로그 14일치·운영 DB)를 만드세요.
- 시스템을 직접 재어 /root/intake/facts.json 에 app_version·timezone·retention_days·log_days·daily_orders_max·integrations·backup_interval_hours 일곱 칸을 적으세요.
- 칸마다 비교 방법을 정해 /root/intake/rules.json 에 fields 목록으로 적으세요. 범위로 답한 칸은 range, 목록으로 답한 칸은 set, 어림수로 답한 칸은 tolerance(tolerance_pct 20), 나머지는 exact 입니다. 잴 자리가 없는 칸은 source 를 null 로 둡니다.
- /root/intake/reconcile.py 를 만들어 exact 와 set 두 규칙으로 match_exact·mismatch 를 판정하고 요약과 함께 JSON 으로 내게 하세요.
- range 와 tolerance 를 더해 범위 안에 들어온 칸을 match_in_range 로 판정하게 하세요. 경계값은 범위 안입니다.
- 답이 비어 있는 칸은 unanswered, 답은 있는데 잰 값이 없는 칸은 unverifiable 로 판정하게 하세요. 둘 다인 칸은 unanswered 입니다.
--questions <경로>를 더해, 일치하지 않은 칸마다 다시 물어볼 질문 한 문장을 담은 JSON 배열을 쓰게 하세요.- 진짜 답변과 진짜 사실로 /root/intake/report.json 과 /root/intake/questions.json 을 만들고, /root/intake/intake_report.md 에 네 절로 보고하세요.
참고
- 실행 계약:
python3 /root/intake/reconcile.py --answers <A> --facts <F> --rules <R> --out <보고 JSON> [--questions <질문 JSON>]은 요약 JSON 한 줄을 표준출력에 내고 종료 코드 0 으로 끝납니다. 입력을 읽을 수 없으면 3 입니다. - 보고 JSON:
{"summary": {"fields": 정수, "match_exact": 정수, "match_in_range": 정수, "mismatch": 정수, "unanswered": 정수, "unverifiable": 정수}, "findings": [...]}. findings 는 field 이름 오름차순이고, 항목마다 field·rule·answer·fact·verdict 다섯 키가 있습니다. - 판정 이름은 정확히 match_exact · match_in_range · mismatch · unanswered · unverifiable 다섯입니다.
- 규칙 파일:
{"fields": [{"name": …, "kind": "exact|range|tolerance|set", "source": 문자열 또는 null, "tolerance_pct": 정수}]}. tolerance 가 아닌 칸에는 tolerance_pct 를 두지 않아도 됩니다. - range 는 답변이
{"min": …, "max": …}인 칸이고 경계값을 포함합니다. tolerance 는잰 값과 답변의 차이 <= 답변 × tolerance_pct / 100일 때 범위 안입니다. 잰 값이 답변과 정확히 같으면 tolerance 칸이라도 match_exact 입니다. - 사실 파일의 값은 직접 재세요. 버전은
site/app/VERSION, 설정은site/app/app.ini(configparser), 보존 기간과 시간대는site/data/app.db의 settings 표, 로그 보존 일수는site/logs의 파일 이름, 하루 최대 주문은 orders 표, 백업 주기는 backup_log 표의 시각 간격입니다. - 흔한 실수: 목록을 순서까지 비교하기, 허용 오차를 코드에 숨겨 두기, 확인하지 못한 칸을 일치로 적기, 질문 문장 대신 지적 문장을 내기.
- tolerance_pct 20 과 "답이 없는 칸이 확인 불가보다 먼저" 라는 우선순위는 이 실습의 가정입니다. 표준이 정해 주는 값이 아니라 팀이 합의하고 규칙 파일에 적어 두는 값입니다.
- 참고 문서: RFC 2119 와 RFC 8174 는 규칙 문장의 강도를 낱말로 못박는 방법을, RFC 3339 는 날짜와 시각 표기를, 파이썬 json 문서와 SQLite 날짜 함수는 이 실습에서 쓰는 도구를 설명합니다.
답변과 시스템을 손에 쥐기
/root/intake/gen_site.py 를 만들어 실행해 /root/intake/answers.json(9칸)과 /root/intake/site/ 를 만드세요. site 에는 버전 파일, app.ini, 로그 14일치, 운영 DB(settings·orders·backup_log)가 들어갑니다.
현장에서 손에 쥐는 것은 답변 파일 하나와 시스템 한 대뿐입니다. 여기서는 그 둘을 우리가 만듭니다. 먼저 /root/intake 를 만들고 그 안에서 python3 로 파일과 sqlite DB 를 만드세요. 답변은 고객이 기억으로 적은 값이라 시스템과 여러 칸에서 다릅니다.
시스템에서 직접 재기
/root/intake/facts.json 에 app_version·timezone·retention_days·log_days·daily_orders_max·integrations·backup_interval_hours 일곱 칸을 적으세요. 값은 전부 site/ 에서 직접 잰 것이어야 하고, 일곱 칸 말고 다른 칸은 넣지 마세요.
버전은 site/app/VERSION 한 줄, 시간대와 보존 기간은 site/data/app.db 의 settings 표, 연동 목록은 site/app/app.ini 의 integrations 절입니다. log_days 는 site/logs 의 서로 다른 날짜 수이고, daily_orders_max 는 orders 표를 날짜별로 센 최댓값, backup_interval_hours 는 backup_log 의 이웃한 시각 사이 간격입니다.
판정 규칙을 파일로 굳히기
/root/intake/rules.json 에 답변 9칸 전부를 fields 목록으로 적으세요. 범위로 답한 칸은 kind range, 목록으로 답한 칸은 set, 어림수로 답한 칸(daily_orders_max)은 tolerance 에 tolerance_pct 20, 나머지는 exact 입니다. 잰 값이 없는 칸은 source 를 null 로, 있는 칸은 어디서 쟀는지 문자열로 적습니다.
규칙은 대조하기 전에 정해야 합니다. 대조하면서 정하면 자기가 보고 싶은 결과가 나옵니다. 어떤 칸에 잴 자리가 없는지는 facts.json 에 그 이름이 있는지로 갈립니다. source 에는 경로나 표 이름처럼 나중에 고객에게 보여 줄 수 있는 근거를 적으세요.
정확히 일치와 불일치 가르기
/root/intake/reconcile.py 를 만들어 exact 와 set 두 규칙으로 판정하게 하세요. 값이 같으면 match_exact, 다르면 mismatch 입니다. set 은 순서를 보지 않습니다. 보고 JSON 에는 summary 와 findings 가 들어갑니다.
findings 는 field 이름 오름차순으로 정렬하고 항목마다 field·rule·answer·fact·verdict 다섯 키를 담으세요. summary 는 판정 이름 다섯 개를 각각 세고 fields 에 전체 칸 수를 적습니다. 목록 비교는 정렬한 뒤 하면 순서에 흔들리지 않습니다.
범위 안을 따로 세기
range 와 tolerance 를 더해 범위 안에 들어온 칸을 match_in_range 로 판정하게 하세요. range 는 답변이 min·max 인 칸이고 경계값을 포함합니다. tolerance 는 차이가 답변의 tolerance_pct 퍼센트 이내일 때이고, 잰 값이 답변과 정확히 같으면 match_exact 입니다.
어림수 칸을 전부 불일치로 적으면 진짜 문제가 같은 색으로 묻힙니다. 경계값을 포함할지 뺄지는 규칙이 정하는 것이고, 이 실습은 포함합니다. 허용 오차는 코드에 숨기지 말고 규칙 파일의 tolerance_pct 를 읽어 쓰세요.
답이 없는 칸과 확인 불가
답이 비어 있거나 아예 없는 칸은 unanswered, 답은 있는데 잰 값이 없는 칸은 unverifiable 로 판정하게 하세요. 둘 다인 칸은 unanswered 입니다.
확인하지 못한 칸을 일치로 적으면 아무도 그 칸을 다시 보지 않고, 불일치로 적으면 고객과 쓸데없이 다툽니다. 답변에 키가 아예 없는 경우와 값이 null 인 경우를 같게 다루세요. 우선순위를 코드 맨 앞에 두면 나머지 규칙이 이 두 가지를 건드리지 못합니다.
지적 대신 질문 만들기
--questions <경로> 를 더해, 일치하지 않은 칸마다 항목 하나씩을 담은 JSON 배열을 쓰게 하세요. 항목에는 field·verdict·answer·fact 와 함께 ask 한 문장이 들어갑니다. ask 에는 칸 이름이 들어가고 물음표로 끝나야 합니다.
열두 칸이 틀렸다는 표를 들고 가면 고객은 방어부터 합니다. 같은 내용을 질문으로 바꾸면 대화가 됩니다. 판정 종류마다 문장 틀을 따로 두세요 — 불일치는 어느 쪽이 맞는지, 확인 불가는 어디를 보면 되는지, 답이 없는 칸은 누가 정하는 값인지 묻습니다.
진짜 답변으로 돌리고 보고하기
진짜 답변과 진짜 사실로 /root/intake/report.json 과 /root/intake/questions.json 을 만들고, /root/intake/intake_report.md 에 ## 무엇을 대조했나 ## 어긋난 칸 ## 답이 없는 칸 ## 다시 물어볼 것 네 절로 적으세요. 어긋난 칸과 답이 없는 칸의 이름이 보고서에 모두 나와야 합니다.
보고서는 손으로 쓰지 말고 report.json 과 questions.json 에서 만들어 내세요. 그래야 2주 뒤에 같은 명령을 다시 돌렸을 때 보고서도 함께 갱신됩니다. 숫자는 요약에서 그대로 가져오고, 칸 이름은 findings 에서 가져옵니다.