transaction-deduplicator について
重複期間のある明細取り込みから、重複・類似取引を見つける取引処理スキルです。口座、符号付き金額、説明、日付の近さを使い、正当な反復決済は残します。
主な機能
- 01口座・符号付き金額・説明で照合
- 02日付の1日差を許容
- 03正当な反復決済を保持
- 04類似取引を確認用に抽出
- 05重複を既存レコードに紐付け
活用シーン
- 01重複期間のある明細の取引整理
- 02詳細が一致する同日の複数決済の保持
- 03保留中と確定済みの請求の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lyndonkl/ claude --skill transaction-deduplicatorインストール後、Claude Code で/transaction-deduplicatorを入力して読み込まれたか確認します。
詳細
Transaction Deduplicator
目次
概要
明細書の期間は重複することがよくあります。1月の明細書は12月15日から1月14日までを対象とし、12月の明細書は11月15日から12月14日までを対象としますが、同じ12月15日の取引が両方に記載されます。このスキルは、正当な同日・同金額・同じ加盟店での繰り返し請求(例:1日にコーヒーを2杯購入)を失わずに、こうした重複を特定します。
入力の仕様
呼び出し元は以下を提供します。
incoming— 新たに抽出された取引の配列:{date, post_date, account_id, amount_cents, description_raw, source}。existing— 同じフィールドに加えてidを含む、ストア内にすでにある取引の配列。
重複排除キー
重複は次のタプルで識別します。
(account_id, abs(amount_cents), description_normalized, |date_a - date_b| <= 1 day)
description_normalizedには、分類器と同じ正規化(大文字化、ベンダーコードの除去、地理情報の除去、空白の連続の圧縮、日付の削除)を適用します。- 1日の許容範囲により、2つのソース間で生じる
dateとpost_dateの不一致を吸収します。 abs(amount_cents)を使うと、元の購入に対する払い戻しが重複として扱われなくなります(符号が異なるため)。複合キーには符号付き金額を使います。
符号付きの amount_cents を使用してください。払い戻し(符号が逆)は、購入の重複にはなりません。
ワークフロー
Dedupe Progress:
- [ ] Step 1: Index existing transactions by (account_id, signed_amount, normalized_desc)
- [ ] Step 2: For each incoming, look up the index
- [ ] Step 3: Filter index hits by date proximity (≤ 1 day)
- [ ] Step 4: If no hit, mark as new
- [ ] Step 5: If exactly one hit, mark as duplicate of that id
- [ ] Step 6: If multiple hits, run the multi-instance same-day rule
- [ ] Step 7: Surface near-duplicates (different amount or desc) for review
ステップ 1 — インデックス化
existing_by_key[(account_id, amount_cents, description_normalized)] = [tx, …] を作成します。
ステップ 2 — 検索
各新規取引のキーのタプルを計算し、該当するバケットを検索します。
ステップ 3 — 日付の近接性によるフィルタリング
バケット内の候補ごとに、|incoming.date − candidate.date| ≤ 1 day を満たすものだけを残します。post_date が存在する場合は、両方で min(date, post_date) を使います。
ステップ 4 — 一致なし
decision: "new" と設定します。経理担当者が transactions.json に追加します。
ステップ 5 — 一致が 1 件のみ
decision: "duplicate" と設定し、duplicate_of: <existing_id> を指定します。インポートしないでください。
ステップ 6 — 複数件一致(正当な同日での繰り返し)
ストアに同じ日の同一キーの取引が N 件あり、新規バッチに同じ日の同一キーの取引が M 件ある場合:
M ≤ Nの場合 → 新規取引はすべて既存取引との重複とみなします(日付順に 1 対 1 で対応付けます)。M > Nの場合 → 最初の N 件は重複とし、残りのM − N件は新規取引とします(正当な同日での繰り返し請求。例:コーヒーを2杯購入、ガソリンスタンドでの事前承認と最終請求)。
このルールにより、実際の繰り返し請求を保持しながら、重複してインポートされる取引を抑制できます。
ステップ 7 — 類似重複の確認
類似重複とは、金額または説明以外のすべてが一致し、1日以内に発生した取引です。よくある例:
- 保留中の請求($45.00)がわずかに異なる金額($45.83)で確定する — 確定した取引を残し、保留中の取引を削除します。
- 加盟店名が請求期間の途中で変わる("AMAZON.COM*ABC123" → "AMZN Mktp US")。
両方の記録を並べて review[] に出力し、推奨アクションとして keep_incoming_drop_existing | keep_existing_drop_incoming | keep_both | merge のいずれかを指定します。
類似重複の処理
類似する不一致について類似度スコアを計算します。
- 金額差:同額なら 1.0、$1 以内または 2% 以内なら 0.9、$5 以内または 10% 以内なら 0.5、それ以外は 0.0。
- 説明のジャカード係数:トークン集合に対して 0.0~1.0。
- 日付の近接性:同日なら 1.0、1日以内なら 0.7、3日以内なら 0.4。
near_dup_score = 0.4*amount + 0.4*description + 0.2*date。
0.7 ≤ near_dup_score < 0.95 の場合は確認対象として提示します。0.95 を超える場合は重複として扱い、0.7 未満の場合は独立した取引として扱います。
出力の仕様
{
"new": [
{ "id": "tx_20260115_017", "decision": "new" }
],
"duplicates": [
{
"incoming_index": 4,
"decision": "duplicate",
"duplicate_of": "tx_20251220_003",
"reason": "exact key match within 1 day window"
}
],
"review": [
{
"incoming_index": 12,
"matched_existing_id": "tx_20260108_005",
"near_dup_score": 0.86,
"diff": {
"amount_cents": [-4500, -4583],
"description_raw": ["AMAZON PENDING", "AMZN MKTP US*AB12CD"]
},
"suggested_action": "keep_incoming_drop_existing",
"rationale": "incoming is the finalized charge (post_date set, definite merchant code)"
}
],
"summary": {
"incoming_total": 142,
"new_count": 96,
"duplicate_count": 44,
"review_count": 2
}
}
ガードレール
- 符号が重要です。 返金と購入を絶対値でまとめないでください。キーには符号付きの金額を使用してください。
- 対象期間は1日のみです。 期間を広げると、給与サイクルをまたぐ誤検出が発生します。
- 同一口座内に限ります。 口座をまたいで重複排除しないでください。当座預金口座からの50ドルの振替と、貯蓄口座への50ドルの入金は、重複レコードではなく、それぞれ別のレコードです。
- レビュー時には元の説明を保持してください。 人間には両方の
description_raw文字列を表示し、正規化された形式は表示しないでください。 - 冪等性。 同じ入力に対して重複排除を2回実行しても、同じ出力になります。このスキルは
existingを変更しません。 - 監査。 重複として除外するたびに
duplicate_ofを記録し、新しいインポートに取引が表示されなかった理由をユーザーが追跡できるようにしてください。