execution-budget-vs-caps
Skill0 starsChanged 5 months agoMITView on GitHub
caps×遅延/サイズの積が実行枠を超えるとSIGKILL/サイレント打ち切りになる。コードに1行もバグがなくても毎日壊れる型と、自分から締切前に止まる実装パターン。
In this repository99 other files it gives its agents.
- agents-tools-quoted-jsonSkill
- asc-api-app-store-submitSkill
- asd-ste100Skill
- automation-bool-selector-pitfallsSkill
- automation-stale-cooldown-flagSkill
- autonomous-build-verifySkill
- book-to-skillSkill
- ccusage-cli-cost-trackingSkill
- chrome-ext-mv3-programmatic-injectSkill
- chrome-ext-store-assetsSkill
- claude-headless-p-invocationSkill
- claude-plugin-context-auditSkill
- claude-session-log-to-kbSkill
- cloudflare-workers-do-deploySkill
- codebase-to-courseSkill
- codesign-keychain-prompt-fixSkill
- codex-cli-setupSkill
- codex-delegation-handoffSkill
- content-factory-grounding-dedupSkill
- conversation-log-append-patternSkill
- cron-to-launchd-macosSkill
- cross-automation-shared-resource-killSkill
- design-token-migration-rnSkill
- discord-bot-image-to-claudeSkill
- discord-gateway-resume-dedupSkill
- excel-filtered-url-http-auditSkill
- expo-free-local-ios-testflightSkill
- ga4-connect-projectsSkill
- gcal-oauth-desktop-setupSkill
- git-commit-helperSkill
- git-prepush-secret-remote-checkSkill
- gsc-cli-automationSkill
- hatena-blogsync-autopostSkill
- hook-latency-wrapSkill
- hook-log-append-patternSkill
- html-to-pdf-slide-deckSkill
- humanizerSkill
- human-review-gate-shellSkill
- implementation-model-routingSkill
- insights-to-claude-mdSkill
- ios-permission-key-security-matrixSkill
- ios-sim-store-screenshotsSkill
- launchd-exit78-exconfig-debugSkill
- llm-content-pipeline-quality-gateSkill
- local-ai-video-pipelineSkill
- local-flux-mflux-image-genSkill
- local-llm-slow-diagnosisSkill
- local-music-generationSkill
- lottie-skottie-authoring-pitfallsSkill
- machine-wide-api-ratelimit-latchSkill
- macos-hook-path-timeoutSkill
- md-to-docx-reportSkill
- memory-md-inject-bloat-auditSkill
- message-display-secrets-maskSkill
- metric-source-attributionSkill
- migrate-icloud-desktop-assetsSkill
- nextauth-local-e2e-sessionSkill
- nextjs-rsc-payload-slimSkill
- nothing-designSkill
- openclaw-ollama-setupSkill
- The first 60 shown.
The file
Files
execution-budget-vs-caps — 器のサイズを実装が知らないまま動く型
問題の本質
「upper caps」と「その caps に到達するまでにかかる時間・容量」を別々の場所に書くと、
どの行も正しいのに組み合わせだけが毎日壊れる。
caps × delay_avg + jitter > container_limit → 外部からSIGKILL / 黙って切り捨てコードレビューで見つからない。なぜなら どの設定も個別には正しいから。
見つかるのは算術(積)だけ。
4つの器と実例(2026-08-12窓)
| 器 | プロジェクト | 実装が知らなかった上限 | 実害 |
| 時間 | o81-brand ig_engage.py | BROWSER_SLOT_TIMEOUT_SEC=2400 | caps101×avg40s+jitter900=5040s → 毎日 exit 124 (SIGKILL) |
| 文字数 | lily-line-funnel pdca.mjs | Discord 1メッセージ 2000字 | レポート長い日は通知ごと落ちる |
| 画素(撮影) | note-autolike 表画像 | Chrome --headless=new はウィンドウサイズをそのまま撮る | 1760×4000px(白余白巨大)で公開 |
| 画素(生成) | ai-portraits | 内蔵imagegen の出力は指定と違う寸法で返る | sips 正規化の不統一 |
診断チェックリスト(自動化ジョブが「バグなし・毎日失敗」なら)
# 1. exit code を確認(124=SIGKILL 候補)
grep "exit_code" ~/.logs/<job>.log | tail -20
# 2. caps × delay の積を計算
python3 -c "caps=101; delay_avg=40; jitter=900; timeout=2400; print(caps*delay_avg+jitter, '>',timeout, '?', caps*delay_avg+jitter > timeout)"
# 3. 実行枠の設定元を確認(launchd は TimeOut、docker は --timeout、etc)
grep -r "TIMEOUT\|TimeOut\|slot_timeout" ~/dev/<project>/ --include="*.py" --include="*.plist"
# 4. Discord: レポートの最大文字数を測る
python3 -c "import json; r=json.load(open('report.json')); print(len(r['body']))"
# 5. Chrome: headless screenshot の実寸を確認
file output.png # → dimensions実装パターン:自分から締切前に止まる
1. 時間予算(Python / launchd)
import os, time
def compute_budget() -> float | None:
"""環境変数が消えたら None → 既存挙動を1ミリも変えない"""
raw = os.environ.get("IG_ENGAGE_BUDGET_SEC") \
or os.environ.get("BROWSER_SLOT_TIMEOUT_SEC")
if not raw:
return None
return float(raw)
BUDGET_MARGIN_S = 120 # 終了処理のバッファ
budget = compute_budget()
deadline = (time.time() + budget - BUDGET_MARGIN_S) if budget else None
def over_budget() -> bool:
return deadline is not None and time.time() > deadline
# 各ループの先頭に相乗り(新しいクラス・ブロック不要)
if blocked["hit"] or over_budget():
break
# jitter も残予算の20%でクランプ
jitter_max = min(900, (deadline - time.time()) * 0.2) if deadline else 9002. 文字数制限(Discord 2000字チャンク分割)
function chunkDiscord(text, limit = 1990) {
// サロゲートペア考慮: [...s].length
const chars = [...text];
const chunks = [];
let buf = [];
for (const c of chars) {
if (buf.length >= limit) {
chunks.push(buf.join(""));
buf = [];
}
buf.push(c);
}
if (buf.length) chunks.push(buf.join(""));
return chunks;
}
// エラー本文はDiscordには先頭800字、ログには全文
await sendDiscord(errorMsg.slice(0, 800) + (errorMsg.length > 800 ? "…" : ""));
console.error("FULL:", errorMsg); // ログ側は全文3. Chrome headless screenshot(2パス化)
# パス1: scrollHeight を取得(ウィンドウ高さは小さくする=200)
HEIGHT=$(chromium --headless=new --window-size=1760,200 \
--dump-dom "$URL" | python3 -c "
import sys; from html.parser import HTMLParser
# scrollHeight相当を body height から取得
...")
# パス2: 実寸で撮影
chromium --headless=new --window-size="1760,${HEIGHT}" \
--screenshot="$OUT" "$URL"4. 画像生成後の強制正規化
# 生成ツールのアスペクト指定は信用しない。保存後に毎回正規化
TARGET_W=1024; TARGET_H=1280
sips -z "$TARGET_H" "$TARGET_W" "$OUTPUT_FILE"
# 実寸を読んで確認(ログに残す)
ACTUAL=$(sips --getProperty pixelWidth --getProperty pixelHeight "$OUTPUT_FILE" \
| grep -E "pixel(Width|Height)" | awk '{print $2}' | paste -sd'x')
echo "normalized: $ACTUAL (expected: ${TARGET_W}x${TARGET_H})"🔴 silent-success 罠と対策
打ち切りを exit 0 にした瞬間、「毎日ちゃんど動いているが成果は半分」が誰にも見えなくなる。
# state/engage_budget.json で連続打ち切り日数を追跡
import json, pathlib, datetime
STATE_FILE = pathlib.Path("state/engage_budget.json")
def record_budget_cutoff(likes, follows, unfollows, caps):
state = json.loads(STATE_FILE.read_text()) if STATE_FILE.exists() else {}
today = datetime.date.today().isoformat()
if state.get("last_date") == today:
return # 同日2回目は無視
streak = state.get("streak", 0) + 1 if state.get("last_date") else 1
state.update({"streak": streak, "last_date": today})
STATE_FILE.write_text(json.dumps(state))
# 3日連続かつ今日まだ通知してない場合のみアラート
last_alert = state.get("last_alert_date", "")
if streak >= 3 and last_alert != today:
state["last_alert_date"] = today
STATE_FILE.write_text(json.dumps(state))
send_alert(
f"capsが実行時間に対して過大:予算到達での打ち切りが{streak}日連続\n"
f"実績: likes={likes}/{caps['likes']}, follows={follows}/{caps['follows']}"
)ルール: 単発1日は鳴らさない(重い日で狼少年)。毎日は鳴らさない(読まれなくなる)。3日連続+1日1回。
設定値の書き方(積を最初から持つ)
# ❌ 悪い:caps と delays を別々の定数にする
CAPS = {"likes": 62, "follows": 24, "unfollows": 15}
ACTION_DELAY_AVG = 40 # seconds
TIMEOUT = 2400
# ✅ 良い:必ず積を計算してログに出す
total_actions = sum(CAPS.values()) # 101
estimated_sec = total_actions * ACTION_DELAY_AVG + JITTER_MAX # 4940s
if estimated_sec > TIMEOUT:
logger.warning(f"caps×delay={estimated_sec}s > timeout={TIMEOUT}s — 予算超過リスク")LINE月間上限のような「月次枠」も同様:
# LINE 無料枠 200通/月 → 180で強制停止(10%バッファ)
LINE_MONTHLY_CAP = 200
LINE_MONTHLY_SOFT_LIMIT = int(LINE_MONTHLY_CAP * 0.9) # 180Pitfalls
- SIGKILL は finally を通らない:
ctx.close()/ ファイルclose / ロック解除が全部スキップされる。Chromium孤児化・ロックファイル残留が発生 → - launchd TimeOut デフォルト は 30秒(短い)。
BROWSER_SLOT_TIMEOUT_SECなどの環境変数が設定元と食い違う場合がある。実設定はlaunchctl print system/<label>で確認 - jitter を残予算から引く: jitterを固定max(=900)にすると、予算の大半がjitterで消える。
min(jitter_max, remaining * 0.2)でクランプ - Discord文字カウント:
len(s)はバイト数ではなくPythonコードポイント数。サロゲートペア(絵文字等)は[...s].length(JS)/len(s)(Python3 unicode)で正しい - Chrome scrollHeightの落とし穴: パス1のウィンドウ高さを大きくすると(例:2000)、scrollHeightが2000未満にならず同じバグが残る。パス1の高さは200など小さくする
関連スキル / wiki
- — 同じ08-12窓のmtime汚染対処
- — 自動化の別型(boolean戻り値忘れ)
~/.claude/wiki/learning/execution-budget-vs-caps.md— 正典(実測値・実装コード)~/.claude/wiki/learning/silent-success-antipattern.md— exit 0化の穴
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

