◉CLAUDE LABEN
●2.1.302 — fork サブエージェントが claude -p・Agent SDK・デスクトップで既定オンになりました。無効化は CLAUDE_CODE_FORK_SUBAGENT=0(10/16)●2.1.307 — スリープやキーチェーンロックのあとに MCP が再接続されない問題を修正しました(10/21)。2.1.306 では claude -p の誤表示も解消●SONNET 4.5 — Claude API での提供終了は 11/30、残り38日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.302 — fork サブエージェントが claude -p・Agent SDK・デスクトップで既定オンになりました。無効化は CLAUDE_CODE_FORK_SUBAGENT=0(10/16)●2.1.307 — スリープやキーチェーンロックのあとに MCP が再接続されない問題を修正しました(10/21)。2.1.306 では claude -p の誤表示も解消●SONNET 4.5 — Claude API での提供終了は 11/30、残り38日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/Cowork
◈ Cowork/2026-10-22中級

定期タスクの完了ログを半分読めなかった夜、正規表現を広げず最終行に印を1行足しました

日次ログ 1,076 件のうち結果を読めたのは約半数でした。正規表現を広げても回収は35件で誤報も出たため、最終行に決まった形の印を残す関数と、毎朝の点検スクリプトを作った記録です。

Cowork54スケジュールタスク30ログ設計6bash6Python23

✦ プレミアム記事

木曜の夜、定期タスクの日次ログを半年ぶんならべて、結果を一覧にしようとしました。

欲しかったのは単純な表です。どの日に、どのタスクが、SUCCESS だったか FAILED だったか。ログには毎回 Status: の行を書いてきたつもりでしたので、grep 一本で終わると考えていました。

結果は、読めたのが約半分でした。

files=519 entries=1076
読めた段: {'strict': 526, 'silent': 515, 'body': 24, 'header': 11}

手元の日次ログ 519 ファイル・1,076 件のうち、Status: 行から結果を読めたのは 526 件です。残りの半分近く(515 件)は、結果を示す語がどこにも見つかりませんでした。

ここからは、原因の切り分けと、正規表現を広げる道をやめた理由、最終行に「印」を1行だけ足す方式の作り方をお伝えします。個人開発の運用で定期タスクが増えた方の、参考になれば幸いです。

読めなかった半分は、月ごとに増えていました

まず、読めなかった件を月別に数えました。

月件数結果を読めなかった件割合
3月1644約2%
5月13550約37%
6月182142約78%
8月9473約78%
10月(22日まで)11264約57%

3月はほぼ全件が読めています。ところが6月に一気に崩れ、そのまま戻っていません。

原因は、書式が壊れたことではありませんでした。定期タスクの種類が増えるたびに、それぞれが自分の書式でログを書き始めたのです。朝の更新、昼の見直し、統合作業、トラブル調査。6月以降で結果の語がなかった 448 件をファイル名で分けると、日次の本体ファイルが 166 件、見直し系(_brushup_am など)が 232 件、残り 50 件が統合作業やトラブル調査でした。

どのログも、書いた時点の私には読めるものでした。人が読むには問題がなく、機械が読もうとしたときに初めて困るのです。この種の負債は、気づくまで静かに溜まっていくのだと、今回あらためて感じました。

測定スクリプト — どの段で読めたかを一緒に記録します

数字を出したスクリプトを、そのまま載せます。ポイントは、結果を拾うだけでなく「どの段で拾えたか」を数えている点です。

#!/usr/bin/env python3
"""日次ログ(空行区切りの自由書式)から、1件ごとの結果を読み出す。
上から順に試し、どの段で読めたかも記録する(strict → header → body → silent)。"""
import re, sys, glob, collections, pathlib
 
WORDS = r"(SUCCESS|FAILED|PENDING_PUSH|PENDING|SKIPPED_DUPLICATE|SKIPPED|SKIP)"
HEAD  = re.compile(r"^\[(?:\d{4}-\d\d-\d\d|\d\d:\d\d|[\w-]+ \d\d:\d\d)[^\]\n]*\]", re.M)  # 行頭が日付か時刻の [..] だけを1件の始まりとみなす
STRICT = re.compile(rf"^\s*[-*]?\s*Status:\s*{WORDS}", re.M)     # 決められた書式
INHEAD = re.compile(rf"^\[[^\]\n]+\]\s*{WORDS}", re.M)           # [task 15:00] SUCCESS 型
LOOSE  = re.compile(rf"\b{WORDS}\b")                             # 本文のどこかに書かれている
 
def split_entries(text):
    starts = [m.start() for m in HEAD.finditer(text)]
    if not starts:
        return [text] if text.strip() else []
    starts.append(len(text))
    return [text[a:b] for a, b in zip(starts, starts[1:])]
 
def classify(block):
    for name, rx in (("strict", STRICT), ("header", INHEAD), ("body", LOOSE)):
        m = rx.search(block)
        if m:
            return name, m.group(1)
    return "silent", None
 
def main(log_dir):
    by_method, by_status, silent_files = collections.Counter(), collections.Counter(), []
    files = sorted(glob.glob(str(pathlib.Path(log_dir) / "20??-??-??*.txt")))
    for f in files:
        blocks = split_entries(pathlib.Path(f).read_text(encoding="utf-8", errors="ignore"))
        if not blocks:
            silent_files.append((f, "empty")); continue
        for b in blocks:
            method, status = classify(b)
            by_method[method] += 1
            if status: by_status[status] += 1
            else: silent_files.append((f, "no-status"))
    print(f"files={len(files)} entries={sum(by_method.values())}")
    print("読めた段:", dict(by_method))
    print("結果   :", dict(by_status.most_common()))
    print("読めなかった:", len(silent_files))
    for f, why in silent_files[:5]:
        print("  ", pathlib.Path(f).name, why)
 
if __name__ == "__main__":
    main(sys.argv[1])

実行は、ログのあるディレクトリを渡すだけです。

python3 ledger_scan_status_fallback.py /path/to/log_dir

四つの段は、上から順に試します。strict は決めた書式(Status: SUCCESS)、header は [タスク名 15:00] SUCCESS のように見出し行に書かれた型、body は本文のどこかに語が出てくる型、どれも当たらなければ silent です。

silent の件数が、そのまま「機械から見て黙っているログ」の量になります。自分のログでも、まず3分でこの数字を出してみてください。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦自分の定期タスクのログが機械的にどこまで読めるかを、測定スクリプトで3分のうちに数えられるようになる
✦本文にたまたま書かれた FAILED を失敗と誤報する事故を、最終行の印だけを読む設計で前もって防げるようになる
✦毎朝1コマンドで、動くはずのタスクが何も言わずに止まったことに気づけるようになる
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

◈ Cowork2026-10-21
共有 /tmp の clone に書き込めなかった定期タスクで、古いリポジトリを借りず毎回 clone し直すと決めた理由
定期タスクが /tmp のクローン先を作れずに止まりました。原因の切り分け、借りられた古いクローンが約9.6時間遅れていた事実、毎回 clone し直した場合の費用、作業場所を選ぶスクリプトをお伝えします。
◈ Cowork2026-10-18
前読みを head -150 で切っていた朝、読んだ 15.6KB のうち最新日は 3.3KB でした
日次メモの前読みを head -150 にしていた定期タスクで、行数は予算にならないと分かりました。日付ブロック単位で読む小さなリーダーと、切るときに消えやすい「まだ使っていない案」の守り方をお伝えします。
◈ Cowork2026-10-17
スケジュールタスクが SUCCEEDED のまま成果を出さなくなったら、最初の1分で外への通信を疑います
実行記録は緑なのに成果物が昨日のまま。外部への通信が CONNECT の 403 で止まっていないかを、短いプローブと鮮度チェックで最初の1分に見分ける手順をお伝えします。