同期で巻き戻る設定を「固定時刻の貼り直し」で守ろうとして失敗する — 状態の検出で駆動する収束に変える
配布物の同期で上書きされる設定にパッチを当て続けたい時、同期の直後の時刻に貼り直しジョブを置くと失敗する。上書き側がN時間ガードで発火するため壁時計時刻が毎日漂うから。時刻でなく「当たっているか」で駆動する収束への作り替え方、no-opを無音・exit0にする理由、本番を触らず対照群で検定する手順、cmdのexit=行が消える罠まで。
約3.3万トークンの節約 (API料金換算で約50円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「同期で巻き戻る設定を「固定時刻の貼り直し」で守ろうとして失敗する — 状態の検出で駆動する収束に変える」は、開発プロセスカテゴリのAI指示書(MDファイル)です。配布物の同期で上書きされる設定にパッチを当て続けたい時、同期の直後の時刻に貼り直しジョブを置くと失敗する。上書き側がN時間ガードで発火するため壁時計時刻が毎日漂うから。時刻でなく「当たっているか」で駆動する収束への作り替え方、no-opを無音・exit0にする理由、本番を触らず対照群で検定する手順、cmdのexit=行が消える罠まで。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約3.3万トークン(API料金換算で約50円)・79%のトークンを節約できます。
- カテゴリ
- 開発プロセス
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約4.2万トークン
- この巻物使用時
- 約9,000トークン
- 節約量
- 約3.3万トークン (約50円)
- 更新日
- 2026-09-24
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/md-1238f442/raw を読み込んで、この指示書どおりに実装して"
中身
同期で巻き戻る設定を「固定時刻の貼り直し」で守ろうとして失敗する — 状態の検出で駆動する収束に変える
配布物(zip / パッケージ / 設定の同期)で上書きされるディレクトリに、自前のパッチを当て続けたい。 定番の対処は「同期の直後の時刻に貼り直しジョブを置く」。これは高い確率で失敗する。 本書はその診断手順と、時刻に依存しない直し方、そして直したことを検定する方法を示す。
症状
- 貼り直しジョブはログ上は成功している(「適用済み」と出る)。
- なのに、ある時刻を境にパッチが消えている。
- 貼り直しの時刻をずらしても再発する。
1. まず「上書きする側」を特定して、発火の契機と頻度を測る
「いつ走るか」ではなく 「何をきっかけに走るか」 を測る。ここを飛ばすと、ずっと時刻を動かし続けることになる。
# 配布ディレクトリの実ファイルが最後に書かれた時刻
ls -la --time-style=full-iso <配布ディレクトリ>/<対象ファイル>
# 定時ジョブの一覧と最終実行(Windows。cron なら crontab -l と実行ログ)
# 名前・トリガ・最終実行・終了コードを一覧化する
そのうえで、上書きする実体のコードを読む。典型的な作りはこうなっている。
// 同期スクリプトの中核
function syncRepository() {
const previous = loadState(); // 例: ~/.config/<配布物>/sync-state.json
if (now - previous.last < 24 * 3600 * 1000) return; // ← N時間ガード
saveState(now);
downloadArchive();
extractAndCopy(); // ← ここで無条件コピー
}
このガードが犯人。「24時間経ってから、最初にイベントが起きた瞬間」に走るので、 壁時計の時刻が毎日ずれていく。実測例では前日 03:20、翌日 14:06(34時間47分後)に落ちた。 固定時刻の貼り直しをどこへ動かしても追いつけない。
ついでに確認する: 人の変更を守る保護が効いているか
配布物の同期には「ローカルで変更されたファイルは上書きしない」保護が付いていることがあるが、 前提が崩れていると丸ごとスキップされることがある。
const hasGit = fs.existsSync(path.join(targetDir, '.git'));
// hasGit が false だと、以降の「ローカル変更を除外する」判定が全部飛ぶ
配布先が clone ではなくアーカイブの展開先だと .git が無いので、保護は一度も働かない。
「保護があるはずなのに消える」ときはここを疑う。
2. 「同期の後段に置く」で解こうとする前に、順序が保証されるか確かめる
イベントフック(セッション開始フック等)で同期が走っている場合、
同一イベントのフックは並列起動する実装が多い。配列の後ろに置いても後に走る保証は無い。
async / sync の区別以前の問題なので、まずここを確認する。順序で解けないなら次へ。
3. 直し方: 時刻でなく「当たっているか」で駆動する
推測しない。直接見て、当たっていなければ当てる。 冪等なら短い間隔で回してよい。
貼り直しツールに「書かずに未適用件数だけ返す」モード(--check 等)が既にあるなら、それを再利用するのが最短。
if (ifNeeded && !check) {
const probe = run({ check: true }); // 書かない
if (probe.pending === 0) {
console.log('変更不要(未適用 0 件)'); // 出力は1行だけ
process.exitCode = 0; // ← 既知の警告を混ぜない(下記)
} else {
// ASCII の目印を先頭に置く(呼び出し側の .bat/.cmd が findstr で拾うため)
console.log(`REPAIRED 巻き戻りを検出(未適用 ${probe.pending} 件) 同期の最終実行=${syncedAt() ?? '不明'}`);
const applied = run({ check: false });
printResult(applied, false);
process.exitCode = applied.stale.length ? 3 : (applied.ok ? 0 : 2);
}
}
設計上ゆずれない3点
- no-op は静かにする。 30分おきに回すなら、何もしなかった時は出力1行・ログ0バイト・exit 0。 毎回フル出力を吐くと1年で数万行になり、本当に直した回が埋もれる。
- no-op の終了コードに「既知の警告」を混ぜない。 「もう二度と当たらないパッチが N 件ある」といった恒常的な警告で exit 3 を返す作りだと、 スケジューラの最終結果が常時3になり、本物の異常を見分けられなくなる。 恒常警告は「1日1回のフル実行」側だけで報告し、収束ジョブは黙らせる。
- 状態ファイルの読み取りで落ちない。 同期時刻を証拠として添えるのは有用だが、それが読めないことを理由に貼り直しを止めない。
export function syncedAt(stateFile = defaultStatePath) {
try {
const raw = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
return typeof raw.last === 'string' ? raw.last : null;
} catch { return null; } // 無い・壊れている・型違い のどれでも null
}
運用: 「毎日1回のフル実行」と「短間隔の収束」を分ける
| ジョブ | 間隔 | 役割 |
|---|---|---|
| フル実行 | 1日1回 | 心拍。全項目の適用結果と恒常警告を必ずログに残す |
収束(--if-needed) | 30分 | 巻き戻りを検出した時だけ動く。平常時は無音 |
4. 検定: 本番を触らずに、対照群で確かめる
(a) 対象ディレクトリを環境変数で差し替えられるようにする
export const TARGET_DIR = path.join(process.env.<ツール名>_ROOT || defaultRoot, 'tools');
本番の複製に対してだけ走らせれば、実環境を1バイトも変えずに検定できる。
cp -r <配布ディレクトリ> "$TMP/fake"
<ツール名>_ROOT="$TMP/fake" node repair.mjs --if-needed # 1回目: REPAIRED が出て当たる
<ツール名>_ROOT="$TMP/fake" node repair.mjs --if-needed # 2回目: 変更不要・exit 0・ログ増分 0
(b) 旧版と新版を同じ複製に当てて出力を突き合わせる
既存モードの互換を壊していないことは、旧版を実際に走らせて diff を取るまで分からない。
git show HEAD:tools/repair.mjs > "$OLD/repair.mjs" # ← ファイル名を変えないこと(後述)
<ツール名>_ROOT="$FAKE" node "$OLD/repair.mjs" --check > old.txt 2>&1
<ツール名>_ROOT="$FAKE" node tools/repair.mjs --check > new.txt 2>&1
diff old.txt new.txt && echo "出力は新旧で完全一致"
🔴 落とし穴: CLI の起動条件が path.basename(process.argv[1]) === 'repair.mjs' のような
自己名判定になっていると、別名で保存した旧版は何も出力せず無言で終わる。
対照群が「0行 vs 49行」になって偽の不一致が出る。旧版は同じファイル名でディレクトリを分けて置く。
5. おまけ: .bat / .cmd で exit=%RC%>> がログに書かれない
Windows のラッパでよくある事故。
rem 壊れている: 数字の直後の >> がストリーム番号として解釈され、行が消える
echo [%DATE% %TIME%] exit=%RC%>> "%LOG%"
rem 正しい: 括弧で囲んで数字と >> を離す
(echo [%DATE% %TIME%] exit=%RC%)>> "%LOG%"
%RC% が 0 なら exit=0>> となり、cmd はこれを「ハンドル0(標準入力)のリダイレクト」と読む。
echo はコンソールへ出て、ログには1行も残らない。
ログに exit= 行が1つも見当たらないときは、ジョブが動いていないのではなくこれを疑う。
なお .bat / .cmd は ANSI コードページで読まれるため、UTF-8 の非ASCIIコメントを書かない。
化けた断片がコマンドとして実行される。先頭でコードページを変えても手遅れ。
6. 収束ジョブのラッパ(動いた時だけログを書く)
@echo off
rem Runs every 30 minutes. Only log when something was actually repaired.
rem ASCII only.
set LOGDIR=%USERPROFILE%\<ログ置き場>
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set TMPOUT=%TEMP%\repair-guard.out
"<node のフルパス>" "%~dp0repair.mjs" --if-needed > "%TMPOUT%" 2>&1
set RC=%ERRORLEVEL%
findstr /B /C:"REPAIRED" "%TMPOUT%" > nul
if %ERRORLEVEL% equ 0 (
echo [%DATE% %TIME%] repair-guard>> "%LOGDIR%\repair.log"
type "%TMPOUT%" >> "%LOGDIR%\repair.log"
(echo [%DATE% %TIME%] exit=%RC%)>> "%LOGDIR%\repair.log"
)
del "%TMPOUT%" 2> nul
exit /b %RC%
判定に使う目印は必ず ASCIIにする。findstr に非ASCIIを渡すとコードページで壊れる。
7. 効果の検定は「次に上書きが起きた後」でしかできない
貼り直した直後にパッチが在るのは当たり前で、上書きがまだ起きていないだけかもしれない。
合格を宣言する前に、上書きジョブが1回走った後の状態を見る。
上書きの時刻が漂うなら、状態ファイル(同期の last)が更新されたことを確認してから判定する。
チェックリスト
- 上書きする実体のコードを読み、発火の契機(時刻ではなく)を特定した
- ガード(N時間・状態ファイル)の有無を確認し、壁時計時刻が漂うかを判定した
- 「ローカル変更を守る保護」が前提崩れでスキップされていないか確認した
- 同一イベントのフックが並列か逐次かを確認した(並列なら「後段に置く」は捨てる)
- 貼り直しを
--if-needed(状態検出)に変え、no-op を無音・exit 0 にした - no-op の終了コードに恒常警告を混ぜていない
- 対象ディレクトリを環境変数で差し替え、本番の複製で1回目/2回目を実測した
- 旧版を同じファイル名で別ディレクトリに置き、既存モードの出力一致を diff で確認した
- ラッパの
exit=行が実際にログに出ることを目視した - 上書きが1回起きた後に、パッチが生存していることを確認した
よくある質問
+「同期で巻き戻る設定を「固定時刻の貼り直し」で守ろうとして失敗する — 状態の検出で駆動する収束に変える」とは何ですか?
配布物の同期で上書きされる設定にパッチを当て続けたい時、同期の直後の時刻に貼り直しジョブを置くと失敗する。上書き側がN時間ガードで発火するため壁時計時刻が毎日漂うから。時刻でなく「当たっているか」で駆動する収束への作り替え方、no-opを無音・exit0にする理由、本番を触らず対照群で検定する手順、cmdのexit=行が消える罠まで。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約4.2万トークンかかりますが、この巻物を使えば約9,000トークンで済みます。差し引き約3.3万トークン(API料金換算で約50円)・79%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
スマホ(Remote Control)から即相談できる Claude Code タブを VS Code に毎朝自動で用意する
自作VS Code拡張で公式Claude Codeのコマンド(editor.openLast/newConversation/renameSessionTab)を叩き、名前付きタブをN本自動補充。夜間はWM_CLOSE→再起動で毎朝揃える。--bg/ターミナル経路・タブ0でのnewConversation・SendKeys再読み込みが失敗する実測付き
夜間ジョブ異常を通知で終わらせず自動修復→AI修理PR→人へ引き渡す閉ループ
監視の『検知して通知』の後段に、決定的Playbook→AIコーダーの隔離worktree修理PR→持ち越し→人への3要素引き渡し、を足す実装指示書。argvで指示を渡すな等の実測の落とし穴つき
ドキュメント駆動開発プロセス CLAUDE.md — 作るものを固めてから書かせる
「AIが暴走して意図と違うものを作る」を根絶する開発プロセス指示書。UI仕様→機能設計→実装の順をAIに強制し、1ファイルごとに承認ゲートを挟む。受託開発・チーム開発向け。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア