「積み残しってありますか」を毎朝聞かずに済ませるための状態ブロック

開発claude-code-tools

「積み残しってありますか」を毎朝聞かずに済ませるための状態ブロック

朝いちばんに、ほぼ毎日同じことを聞いている。

「積み残しって何がありますかね」。

昨日立てた計画が翌日に持ち越されていたり、途中まで実装して止まっていたり、終わっているのに計画書へ反映されていなくて未了のまま残っていたり。 パターンはだいたい決まっている。 決まっているなら、毎回しゃべらなくていいはずだ。 スラッシュコマンドにしたい、と言うところから今日が始まった。

出させてみたら、10件のうち5件はすでに終わっていた

コマンドを設計する前に、今ある積み残しを出させた。

Googleタスクは10件が期限超過で、最長のもので9日過ぎていた。 ただ、こういうときは終わっているのに閉じ忘れているものが混ざる。 サブエージェントを5本並列で走らせて、1件ずつ実物ベースで進捗を確認させた。

見に行かせたら、すでに片付いていたものが出てきた。 SEOのフェーズDは、サーチコンソールを実際に開かせたら全項目クリアしていた。 5xxエラーは183件から119件へ、クロール済みで未登録のページは303件から273件へ減っていた。 上位10ページの顔ぶれも、ベースラインと10件すべて一致していた。 台帳に書き戻させて、タスクは10件から5件になった。

Googleタスク以外の一覧も出し直させたら、前回より1件増えていた。 増えていたのは「積み残しコマンドの設計」の決裁フォームで、回答待ちのまま止まっていた。 積み残しを減らそうとしているのに、そのためのコマンドの設計自体が積み残しになっていた。

目で見て確認する方式が成立しない量だった

計画書の未了項目を数えさせた時点で、当初の想定が崩れた。

memo/ の未チェックは、148ファイルに散らばった1,669件あった。 毎朝これを読んで棚卸しするのは無理だ。 リストを出してもらって目で見るという今までのやり方は、量の問題で成立しなくなっていた。

ここで設計の向きが変わった。 毎朝スキャンして計画書を読み直すのではなく、計画書の側に「今どの状態か」を書いておく。 機械が読むのはその宣言だけでいい。

計画書のH1直下に、状態をHTMLコメントで置く

決めた書式はこれだけ。

# 計画書のタイトル

<!-- carryover
status: in-progress
opened: 2026-08-11
closed:
checked: 2026-08-11
targets: .claude/commands/, scripts/scan-carryover.mjs
successor:
next: Phase 2 の集計スクリプトを書く
-->

status は棚卸しの一次フィルタになり、opened からは何日抱えているかを算出する。 checked には最後に状態を照合した日を書く。 targets はこの計画が触る対象で、そこへのコミットがあるかどうかが完了判定の材料になる。 next には、翌日そのまま着手できる一手を1行だけ書く。

frontmatter ではなく HTML コメントにしたのは、memo/ の Markdown を pandoc で HTML 化するときにタイトルが二重に描かれる問題と干渉するからだ。 コメントなら Markdown でも HTML 単体でも同じ書式が通り、pandoc も git も素通しする。

status: done を打った瞬間に、未了が消える

書式を決めたあと、Codex でレビューさせた。 3回まわしたなかで、いちばん効いた指摘がこれだった。

status はファイル全体の局面しか表さない。 個々の項目の内訳は持っていない。 だから status: done を根拠にチェックボックスを一括で埋めると、31項目のうち3項目が実は未了でも、その3件は消える。

消えるのはチェックだけではない。 放置された積み残しは、未チェックのまま残っているから次の朝に見つかる。 一括更新で埋めた3件は、誰も気づかないまま完了扱いになり、二度と浮かんでこない。 見えないまま消えるほうが、放置より始末が悪い。

同じ理由で、next の1行に複数の未了をまとめるのも禁止にした。 未了が3件あるなら、項目として3件残す。 未了項目を全部列挙して1件ずつ確認が取れたときにだけ done を打てる、と規約に書いた。

進捗を項目単位で持つと決めたので、判定は共通の中間表現に落としてから見ることにした。 Markdown なら - [ ]- [x] を、HTML 単体なら <input type="checkbox">checked 属性を見る。 どちらの形式でも、未了か済みかだけを取り出す。

同じ計画を2回数えない

もうひとつ Codex から出たのが、同じ計画が2件に見える問題だった。

memo/ には pandoc で生成した HTML が同名で並んでいる。 .md.html を両方数えると、1本の計画が2本になる。 ルールは単純に決めた。 同じ名前の .md があるなら .html は生成物として無視し、.md が無い .html だけを正本として扱う。 ファイル名だけで判定できるので、中身を読まずに済む。

指摘を受けて実測を取り直したら、Codex の数字のほうが正しかった。 自分が先に出した組数は、探索の深さが足りずに取りこぼしたものだった。

判定材料は、パスの実在とコミットから取る

規約を決めたあと、集計スクリプト scan-carryover.mjs を書かせた。 判定ロジックは純粋関数に分けさせている。

最初に動かした版は、走りこそしたが分類が実用にならなかった。 「終わったのに未チェック」を1件も検出できていない。 状態の宣言がまだどの計画書にも入っていないので、当然だった。

そこで、項目本文に書かれたパスが実在するかと、そこへのコミットがあるかを証拠に使う形へ直させた。 今度は閾値が甘くて誤検出が76件出たので、件数ではなく割合で判定するように書き直した。 dotclaude の計画書を例に取って、successor(後継文書)を書いただけで候補に上がることを実証できた。

テストは1件落ちた。 日本語の読点の直後に置かれたパスを拾えていなかった。 そこを直して、Phase 2 まで通した。

判断6件は、ターミナルではなく画面で答えた

設計中の判断は6件あった。 ターミナルの選択肢では前提を読みながら選べないので、計画書の HTML に埋め込んだ3択で答えた。

6件とも推奨どおりを選んだが、1件だけコメントを書いた。

警告を出すんじゃなくて、コミット時に締めコマンドの実行にしてくれませんかね。これ私が手動で言う必要ないと思うんですよ。

checked が古いときに「更新してください」と警告を出す設計だった。 警告は読み飛ばせる。 読み飛ばせるものは、いずれ全部読み飛ばす。 コミットのタイミングで締めのコマンドを走らせる形に変えてもらった。 学習ゲートが /learn を要求するのと同じ構えで、自分が口で言う工程を1つ減らした。

設計とスキャナは 556103c5 でコミットした。

片付いた記録は、消さずに棚へ上げる

同じ日に、issue の置き場も直した。

.claude/issues/.gitignore で除外していた。 ローカルの知識として置いておく想定だったが、2台運用でもう一方の機体から過去の踏み跡が読めない。 リポジトリが private であることと、機密が混ざっていないことを確認させてから、追跡対象に戻した(3541491f)。

ただ、311ファイルを永久に手前へ積み上げるのも違う。 片付いたものは _archive/YYYY-MM/ へ移す運用にした(18577994)。 消さないので履歴は残り、手前は棚卸しできる量に保たれる

仕分けの判定材料はファイル名の日付とステータス欄だけにした。 更新時刻は git checkout で壊れるので使えない。 - [x] 解決済み は移し、- [x] 未解決 なら日付に関係なく手前へ残す。 印が無いまま30日以上経ったものは履歴とみなす。 - [x] 原因特定済み を解決扱いにしないことも書き添えた。 原因が分かっただけで直っていないものがある。

実行すると手前に30本、アーカイブに281本という配分になった。 移動でリンクが切れないよう参照箇所を数えさせたら、生きているドキュメントからは6ファイル7箇所だけだった。 そこは自動で書き換えて、壊れた参照は0件で済んだ。

本番が古いままだったのは、ブランチ名だけが理由だった

デプロイ後の検証で、JSが926本まとめて404になった。

切り分けさせたら、本番ドメインが配信していたのは古いビルドだった。 新しいビルドは preview 側に入っていた。 別セッションがブランチを切ったまま /deploy を走らせたので、wrangler が preview 扱いにしていた。

中身は同じだった。 master と HEAD は同一コミットで、ビルドもアップロードも成功していた。 ブランチ名だけが本番判定を外していたので、再ビルドせずに出し直すだけで済んだ。 復旧までにかかったのは1.07秒だった。

恒久対策として、デプロイ先を master 明示にして、配信されている buildId を照合する検証を足した(f12a0079)。 どのビルドが本番に載っているかを、目視ではなく機械が突き合わせる。

なお、この切り分けの途中で本番への接続がタイムアウトし始めた。 犯人は自分が起動した検証プロセスだった。 タスクを止めたあとも孤児として残り、20分間32並列で本番を叩き続けていた。 ラッパーを止めても node 本体が残ることがあるので、以後は本体まで見て落とすようにした。

今日決めたこと

  • 状態は計画書が宣言する。機械はそれを数えるだけにする。1,669件を毎朝読み直す前提の設計にしない
  • done は宣言ではなく、未了項目を1件ずつ確認した結果として打つ。まとめて埋めた3件は誰にも見つけてもらえない
  • 片付いた記録は消さずに _archive/ へ移す。手前に残すのは生きている問題だけにする