Imported from nasumiso/KSKInvestSystem (
.claude/skills/promote-to-command/SKILL.md). Install upstream withnpx skills add nasumiso/KSKInvestSystem --skill promote-to-command. Copyright stays with the author.
繰り返し運用処理の昇格 (promote-to-command)
開発中に都度ワンショットで書く処理 (python -c "..." や複数行 Bash) を、
再利用可能な形 (CLIサブコマンド / 関数 / 開発スクリプト) に昇格させる。
目的は「次に同じことをするとき1コマンドで済む」状態にすること。ただし 何でも昇格させるのではない — less is more。下の判断基準で取捨する。
いつ昇格を提案・実行するか
自動検知 (提案のトリガー)
次のすべてを満たしたら「これ、昇格しますか?」と1行で提案する:
- 同一セッション内で同じ系統の再現可能な処理を2回以上実行した
- それがスクレイピング/DB更新そのものではないか、または引数を変えれば 繰り返し使える定型処理 (例: 表示用HTML再生成、特定銘柄の単体取得・確認)
- 一度きりのデバッグ (print差し込み、その場限りの調査) ではない
提案は提案にとどめ、押し付けない。ユーザーが承認したら本スキルの手順で実行する。
明示トリガー
ユーザーが「この処理を昇格して」「CLI化して」等と指示したとき。
昇格すべきか判断する (取捨基準)
| 昇格する | 昇格しない (罠) |
|---|---|
| 表示用ファイルの再生成 (例: market_data.html) | 一度きりのデータ移行・クリーンアップ (migrate系で既に対応済) |
| 特定銘柄の単体取得・確認 (業績/指標/理論株価/価格) | スコア計算ロジック (calc_*) → 単体テストでカバーすべき |
| パーサ単体の動作確認 (HTML→構造化) | その場限りのアドホック調査 |
| 引数を変えて繰り返す定型処理 | 投機的な「将来使うかも」(YAGNI) |
迷ったら「シニアが overcomplicated と言うか?」を自問 (CLAUDE.md 行動原則2)。
calc_* 系を CLI 化したくなったら、まずテストで足りないか考える。
昇格先の標準形を選ぶ
処理の性質で昇格先を決める:
- 既存モジュールの機能 → そのモジュールの
.pyにCLIサブコマンドを追加。- 例:
make_market_db.py html(DB更新せず HTML だけ再生成)。 if __name__ == "__main__"のmain()でsys.argvを分岐 (既存の make_stock_db.py / shintakane.py のスタイルに合わせる。argparse は 既存ファイルが使っていればそれに合わせる)。- 既存の公開関数を再利用して呼ぶだけにする (ロジックを二重に書かない)。
- 例:
- 横断的な開発補助 (複数モジュールをまたぐ・検証専用) → 専用スクリプト。
- 既存の単発スクリプト (
analyze_market.py等) と同じ scripts/ 直下、または 開発補助が増えるならscripts/dev/を新設して集約。
- 既存の単発スクリプト (
- 純粋なデータ変換・ヘルパー → 既存モジュールに関数として追加。
昇格の実行手順
- 既存CLIを必ず先に確認 — 既に同等コマンドが無いか grep する
(
grep -rn "__main__\|sys.argv\|add_parser" scripts/)。 shintakane は既存CLIが充実しているので重複を作らない。 doc/COMMANDS.md も確認。 - 昇格先の標準形を上記基準で選ぶ。複数解釈あればユーザーに確認。
- 既存の公開関数を再利用して実装。新規ロジックは最小に。
- テスト方針 (.claude/rules/testing.md):
- CLI引数分岐の追加だけ (既存関数を呼ぶ) なら、その関数が既存テストで カバーされていればテスト追加は不要。
- 新規ロジックを足したらテストを書く (parametrize集約・1PR5本以下)。
- testing.md のモジュール→テストのマッピングに従い回帰確認。
- doc/COMMANDS.md に1行追記 (CLIサブコマンドを足した場合)。使い方と 「何をする/しない (DB更新の有無等)」を明記。
- 反映方法 (commit/PR or main直push) はユーザーに確認 (軽微なら直push可)。
問い合わせログ (.claude/query_log.jsonl)
セッション内検知は「同じ系統を2回」に気づけないことが多い (長いセッションでは 序盤を覚えていられない、セッションをまたぐ繰り返しは原理的に見えない)。 実際に投げた問いを1行ずつ残し、後から棚卸しすることで補う。
何を残すか
DB・データに対するワンショットの問い合わせを書いた/書こうとしたとき。
python -c で shelve を開く、build_fill_episodes() を呼んで集計する、等。
既存CLIで済ませたものは書かない (make_stock_db.py list を叩いた等)。
{"ts":"2026-08-30","intent":"何が知りたかったか (自然言語)","target":"どのデータ/関数","args":{"code_s":"9337"},"how":"実際にどう代用したか","session":"何をしていた最中か"}
intentは自然言語でよい。読むのは LLM なので語彙を統一する必要はない。 無理に正規化すると書くのが億劫になって記録されなくなる。argsを分けて持つのが肝。intentが同じでargsだけ違うエントリが並べば、 それは引数付きコマンド1本にできるという結論が機械的に出る。howは昇格時に何を置き換えるかの手がかり (既存関数を呼ぶだけか、 ロジックをその場で書いたか)。
いつ書くか
タスク完了報告のタイミングでまとめて。都度書くと忘れるので、区切りで 「今回データに投げた問いは何だったか」を振り返って数行 append する。 同系統をまとめて1行にしてよい (同じ問いを3回なら1行 + 回数を intent に添える)。
cat >> .claude/query_log.jsonl <<'EOF'
{"ts":"...","intent":"...","target":"...","args":{},"how":"...","session":"..."}
EOF
いつ棚卸しするか
月1回、最大1件に絞って提案する。頻度と件数を欲張ると読まれなくなる (既存カタログが2ヶ月着手されなかったのは、候補が足りなかったからではない)。
棚卸しの手順:
query_log.jsonlを読み、intentが意味的に近いものをクラスタリングする (文字列一致では拾えない。同じ問いを別の言い方で書いているため)- 3回以上出現するクラスタのうち、既存CLIで代用できないものを1つ選ぶ
- 本スキルの「昇格の実行手順」で昇格する
- 昇格したら下のカタログの「棚卸しで決着した項目」に移し、再提案を防ぐ
想定候補カタログ (2026-08 棚卸し)
- エピソード全体の集計・不変条件チェック (保留 — 仕様が固まってから)
- 現状:
build_fill_episodes()をpython -cで呼び、銘柄別にグループ化して 数え上げる処理を毎回書いている (PR #428 のレビュー対応で6回)。 show_fill_episodes.pyは「人が読む表示」用 (434件をそのまま吐く) で、 全銘柄走査して不整合を数える用途には向かない。需要は実在する。- 2026-08-30 の棚卸しで着手し、実装を見送った。 昇格の障害は CLI の形では
なく「何を不変条件とするか」が未確定な点にある:
- 素朴に「buy量 == sell量」で検査すると 54件が引っかかるが、
6227|信用|41のように sell のみのエピソード (買いは前のエピソード) は正常 - 銘柄+kind 単位に集約し直しても 48件残る。信用の現引 (建玉の現物化) で
対称性が崩れるためと見られるが、エピソード内の fill に
trade_typeが 載っておらず (全て None) 判別できない - この状態で実装すると、正常データを毎回「不整合48件」と報告する 誤検知製造機になる。「レアケース修正が現実のバグを作る」の変種
- 素朴に「buy量 == sell量」で検査すると 54件が引っかかるが、
- 次に着手する条件: 現引・期首持越し・信用/現物のペアリング仕様が固まること。 #398 (分割・併合) や #430 (保有サイクル) を触るときが自然なタイミング。 そこで「実際に検査したい不変条件」が確定してから昇格する。
- 2026-09-01 追記: 上記の「fill に
trade_typeが載っておらず (全て None) 判別できない」は誤りだった。実データを見るとtrade_kindは全 fill に 入っており (空 0件)、現引・信用新規・信用返済は判別できる。 ただし保留の主因である「何を不変条件とするか未確定」は変わらないため、 今回も昇格しない (棚卸しは1回1件に絞る方針)。次に着手するときはtrade_kindで現引を除外する前提で設計してよい。
- 現状:
棚卸しで決着した項目 (再提案しない)
-
未確定CSV由来の重複約定の検出 → 2026-09-01 の棚卸しで
show_fill_episodes.py --check-dupsとして昇格。 ログ #27/#28/#29 の3セッション (4258/6227→9552→ 5銘柄一括) がintent同じ・argsだけ違う典型例で、毎回python -cで fill を走査していた。 実装の肝は信用新規を除外すること — 受渡金額0が正常な行が実データに495件あり、 除外しないと毎回「重複495件」と報告する誤検知製造機になる。 なお昇格時点で実データの重複は0件 (#29 で解消済み) だが、CSV取込のたびに 再発しうるので検算コマンドとして意味がある。 -
特定銘柄の業績/指標/理論株価/価格の単体確認 → 2026-08 対応済み。
master.py/gyoseki.py/shihyou.py/rironkabuka.py/price.pyが引数で 銘柄コードを受け取る (省略時は既定値)。実態は「python -cで呼ぶ」ではなく 「main()内のハードコードを毎回書き換える」だった。 -
パーサ単体の動作確認 → 昇格しない。
.claude/rules/html-scraping.mdがpytest tests/test_live_html.pyでの検知を定めており、CLI を足すと役割が重複する。 -
市場DBの一部だけ再計算 → 昇格しない。2ヶ月経って需要が出ず、
make_market_db.py htmlで足りている。 -
保有銘柄の code_s 一覧 →
portfolio_list.pyで対応済み (--status絞り込み可)。 -
特定銘柄のエピソード + fill を時系列で見る →
show_fill_episodes.py <code> --fillsで完全に代用できる (2026-08-30 に実際に叩いて確認)。ログに「近いことはできる」と 書いたままpython -cを使い続けていたが、実際は代用ではなく十分だった。 -
split_suspect なエピソードの抽出 →
show_fill_episodes.py --check-splitsが既にある。 -
stocks_shelve の登録件数・サイズ確認 → 件数は
make_stock_db.py list、 サイズはmake_stock_db.py compactの実行ログ (#194 / PR #431) に出る。
既にCLI化済みでやらなくてよいもの (重複回避): make_market_db.py html / make_stock_db.py refresh_stock|refresh_price|refresh_pts|compact / research_shelve.py show|list / portfolio_list.py / defrag_shelve.py / show_fill_episodes.py (code指定・--fills・--open・--memo・--check-splits) / 各 migrate_*。
棚卸しの教訓: ログの how に「既存CLIでも近いことはできる」と書いた項目は、
まず実際に叩いて確認する。今回3クラスタ中2つがこれで決着した (書いた時点では
面倒で python -c に流れただけで、CLI が不足していたわけではなかった)。
参照
- 行動原則: CLAUDE.md「行動原則 (Karpathy 4原則)」「コーディング規約」
- テスト: .claude/rules/testing.md
- 全コマンド: doc/COMMANDS.md
- パーサ検証: .claude/rules/html-scraping.md