朝、5/18 の積み残しメモを開いた
朝一でリポジトリに座って、まず memo/2026-05-18/00-backlog.md を Claude Code に読ませた。前日の自分が10件強の積み残しを書き出して優先度順に並べてくれていたので、上から拾えばいい状態になっていた。最優先には CFWS Issue(.claude/issues/2026-04-14-cfws-com-check-nonzero.md)の #3・#4 が残っている。連結精算表の COM 検証が一部のセルで非ゼロになる、というやつ。
「ちょっと確認してください」と軽く渡したつもりだったが、Claude Code に最新の CFWS で COM 検証を回させたら、全 check=0 でクリーンに通ってしまった。4/14 17:10 生成の成果物では再現しない。他のライフサイクル成果物でも検証して、いずれも再現せず。
issue を立てた時点では確実に再現していた症状が、その後の修正の副産物として消えていたパターン。原因コミットを特定するのは時間がかかるし、いま動いているコードを壊す危険もある。
とはいえ消すだけで終わらせるのは怖い。同じ症状が別のタイミングで戻ってきたとき、過去 issue が残っていないと、また同じ調査をゼロから始めることになる。
「テスト書いてるんだから全部回せ」と決めた
ここで一瞬「じゃあ issue クローズで終わりか」と流しかけたが、自分でブレーキを踏んで方針を切り替えた。
バグが再現しなくなったときの正しい挙動は、issue を消すことではなく再発したら即落ちる場所にテストを置くことだ。Claude Code に「これだからテスト書いてるってことですよね。だから全部やったらいいんじゃないですか。イシューをクローズ扱いにして、テストとして固定化」と返した。
Claude Code が既存の verify_excel() を再利用して、Dropbox 配下の最新生成 CFWS を全部 smoke test で回す回帰テストを追加してくれた。
pytest を回したら、最初は warning スタックトレースまみれで落ちかけた。原因は verify_cfws_excel.py の冒頭で sys.stdout をユーティリティ側で上書きしていて、pytest の capture と衝突していたこと。スクリプト単体で実行したときには UTF-8 出力を強制するための副作用が、ライブラリとして import された瞬間にテストランナーの標準出力ハンドリングを破壊する。
「ロジックは純粋関数に閉じ込め、副作用はエントリポイントに集約する」という普段のルールが、ここで効いた。__main__ ガード内に sys.stdout の差し替えを移動させて、import 経由で呼ばれたときには副作用が走らないようにした。再実行で 3 passed、全 PASS。issue は「解決済み(回帰テストで固定化)」に書き換えて閉じた。
このやり取りで残った教訓は、**「再現しない issue は消すな、テストの代わりにしろ」**の一行に尽きる。
教科書 Part 2 のユーザーレビュー — implementation-notes.html を作業ログにする
CFWS の片付けが終わったところで、ユーザー(自分)から本命の指示が降ってきた。Part 2 のユーザーレビューを順次やってほしい、と。具体的には3タスク。
- CH9 の本文字数が 5,020 字で、指示書目安 6,500〜8,500 字の下限に届いていない
- CH7 ↔ CH8 の Part 跨ぎナビが普通の章ナビと同じ見た目で、「ここで Part が切り替わる」というシグナルが弱い
- Part 2 の SVG が足りない章(残り 57 問)への補助図追加
ここで自分から追加要件を1つ足した。実装が仕様から逸脱した点や、自分が知っておくべき判断は全部 memo/2026-05-19/implementation-notes.html に残し続けてほしい、と。あとから「なぜここでこの選択をしたか」を辿れるようにする保険。
Claude Code に初期化させて、タスクごとに追記していく運用にした。HTML にしたのは、スクショや figure を直接埋め込みたかったからで、Chrome で開けば作業ログとレビュー資料を兼ねられる。後でユーザー(自分)が implementation-notes.html を立ち上げるよう Claude Code に頼んで、Chrome のタブで開いてレビューする流れも自然に動いた。
タスク1:CH9 本文を 5,020 → 7,890 字に肉付け
実測してみたら CH9 は 5,935 字あった。backlog の数字よりは少し多かったが、それでも目安の下限を割っている。Claude Code に「目安範囲内(6,500〜8,500)に収まるよう肉付け、ただし内容を薄めず具体例と数値を増やす方向で」と渡した。
肉付けの方針として、抽象的な説明を増やすのではなく、既に書かれている論点の具体例を1段深く掘ることを指示した。たとえば「営業 CF と純利益の乖離を読む」という節があれば、乖離の代表的なパターンを2つに増やし、それぞれに小さなケーススタディを添える。文字数稼ぎの空文を入れない縛り。
仕上がりは 7,890 字。目安範囲のど真ん中に着地した。dev server を立てて実機で読んでみたが、付け足された段落が浮いていない。元の論理展開を保ったまま、具体例の解像度だけ上がっている。implementation-notes に「CH9 5,935 → 7,890 字、目安範囲内」と1行記録。
タスク2:CH7 ↔ CH8 の Part 跨ぎナビ
CH7 は Part 1 の最終章、CH8 は Part 2 の最初の章。今までは普通の「次の章へ」「前の章へ」と同じ見た目で、ユーザーが「ここで Part が変わる」と気づけない状態だった。
Claude Code に「Part 跨ぎ専用のナビ要素を CSS で立てて」と渡した。pager--part-transition というモディファイアと、pager__part-badge のスタイルを追加。CH7 章末から CH8 へ進むとき、ボタンに「PART 2 に進む ── 数字を投資判断に変える」というバッジ付きのラベルが出るようにした。
ここで実装の細かい判断が一つ。バッジを目立たせすぎると章ナビ全体のリズムが壊れるので、色は既存のアクセントカラーを薄く使い、Part 名と副題を縦2段で配置するに留めた。読者が「あ、次の Part に切り替わるんだな」と気づける最低限のシグナル量を狙った。
Chrome DevTools MCP で実機を開いて、CH7 末尾までスクロールしてスクショを取った。バッジがきちんと表示されている。CH8 側でも逆方向(前章への戻り)を確認して、両方向で Part 跨ぎが正しく見えていることを確認。
スクショは implementation-notes に貼って残した。同じファイルにビフォー/アフターを並べておくと、レビューする側が言葉だけ読まずに視覚で確認できる。
タスク3:Part 2 の SVG 補強 — 「新規作成しない」に方針転換
ここが今日の一番の判断ポイントだった。
最初は「残り 57 問への補助 SVG を1枚ずつ作る」つもりで構造調査に入った。クイズページ側(18 ページ)を Claude Code に舐めさせたら、ページ側は全問 figure 完備だった。「残り 57 問」というのはページ側ではなく、教科書ページ内に埋め込まれた InlineQuiz 側の話だったと気づいた。
ここで一度立ち止まる。backlog に書いた過去の自分の「57 問」が、どこの 57 問を指していたのか曖昧になっていた。クイズページ側の問題リストと教科書側の InlineQuiz は別物で、同じ問題コードを持っていても出現場所が違う。backlog を書いたときの自分は「教科書側の InlineQuiz で figure が無い問」を指していたはず、と仮説を立て直す。
そこで教科書ページ側の InlineQuiz を全件調査させたら、highlight: null(= figure 未割り当て)の問が 59 問あった。backlog の「57 問」とほぼ一致。仮説が裏取りできた瞬間で、ここから方針転換の根拠が固まった。
ここで方針を切り替えた。新規 SVG を1枚ずつ作るのではなく、既存 figure の highlight キーに問を割り当てる。Part 2 で使われている既存の figure コンポーネント(Part2OcfVsNetIncome など)は、内部で複数の highlight モードを持っている。問の論点が figure 側の highlight 軸と一致するなら、新しく図を描かなくても figure を再利用して highlight キーを渡すだけで補強できる。
最初に CH9 sec-2 のクイズ Q02 で試した。CH8 にある Part2OcfVsNetIncome をそのまま CH9 にも渡してみたら、グラフが表示された。同じ問題コードが CH8 で figure 付き、CH9 で figure なしで重複していたパターンで、データ側はもう揃っていた。これが見つかった瞬間に、59 問のうちかなりの割合が既存 figure の流用で片付くと確信した。
Claude Code に「サブエージェント 3 並列で TS ファイル単位に分担」と指示した。3 並列で走らせて、各サブエージェントが自分の担当 TS ファイルで「どの問題にどの figure の highlight キーを割り当てるか」を決めて書き換える。
衝突を避けるためファイル単位で分けたのが効いた。同じ figure を2つのサブエージェントが同時に書き換えるリスクは消したが、figure 側の Highlight 型は事前に main エージェント側で一括取得してサブエージェント全員に渡しておいた。共有読み込み専用情報を main で揃え、書き込みだけサブエージェントに分散させる構図。
3 並列の結果を回収したあと、各 figure キーがページ側の figureHighlights 配列に実在するかを検証させた。サブエージェントは個別の TS ファイルしか見ていないので、ページ側との整合は最後に main で取る。これを抜くと「figure キーが間違っていて画面に何も出ない」事故が起きる。
整合 OK を確認した上で、dev server で CH9 sec-2 のクイズ、CH10 の OCF クイズ、07-macro のグラフ表示を実機で確認して、想定通り figure が表示されていることを目視で詰めた。
「図を作らなかった問は、ふさわしくないってこと?」への回答
タスク3が片付いたあと、ユーザー(自分)が一つ質問を投げた。「figure を当てなかった残りの問は、その問題にふさわしくないということなんですか?」
これは正確には違うので、2つの理由に分けて回答してドキュメント化した。
理由 A:既存 figure の対比軸とクイズの論点軸が一致しない(軸ズレ)
既存 figure は「営業 CF vs 純利益」「売上 vs 営業利益率」など、特定の2軸の対比で設計されている。クイズの中には「複数年の傾向を時系列で見る」「業界平均との比較」など、figure の軸とは別の論点を問うものがある。軸が合わないところに無理に figure を貼ると、読者に「この図のどこを見ればいいんだ」と迷わせるだけで、教育効果が下がる。
理由 B:そもそも対応するデータが存在しない
既存 figure はクイズで使う実在企業のデータをそのまま流用している。一方、クイズには架空のシナリオ問題や、まだデータ準備が済んでいない企業の問が混じる。
データが無い問に対しては、figure を割り当てる前にデータセット側を埋める必要がある。これは別フェーズの作業で、今日の SVG 補強タスクの範囲外。データ収集の優先度を別に立てて、そこから降ろす。
この A/B の区別を implementation-notes.html の §3-4 として追記した。「B 系統はやった方がいい?」と聞かれたが、「とりあえずいっか。判断だけドキュメントしといて」で着地。後から再評価できる状態にしておく方が、いま全部潰すより費用対効果が高い。
判断をドキュメント化するとき大事なのは、「やらなかった理由」を残すことだ。「やったこと」はコミットログを追えばわかるが、「やらなかった理由」はソースのどこにも残らない。半年後の自分や、別の人がリポジトリに入ったとき、implementation-notes.html の §3-4 を読めば「ああ、ここはあえて空けたのか」と即座に理解できる。
振り返り:今日の判断のキモ
3つ並べて記録しておく。
- 再現しない issue はテストに固定化する。「現状再現せず」で消すのではなく、回帰テストの種にする。CFWS の COM 検証で実践した。検出用スクリプトを
__main__ガード内に隔離してから pytest に取り込むのも、副作用を分離する基本動作。 - 既存 figure の流用判断は「対比軸が合うか」で決まる。新規作成に走る前に、既にあるものの highlight キーを増やせないかを先に検討する。Part 2 の SVG 補強で実践した。サブエージェント並列に放り込む前に、Highlight 型を main で一括取得してから配るのも肝。
- やらない判断こそドキュメント化する。「とりあえずやらない」を曖昧にしておくと、半年後の自分が同じ調査をやり直す。implementation-notes.html の §3-4 として残したのが今日のハイライト。「やった」はコミットログ、「やらなかった」はノートに残す。
税理士・会計士視点での応用
顧問先向けの教育コンテンツや確定申告マニュアルでも、図の流用判断は同じロジックで決められる。既存の図を再利用するか、新しく描き起こすかは、図の対比軸と説明したい論点の軸が一致しているかどうかで決まる。軸がズレているところに無理矢理流用すると、読者が「どこを見ればいいか」を見失う。新規作成の前に「いまある図の highlight 軸を増やせないか」を必ず先に検討する。
また、「再現しない不具合」をどう扱うかも事務所運営に効く。クライアントから「前回起きたあの計算ズレ、今は起きてないんですけど」と言われたとき、issue を消すのではなくチェックリストの一項目に固定化しておくと、再発時に即座に気づける体制になる。月次レビューのテンプレートに「過去の異常パターンが再発していないか」の項目を入れておくのと同じ発想。