受け取った回答と実際が違う - 項目ごとに突き合わせる
目標
現場に入る前に受け取ったインテーク回答9項目を、その顧客企業の実際のシステムで測った値と照合します。判定ルールをファイルに固め、完全一致・範囲内・不一致・回答なし・確認不能の5つで判定する照合ツールを作り、食い違った項目ごとに再度尋ねる質問を機械に作らせます。
なぜ重要なのか
インテークの回答は顧客の記憶であり、システムは事実です。回答を書いた人はたいてい3年前にそのシステムを導入した人で、その後、保存期間が短くなり、連携が1つ増え、バックアップの間隔が変わりました。回答をそのまま前提にした計画は、着手した途端に崩れます。 そこで、照合は目ではなくルールで行います。項目ごとにどう比較するかを先に決めてファイルに書いておけば、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の7項目を書いてください。
- 項目ごとに比較方法を決めて、/root/intake/rules.jsonにfieldsの一覧として書いてください。範囲で回答した項目はrange、一覧で回答した項目はset、概数で回答した項目はtolerance(tolerance_pctは20)、残りはexactです。測る場所がない項目は、sourceをnullにします。
- /root/intake/reconcile.pyを作成し、exactとsetの2つのルールでmatch_exact・mismatchを判定して、要約とともにJSONで出力させてください。
- rangeとtoleranceを追加し、範囲内に入った項目をmatch_in_rangeと判定させてください。境界値は範囲内です。
- 回答が空の項目はunanswered、回答はあるのに測定値がない項目はunverifiableと判定させてください。両方に当てはまる項目はunansweredです。
--questions <경로>を追加し(プレースホルダーは出力先のパスです)、一致しなかった項目ごとに、再度尋ねる質問を1文で入れたJSON配列を書かせてください。- 本物の回答と本物の事実から、/root/intake/report.jsonと、/root/intake/questions.jsonを作成し、/root/intake/intake_report.mdに4つの節で報告してください。
参考
- 実行契約:
python3 /root/intake/reconcile.py --answers <A> --facts <F> --rules <R> --out <보고 JSON> [--questions <질문 JSON>](プレースホルダーは入力ファイルと出力ファイルのパスです)は、要約JSONを1行、標準出力に出して、終了コード0で終わります。入力を読み込めない場合は3です。 - 報告JSON:
{"summary": {"fields": 정수, "match_exact": 정수, "match_in_range": 정수, "mismatch": 정수, "unanswered": 정수, "unverifiable": 정수}, "findings": [...]}(プレースホルダーは整数です)。findingsはfield名の昇順で、項目ごとにfield・rule・answer・fact・verdictの5つのキーがあります。 - 判定名は、正確にmatch_exact・match_in_range・mismatch・unanswered・unverifiableの5つです。
- ルールファイル:
{"fields": [{"name": …, "kind": "exact|range|tolerance|set", "source": 문자열 또는 null, "tolerance_pct": 정수}]}(プレースホルダーは文字列と整数です)。toleranceでない項目には、tolerance_pctを置かなくてもかまいません。 - rangeは、回答が
{"min": …, "max": …}の項目で、境界値を含みます。toleranceは、잰 값과 답변의 차이 <= 답변 × tolerance_pct / 100(韓国語の式は「測定値と回答の差 <= 回答 × tolerance_pct / 100」という意味です)のとき、範囲内です。測定値が回答と完全に同じなら、toleranceの項目でもmatch_exactです。 - 事実ファイルの値は、自分で測定してください。バージョンは
site/app/VERSION、設定はsite/app/app.ini(configparser)、保存期間とタイムゾーンはsite/data/app.dbのsettingsテーブル、ログの保存日数はsite/logsのファイル名、1日の最大注文数はordersテーブル、バックアップ間隔はbackup_logテーブルの時刻の間隔です。 - よくあるミス: 一覧を順序まで比較すること、許容誤差をコードに隠しておくこと、確認できなかった項目を一致と書くこと、質問文の代わりに指摘文を出すこと。
- tolerance_pctの20と、「回答なしの項目を確認不能より先にする」という優先順位は、このラボの前提です。標準が決めた値ではなく、チームが合意してルールファイルに書いておく値です。
- 参考ドキュメント: RFC 2119とRFC 8174は規則文の強さを語で固定する方法を、RFC 3339は日付と時刻の表記を、Python jsonドキュメントとSQLiteの日付関数はこのラボで使う道具を説明しています。
回答とシステムを手に入れる
/root/intake/gen_site.pyを作成して実行し、answers.json(9項目)とsiteディレクトリを作成してください(保存先: /root/intake/answers.json、/root/intake/site/)。siteにはバージョンファイル、app.ini、14日分のログ、本番DB(settings・orders・backup_log)が入ります。
現場で手に入るのは、回答ファイル1つとシステム1台だけです。ここではその2つを自分たちで作ります。まず/root/intakeを作成し、その中でpython3を使ってファイルとsqlite DBを作成してください。回答は顧客が記憶で書いた値なので、システムとは複数の項目で異なります。
システムから直接測定する
/root/intake/facts.jsonにapp_version・timezone・retention_days・log_days・daily_orders_max・integrations・backup_interval_hoursの7項目を書いてください。値はすべてsite/で直接測定したものにし、7項目以外の項目は入れないでください。
バージョンはsite/app/VERSIONの1行、タイムゾーンと保存期間は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の2つのルールで判定させてください。値が同じならmatch_exact、違えばmismatchです。setは順序を見ません。報告JSONにはsummaryとfindingsが入ります。
findingsはfield名の昇順に並べ、項目ごとにfield・rule・answer・fact・verdictの5つのキーを入れてください。summaryは判定名5つをそれぞれ数え、fieldsに全項目数を書きます。一覧の比較は、並べ替えてから行うと順序に左右されません。
範囲内を別に数える
rangeとtoleranceを追加し、範囲内に入った項目をmatch_in_rangeと判定させてください。rangeは、回答がmin・maxの項目で、境界値を含みます。toleranceは、差が回答のtolerance_pctパーセント以内のときで、測定値が回答と完全に同じならmatch_exactです。
概数の項目をすべて不一致と書くと、本当の問題が同じ色に埋もれます。境界値を含めるか除くかはルールが決めることで、このラボでは含めます。許容誤差はコードに隠さず、ルールファイルのtolerance_pctを読んで使ってください。
回答がない項目と確認不能
回答が空の項目や、そもそもない項目はunanswered、回答はあるのに測定値がない項目はunverifiableと判定させてください。両方に当てはまる項目はunansweredです。
確認できなかった項目を一致と書くと誰もその項目を見直さなくなり、不一致と書くと顧客と無用な争いになります。回答にキーがそもそもない場合と、値がnullの場合は、同じように扱ってください。優先順位をコードの最初に置くと、残りのルールがこの2つに触れません。
指摘ではなく質問を作る
--questions <경로>を追加し(プレースホルダーは出力先のパスです)、一致しなかった項目ごとに1つずつ、項目を入れたJSON配列を書かせてください。項目にはfield・verdict・answer・factとともに、askという1文が入ります。askには項目名が入り、疑問符(?)で終わります。
12項目が間違っているという表を持っていくと、顧客はまず守りに入ります。同じ内容を質問に変えると、会話になります。判定の種類ごとに文の型を別に用意してください。不一致はどちらが正しいか、確認不能はどこを見ればよいか、回答がない項目は誰が決める値なのかを尋ねます。
本物の回答で実行して報告する
本物の回答と本物の事実から、/root/intake/report.jsonと、/root/intake/questions.jsonを作成し、/root/intake/intake_report.mdに、## 무엇을 대조했나、## 어긋난 칸、## 답이 없는 칸、## 다시 물어볼 것の4つの節で報告してください(韓国語の見出しは順に「照合した対象」「食い違った項目」「回答がない項目」「再度尋ねること」という意味です)。食い違った項目と回答がない項目の名前が、レポートにすべて出ている必要があります。
レポートは手で書かず、report.jsonとquestions.jsonから生成してください。そうすれば、2週間後に同じコマンドをもう一度実行したときに、レポートも一緒に更新されます。数字は要約からそのまま取り、項目名はfindingsから取ります。