連結会計シミュレーターの不具合を16件直した日:貸借一致とテスト全件通過では見つからない誤り
連結会計シミュレーターの不具合を16件直した日:貸借一致とテスト全件通過では見つからない誤り
連結精算表シミュレーターは、持分比率を0%から100%まで101×101通り流しても貸借が1円も狂わなかった。 テストも493件すべて通っていた。 それでも金額は間違っていた。
一日かけて16件直した。 まだ直っていないものが2件残っている。
正解値の出どころが2説あった
朝は出典の特定から入った。 シミュレーターのデータセットは論点19本ぶんの正解値を持っている。 ところが、その数字の出どころがドキュメントで2説に割れていた。
蔵書DB(398冊で50,157チャンク)を本文全文で検索して、データセットの数値と書籍本文を1本ずつ突き合わせてもらった。 結果は、会計実務の専門書2冊の使い分けだった。 取得と売却まわりの11本は資本連結の設例を集めた1冊から取っていて、例題として置いてある4本だけが別の計算問題集から来ていた。 残りの演習用の論点は、どの蔵書とも数値が一致しなかった。 自作である。
9月18日に作ってあった非公開ドキュメントへこの結果を追記させたら、日本語強調の lint が1件当たった。
** の閉じ記号を句読点の内側に置いた、いつものパターンである。
直してもらってから描画を確認した。
元ネタの表計算を探して、半日ぶんの走査が空振りした
数値を一度表計算に起こしてから TypeScript にした記憶があったので、その元ファイルを探させた。 ここからが長かった。
Dropbox の Excel を全件スキャンさせたら、4,766件が読めていなかった。 「連結精算表は1本もありません」という報告が来た時点で、走査そのものが成立していない。 原因は、クラウド上にしか実体が無いファイルを Python から直接開けないことだった。 コピーしてから読む方式に切り替えさせた。 今度はコピーが遅い。 更新日で絞り込んでも、シミュレーターを作っていた時期の Excel は1件も出てこなかった。
最後に Google ドライブ側を見たら、Excel ではなくスプレッドシートが1本だけ見つかった。 対応する論点は、追加取得の1本だけだった。 そしてここで思い出した。 表計算に起こすのはこれからやろうと思っていた話で、まだ作っていない。 探していたものは存在しなかった。
自分の勘違いで走査を回させたわけだが、副産物として「書籍のデータをウェブ教材にして、一致を確かめている段階」という現在地がはっきりした。
指摘11件を、関数を直接叩いて再現させた
午後は、別セッションで作ってあった計画書 memo/2026-09-20/consolidation-simulator-dd-plan.md の検証から始めた。
F1 から F11 まで、指摘が実際のコードで再現するかどうかである。
エンジンの関数を tsx で直接実行して計画書の金額と照合させたら、11件中11件が一致した。
あわせて、同率を除く101×101通りの持分比率を全部流させた。
貸借不一致は0件。
「貸借検査では F1・F2・F5 を検出できない」という計画書の主張が、これで裏づけられた。
BSの左右が合うことと、PLの金額が正しいことは別である。
ASBJ の一次資料と計画書の設例数値も突き合わせた。 設例4の数値に食い違いの疑いが出たので原文を直接確認させたところ、こちらは一致していた。
Codex の判定を、自分で付け直した
検証のついでに、計画書そのものに対する指摘が8件出てきた。 調査の中身は信用してよいが、実装計画としては着手前に直したいところがある、という位置づけである。
この8件を Codex(読み取り専用)に判定させた。 読ませたのは計画書とレビュー記録の2ファイルだけで、コードも過去メモも渡していない。 返ってきた重要度はそのまま採らず、中身を見て付け直した。
付け直しが効いたのは決裁の扱いである。 「ユーザーの判断が要る項目が埋もれている」への判定は中で返ってきたが、自分で読み返すと、ファイル分割もテストの組み合わせ数も実装者が決めればいい話だった。 決裁に上げるのは過剰と判断して、3件に絞った。
逆に、Codex の側からはこちらの見落としが1件出てきた。 支配継続取引で資本剰余金が負になったときの期末処理が計画書に無い、という指摘である。 既定の70→80を実行すると資本剰余金の期末残高が−5,000のまま残る。 連結会計基準30-2項を原文で確認すると、期末に零へ戻して利益剰余金から減額することを求めていた。 貸借は一致するので検査には引っかからないが、純資産の内訳と翌期への引継ぎが狂う。 これを F12 として計画書へ足した。
レビュー記録の初版が間違っていた箇所も1つある。 5件の不具合を「どれも同じ1行が原因」と書いていたが、実際は原因が5つに分かれていた。 Codex の指摘で訂正した。
改訂版には Codex の再レビューをかけ、「致命的な問題なし」まで持っていった。 判断が要る3件は3択フォームで決裁した。
直す前に、画面へ注記を出した
修正が本番に出るまでのあいだ、読者は間違った金額を見ることになる。 そこで Phase 0 として、ページ上部に「一部の組み合わせで数値を見直しています」という注記を入れさせた。 PC幅とモバイル幅の両方で表示を確認してから15:12にコミットし、15:15にデプロイを起動した。
ビルドに12分から20分かかるので、待っているあいだに実装へ入ることにした。 ただし、ビルド中のソースを書き換えると、中途半端な状態が本番へ混ざる。 最初はビルド対象外のテスト側から着手させた。
it.fails を17件置いてから、1件ずつ通常のテストへ戻す
進め方は、失敗することを期待する回帰テストを先に全部置いてしまう形にした。
F1 から F12 までを it.fails として書かせ、17件とも意図した金額の不一致で落ちることを確認した。
落ち方が型エラーではないことまで見ておかないと、直したつもりで通ってしまう。
確認してから15:19にコミットした。
続けて、ログを出力するだけだった整合性テストを assert に改めさせた。 これが効いた。 最終残高の照合を4事例から8事例へ広げた瞬間、持分法の取得が専門書の設例と合わないことが出てきた。 30→40は資産合計が書籍より6,560多く、当期純利益は1,740少ない。 F13 である。 「見ているつもりのログ」は、見ていないのと変わらなかった。
ASBJ の設例1から7までの原文から入力と明記された金額を拾い、テスト用のフィクスチャに書き起こさせた。 会計上の関係と遷移方針を返す純粋関数も、別モジュールへ切り出させた。
土台ができたところで修正に入り、15:51から17:05までに fix コミットが14本並んだ。
| 時刻 | 直したもの |
|---|---|
| 15:51 | 同率の年度と、その他投資の売買の区分(F9、F11) |
| 15:59 | のれんの償却を未償却残高で止める(F6) |
| 16:02 | 持分法の土地の評価差額を連結BSへ載せない(F1) |
| 16:05 | 期末に支配を獲得した年度の取得前PLを取り込まない(F2) |
| 16:08 | 持分法の損失も仕訳にする(F3) |
| 16:17 | 前提を1項目だけ変えても貸借が崩れないようにする(F4) |
| 16:21 | 支配獲得時の利益剰余金を省いたときの既定値をそろえる(F14) |
| 16:22 | 持分計算表の残存投資に未償却のれんを含める(F8) |
| 16:25 | 資本剰余金が負になったら期末に零へ戻す(F12) |
| 16:33 | 当期発生の負ののれん発生益をPLに計上する(F5) |
| 16:36 | 追加取得の原価を仕訳と持分計算表で同じ単価から計算する(F7) |
| 16:39 | 中間計算値を仕訳と同じ時点の金額にそろえる(F10) |
| 16:53 | 持分法の取得を専門書の設例に合わせる(F13) |
| 17:05 | 持分法の売却後の投資簿価をそろえる(F16、F17) |
F13 を直すためにテストを広げたら、そこから F16 と F17 が出てきた。 持分計算表が売却分を個別上の取得原価で落としていた件と、関連会社でなくなった後の残存投資に持分法の修正額が残っていた件である。 直したぶんだけ新しく見つかった。
終わってみて、対象4ファイルのテストは772件が成功し、失敗は0件になった。
カバレッジはエンジンが行99.35%、新しく切り出した状態モジュールが行98.36%である。
未修正で残ったのは2件だけだった。
小数の単価で仕訳が±0.5〜1円ずれる F15(it.fails のまま追跡している)と、テストでまだ確かめていない F18 である。
同じ間違いを2回している
F4(画面から当期純利益だけ変えると貸借が10,000崩れる)は、初めて見つけた不具合ではなかった。 5月16日に同じ原因で一度踏んでいて、そのときはテスト側の期待値を手で補正して通していた。 アプリの側は直していない。
検証のレビューでは「既知問題の再発見である。経緯を書かないと同じ直し方を繰り返す」と挙がっていた。 まったくそのとおりだった。 テストを緑にする方法が2つあるとき、安いほうを選ぶと4か月後に同じ場所へ戻ってくる。
明日の最初に決めること
決裁では「状態モデルを作ってから、まとめて直す」を選んでいた。 実際にやったのは、経路ごとに1件ずつ直してコミットを刻む進め方である。 テストは全部通っているし、16件は直った。 それでも、決めたことと違う手順で進んだ事実は残る。
経路別の実装をこのまま正とするか、決裁どおり状態モデルへ寄せ直すか。 明日はここから始める。
学び
- 貸借一致は正しさの証明にならない。101×101通りで不一致0件でも、PLの取込範囲が間違っていれば金額は狂う。左右が合うことと中身が合うことは別の検査が要る
- ログを出すだけのテストは、書いていないのとほぼ同じだった。assert に変えて照合を8事例へ広げた瞬間に F13 が出てきた
- 修正が本番に届くまで日をまたぐなら、注記だけ先に出せる。今回は不具合を1件も直さないうちに Phase 0 としてデプロイした
- レビューの重要度は、出してきた側の判定をそのまま使わない。読み直したら「決裁に上げるべき」は過剰で、逆に見落としが1件あった