販売ページとZIPの同梱物が3ファイルずつでもずれる。小さな照合で止める

販売ページとZIPの同梱物が3ファイルずつでもずれる。小さな照合で止める

ZIPの中には3ファイル、販売ページにも同梱物が3件。数だけ見ればそろっています。それでも、購入者に渡るREADME.mdは販売ページに書かれず、販売ページには存在しないsample.csvが残っていました。

AIに商品説明の下書きを頼んだ場合も、配布物を直したあとに以前の同梱物が文に残ることがあります。文章として自然でも、渡すファイルと一致するとは限りません。そこで架空の「読書ログテンプレート」を使い、販売ページの同梱物一覧と配布フォルダを機械的に照合しました。

3件と3件では、そろった証拠になりません

販売ページの説明は、購入前に見える約束です。一方で、ZIPの中身は購入後に渡るものです。両方に「3件」と書いてあっても、名前の集合が違えば購入者の見える内容は変わります。

見るべきなのは合計ではなく差分です。

今回の見本では、配布フォルダへ次の3ファイルを置きました。

README.md
quick-start.pdf
template.md

最初の販売ページ用データには、README.mdの代わりにsample.csvを入れます。3件という数は同じです。しかし、差分は2件あります。

  • README.mdは渡すのに、販売ページに書かれていません。
  • sample.csvは販売ページに書かれていますが、ZIPにはありません。

私は件数だけを比べる案をやめました。件数が一致した結果を、内容が一致した結果と読み替えてしまうからです。ファイル名の集合を両方向で引くほうが、何を直すかを短く示せます。

販売ページ側を小さなJSONへ分けました

ここで扱うのは実在の商品、販売実績、購入者情報ではありません。空の一時ディレクトリに合成した商品フォルダと、同梱物だけを持つ販売ページ用データを置きました。実行にはPython 3.13.5を使っています。

自然文の販売ページからファイル名を推測する処理は、今回の対象にしていません。AIが書いた本文の全てを正規表現で読む前に、同梱物だけをincluded_filesへ分けて、人が確認できる入力にします。

work="${TMPDIR:-/tmp}/hibanas-listing-deliverables-lab"
mkdir -p "$work/product"
cd "$work"
printf '%s\n' '# 読書ログテンプレート' > product/template.md
printf '%s\n' '開始手順' > product/quick-start.pdf
printf '%s\n' '利用規約' > product/README.md

販売ページ用データはlisting.jsonとして保存します。意図的に古い一覧を残しました。

cat > listing.json <<'EOF'
{
  "title": "読書ログテンプレート",
  "included_files": ["template.md", "quick-start.pdf", "sample.csv"]
}
EOF

次のスクリプトをcheck_listing_delivery.pyとして保存します。フォルダに実在する通常ファイルとincluded_filesを集合として比較し、配布物にあって販売ページにない名前と、販売ページにあって配布物にない名前を別々に出します。

cat > check_listing_delivery.py <<'EOF'
from __future__ import annotations

import json
import sys
from pathlib import Path

product = Path(sys.argv[1])
listing = json.loads(Path(sys.argv[2]).read_text(encoding="utf-8"))
delivered = {
    path.relative_to(product).as_posix()
    for path in product.rglob("*")
    if path.is_file()
}
listed = set(listing["included_files"])
missing_in_listing = sorted(delivered - listed)
listed_but_missing = sorted(listed - delivered)

for name in missing_in_listing:
    print(f"HOLD missing_in_listing={name}")
for name in listed_but_missing:
    print(f"HOLD listed_but_missing={name}")

print(
    f"result={'PASS' if not (missing_in_listing or listed_but_missing) else 'HOLD'} "
    f"delivered={len(delivered)} listed={len(listed)} "
    f"differences={len(missing_in_listing) + len(listed_but_missing)}"
)
raise SystemExit(0 if not (missing_in_listing or listed_but_missing) else 2)
EOF

初稿は2件のずれで止まりました

商品フォルダと販売ページ用データを渡して実行します。

python3 check_listing_delivery.py product listing.json

実行結果です。

HOLD missing_in_listing=README.md
HOLD listed_but_missing=sample.csv
result=HOLD delivered=3 listed=3 differences=2

delivered=3とlisted=3は同じです。それでもdifferences=2なので、販売候補へ進めません。判定はHOLDです。README.mdを販売ページへ追加するか、不要ならZIPから外すかは、人が商品設計として決めます。sample.csvも、同梱するか記載を消すかを判断します。

この検査は、足りないものを自動で作りません。AIにsample.csvを生成させて通すこともありません。販売ページの約束と配布物のどちらを正とするかは、価格や商品価値に関わる判断だからです。

一覧を直して、同じ物差しで見直します

この見本では、配布フォルダの3ファイルをlisting.jsonへそのまま書き戻し、同じコマンドを再実行しました。

cat > listing.json <<'EOF'
{
  "title": "読書ログテンプレート",
  "included_files": ["README.md", "quick-start.pdf", "template.md"]
}
EOF
python3 check_listing_delivery.py product listing.json

実行結果です。

result=PASS delivered=3 listed=3 differences=0

変えたのは検査条件ではありません。販売ページ用データの一覧だけです。differences=0は、今回決めた3ファイルの名前が両方にあることを示します。PDFの中身が正しいか、手順が読みやすいか、商品価格が妥当かは分かりません。

AIに任せる場所と、人が決める場所を分けます

AIは、短い箇条書きや販売ページの下書きを速く作れます。しかし、古い一覧にsample.csvが残っていても、文章は自然に見えます。だから、AIの文体評価だけではこの差分を見つけられません。

この見本では、次の順番にしました。

  1. 配布するフォルダを完成候補として固定します。
  2. 販売ページに出す同梱物を、小さな一覧として読みます。
  3. 両方の名前が一致しなければ止めます。
  4. 差分を読んでから、ZIPか販売ページを人が直します。
  5. 同じ照合で差分0件を確認します。

景品表示法では、実際のものより著しく優良であると示す表示などが問題になります。今回の小さな照合だけでは、法令への適合や販売ページ全体の正しさを判定できません。それでも、渡さないファイルを同梱物として残す、あるいは渡す説明を落とすという取り違えは、販売ページを公開する前に見つけられます。

自然文の本文は、別に人が読みます

included_filesを正しくしても、本文に「記入例付き」と書いてある場合は別の確認が必要です。template.mdに記入例が含まれるかは、ファイルの存在だけでは分かりません。今回のコードは、ファイル名だけを比べます。

また、サブフォルダ、隠しファイル、購入後に別送するリンクを商品に含める場合は、何を同梱物として数えるかを先に決める必要があります。曖昧な説明を増やすより、購入前に約束するファイル名を少数に絞るほうが、照合の意味を保ちやすくなります。

AIで商品作りを速くするなら、説明文と配布物を別々に完成扱いにしないことです。3件ずつという見た目の一致で終わらせず、購入者へ渡す名前が1つずつそろっているかを確かめます。

出典

この記事をシェア