• #Excel
  • #差分検出
  • #キャッシュフロー計算書
  • #Claude Code
  • #Codex
  • #Python
  • #リファクタリング
開発eurekapu-nuxt4メモ

Excel差分検出スキルとCFマッピングJSON自動生成

朝、手修正したExcelファイル(_KKサフィックス付き)とスクリプトの出力を並べて見比べていた。セルの数が多すぎて、目視では差分を拾いきれない。「これ、スクリプトに任せたい」と手が止まったところから今日の作業が始まった。

もう一つの軸は、仕訳データからCF項目の対応表を自動で引き抜く仕組み。全38論点のExcelを横断して、借方・貸方のCF科目をQ番号ごとに整理する。

どちらも「計画を書いてからCodexに叩いてもらう」フローを4往復回して、実装に入る前に設計の穴を埋め切った1日だった。

1. Excel差分検出スキルの設計

背景

eurekapu-nuxt4では、Pythonスクリプトが各論点のExcelファイルを自動生成する。ユーザーが手修正した版(_KKサフィックス)と比較して「何が変わったか」を把握したい。だが手作業では、行の挿入・削除が絡むと前後のセルがずれて追跡できなくなる。

6カテゴリの変更検出

Codexレビューの初回で「セル単位の差分比較では行列の挿入削除を見落とす」と指摘が飛んできた。設計を2次元グリッドベースに書き直し、以下の6カテゴリで変更を拾う方針に落ち着いた。

カテゴリ検出方法
行挿入グリッド行数の増加 + ヘッダ文字列のマッチング
行削除グリッド行数の減少 + 欠落行の特定
列挿入列ヘッダの差分検出
列削除同上
セル値変更対応セル同士の値比較
式変更openpyxlで数式文字列を直接比較

_KKサフィックスがないケースへの対応

全ファイルに_KKが付いているわけではない。同じディレクトリに同名ファイルが複数ある場合、タイムスタンプの新旧で「手修正版」と「スクリプト出力版」を判定するロジックを追加した。

def resolve_pair(directory: Path, base_name: str) -> tuple[Path, Path]:
    kk = directory / f"{base_name}_KK.xlsx"
    if kk.exists():
        return kk, directory / f"{base_name}.xlsx"
    # _KKなし: タイムスタンプで新旧判定
    candidates = sorted(directory.glob(f"{base_name}*.xlsx"), key=lambda p: p.stat().st_mtime)
    return candidates[-1], candidates[0]

Codexが突いた致命的4点

#指摘内容対応
1セル単位比較では行列の挿入削除を検出できない2次元グリッドベース設計に全面書き直し
2ヘッダ行の特定がハードコードされている先頭N行のパターンマッチで自動検出に変更
3マージセルの扱いが未定義openpyxlのmerged_cellsを展開してから比較
4出力がstdoutのみで確認しづらいHTMLレポート + JSON出力を追加

4番目は自分でも気づいていなかった。標準出力だけに差分を流していたところ、ユーザー(自分自身)に「どこに出力されてるの?」と指摘されて目が覚めた。


2. CFマッピングJSON/CSVの自動生成

やりたいこと

仕訳のE列(借方CF科目)とJ列(貸方CF科目)を全38論点のExcelから抽出し、Q番号ごとのCF項目対応表をJSON/CSVで吐き出す。リファクタリングで「勘定科目 -> CF区分」のマッピングをハードコードからデータ駆動に切り替えるための下準備。

Codex 4ラウンドの軌跡

計画書v1を書いてCodexに投げたら「実装はまだいい、計画書をまずドキュメントにして」とユーザーに止められた。そこからv4まで4回のイテレーションを回した。

VersionCodex指摘修正内容
v1検証の方向が逆(JSON->Excelではなく、Excel->JSONで検証すべき)検証フローを反転
v2_EXPLICIT_CF_TYPE_FROM_JSONをマスタdictにすると、論点固有の例外を吸収できない論点別オーバーライド層を追加
v3ラベル正規化が不十分(全角半角・括弧の揺れ)unicodedata.normalizeとカスタム正規化関数を導入
v4LGTM--

v2の「マスタdict化が危険」という指摘は、手が止まった。38論点のうち3つだけ特殊なCFラベルを使っていて、マスタ辞書で一律に引くと上書きされてしまう。論点IDをキーにしたオーバーライド層を挟むことで、汎用マスタと個別例外を両立させた。


3. 古いExcelファイルの整理

作業の合間に、ディレクトリに積み上がっていた古いExcelファイルを old/ に移動した。

  • 移動前: 649ファイル
  • 移動後: 410ファイル(_KKと最新日付のみ残す)
  • 239ファイルを old/ へ退避

ファイル数が減っただけで、スクリプトの実行時間が体感で縮んだ。globのマッチ対象が減るので当然だが、散らかった部屋を片付けた後のような気分だった。


試行錯誤

#テーマ試したこと結果気づき
1差分レポート出力先stdoutのみに出力ユーザーに「どこ?」と聞かれるHTMLレポートとJSONを併用すべき
2計画書v1いきなり実装コードを書き始めるユーザーに止められる計画書を先にドキュメント化してレビューに回す
3マスタdict一本化全論点共通の辞書で引く設計3論点で例外が壊れるオーバーライド層を挟む
4ラベル比較文字列の完全一致全角半角の揺れで不一致多発normalize + カスタム正規化を前段に入れる
5検証方向JSON -> Excel方向で検証Codexに「逆だ」と指摘されるExcel(原本)-> JSON(生成物)が正しい検証方向

今日の学び

  • 差分検出はセル単位で比較するとずれる。行列の挿入削除を先に検出してからセルを対応付ける2段階が必要
  • 「標準出力に流しておけばいい」は自分だけの感覚。確認しやすい形式(HTML/JSON)で出力する習慣をつける
  • Codexレビューを計画段階で回すと、実装前に設計の穴が4つ見つかった。コードを書いてから見つけるより手戻りが圧倒的に少ない
  • マスタ辞書の一本化は魅力的だが、例外が3件あるだけで破綻する。汎用層+オーバーライド層の2層構造が安定する
  • 「実装はまだいい、まず計画書を書け」というブレーキは正しかった。計画書v1からv4まで4回書き直す過程で、実装時の迷いがほぼ消えた

関連リンク