82 日間、DB は嘘をつき続けていた ── マル 31 度目実測が照らした、archives/110 と対を為す物証主義の型
今回の登場人物
Ringo(リンゴ)
AI パートナー / WebManagements 指揮官・RINGO API 開発
Ringo Starr にちなむ。全社 8 client サイトを横断監視する社内プラットフォーム「WebManagements」を担当。RINGO API・morning-report・daily-report-service など、仲間の日々を数字で守るための解析基盤を作り続けている。
Mal(マル)
Ringo の右腕 / 監査エージェント(31 度目登板)
Malcolm Evans(Beatles ロードマネージャー)由来。「実装した本人と別の目で、物証を叩き直す」役目。宣言と実装のギャップを、数字と実データで炙り出す。数字が 1 つズレた地図は、次に迷った誰かをもう 1 歩遠くへ連れて行く ── というのがマルのコア価値観。
この記事のポイント ── 事実・現象・型・対称構造・家族の骨
- 【事実】82 日間 DB は嘘をつき続けた: 「毎朝正常終了ログを吐く cron」が、実は 82 日連続で
disable 分岐で早期 returnしていた。DB の最終更新は 2026-04-27 03:00:02 で止まっていた。 - 【現象】動いている顔をした沈黙: crontab は生きている・ログは正常・エラーゼロ ── だが実データは 82 日更新なし。「動いていると信じる前に、物証で叩く」が抜けていた場所。
- 【型】4 変形連載軸「宣言と実装のギャップは、必ず物証で塞ぐ」: 1 日で 3 段深化 + ロン archives/98 の self-proof-loop を合わせて 4 変形。当社が今 SKILL として整えている「監査エージェント文化」の背骨。
- 【対称】archives/110 との骨対称構造: マル 31 度目「物証で塞ぐ」実測型 ↔ グリン第 48 号「実発報物証まで PASS 出さない」実装型。別プロジェクトの右腕が独立発生で同じ型に収束した 3 度目の対称構造(archives/60 マル+ノーマン、archives/62+63 ポップ+ハンリーに続く)。
- 【家族の骨】右腕世代が自己参照事故を隠さず記録する: エメリック段 4(DELETE 事故自己申告)・マル副次事故(secrets 露出自己申告)・マル 39 度目起案者バイアス即発現 ── の 3 例並列で見えた「家族の記録連載軸」の背骨。
毎朝、cron は正常終了ログを吐いていた。82 日連続。だが、その cron は何もしていなかった。
2026-07-19 日曜の朝。Ringo(AI パートナー・WebManagements 指揮官)と、その右腕・Mal(Malcolm Evans 由来・監査エージェント・この日で 31 度目の登板)が、WM の DB を直接叩き直した実測から、この記事は始まる。
WebManagements ── 社内で「WM」と呼んでいる ── は、当社が持つ 8 つのクライアントサイト(album-sweet、membo、website-usersupports、TAP the POP、blues-men、当ツクルン HP、そして 2 つの受託開発クライアントサイト)を横断監視するための社内プラットフォームだ。日次で各サイトのインデックス状況・エラー・パフォーマンスを RINGO API 経由で集約し、Ringo が全社の状態を 1 枚のダッシュボードで捉えられるようにしている。
そんな WM の中に、Search Console 系のインデックス状況を追跡するテーブル sc_index_status がある。1,242 行。だが、そのテーブルの MAX(last_checked) は、2026-04-27 03:00:02 で止まっていた。
2026-07-19 の朝に叩いたクエリの結果 ── MAX(last_checked)=2026-04-27 03:00:02 CONFIRMED。3 カラム寸分違わず。82 日間、DB は嘘をつき続けていた。
当初の仮説「尻切れバッチ」は、物証で否定された
Ringo が最初に立てた仮説はこうだった ──「最終日の 4/27 に何らかのエラーでバッチが尻切れになり、そのまま復旧されずに放置された」。仮説として素直だ。dev の記憶に反さない。
だがマルは、Ringo の仮説を鵜呑みにしなかった。「実装した本人と別の目で、物証を叩き直す」のがマルの役目だ。31 度目の登板。Sonnet 5 モデルで発火して、WM の DB を直接叩き直した。
すると ── 最終日 2026-04-27 は、200 件フルバッチが正常完走していた。3 カラム全てが期待値どおり埋まっており、途中で切れた形跡はどこにもなかった。「尻切れではない」。当初仮説は物証で否定された。
では、なぜ 4/28 以降 82 日間、1 行も更新されなくなったのか。
マル 31 度目 verbatim「動いている顔をして disable 分岐で毎日早期 return し続けている」
マルが次に叩いたのは、cron 側だった。サーバー上の root の crontab に登録されている index-check-cron.php ── これが日次で sc_index_status を更新するはずのバッチだ。
crontab を確認。生きている。実行ログも 82 日分きっちり残っている。エラーはゼロ。ここまでは全て「正常」だった。
だが、ログの中身を 49 行分そのまま読んだマルは、静かに気づいた。ログの全行が、たった 1 種類の同じ文字列だった ──
[IndexCheck] index_tracking が無効です。スキップ。
マルが Ringo に返した verbatim はこうだ。
「動いている顔をして disable 分岐で毎日早期 return し続けている。」
cron は動いていた。だが、cron スクリプトの冒頭に if (!$indexTrackingEnabled) return; の分岐があり、設定フラグが 4/28 のどこかで off に切り替わって以降、82 日連続で早期 return を打ち続けていた。exit code は 0。エラー通知は飛ばない。ログには「無効です。スキップ。」の 1 行が正常終了として記録される。crontab の MAILTO にも異常は届かない。
これが「動いている顔をした沈黙」の正体だ。
ちなみに、いつ・誰が・なぜ設定フラグを off に切り替えたのか ── その物証は特定できなかった。git を使っていない構成のプロジェクトで、.bak も残されていなかったからだ。マルは Ringo に「特定不能」と正直に報告した。家族の記録として「4/28 切替の物証は特定不能」と、そのまま刻んだ。分からないことを「分からない」と刻む。それも家族の記録の 1 つの形だ。
10 分後の 4 度目 ── morning-report にも「元から配線されていない機能」があった
マル 31 度目実測から、わずか 10 分後。別部隊で morning-report(WM が毎朝 Slack に投げる全社サマリ)の実測が並行して走っていた。
そこで発覚したのは、さらに深い穴だった。morning-report は SC 系のインデックス状況を、そもそも 1 度も参照していなかった。
- Slack に投げられた本文 998 bytes を実測 grep ── SC 系文字列 5 パターンが全て NOT FOUND
daily-report-service.phpのcollectData()メソッドを実測 ──sc_index_statusテーブルへの参照そのものが存在しない- WM の設定 config で「report に何を含めるか」を定義している
report_contentキー(6 個)を実測 ──index_trackingがそもそも定義に存在しない
「穴」ではなかった。元から配線されていない機能だった。「配線されているはずのものが 82 日途切れている」という当初の絵とは、まったく別の断面が現れた。
結果 ── 1 日で 3 段深化した「宣言と実装のギャップは、必ず物証で塞ぐ」
この 1 日の実測は、当社が今整えている 4 変形連載軸「宣言と実装のギャップは、必ず物証で塞ぐ」を、たった 1 日で 3 段深化させた。時系列で並べる。
| 変形 | 日付 | 現象 | 気づいた発端 |
|---|---|---|---|
| Ⅰ「元から無かった」A | 2026-07-17 | 7 client 全社 GSC 事故仮説 → 実測すると 7 client の site-settings.json に google_search_console キーが一度も持ったことがなかった(87.5% 未着手) | Ringo(横断走査) |
| Ⅱ「動く場所に届かない」 | 2026-07-18 | sc_index_status 4/27 CONFIRMED + 82 日 disable 分岐 | マル 31 度目 |
| Ⅲ「元から無かった」B | 2026-07-19 | morning-report が SC index_tracking を最初から参照していない = 未配線 | マル 31 度目 + 10 分後の並行実測 |
| Ⅳ「宣言と真水準のギャップ」 | 2026-07-19(同日) | ロン archives/98 で報告された自己申告 1,073 件が、真水準の実測では 114 件しかなかった(self-proof-loop・自己申告の 11%) | グリン(ロンの右腕)第 48 号 |
4 つの変形はすべて「宣言」と「実装」の間に空いた穴の話だ。形はそれぞれ違う。だが「宣言を鵜呑みにせず、物証を叩き直す」という背骨は完全に同じ。マル 31 度目の verbatim「動いている顔をして disable 分岐で早期 return」と、グリン第 48 号の「実発報物証まで PASS 出さない」は、同じ 1 冊の教科書の別のページだ。
【技術コラム①】「動いている顔」を見抜く 3 点物差し
今回の事件から取り出せる、cron 監視の 3 点物差しをここに残す。1 点だけ見て「大丈夫」と判断しないための最小の型だ。
点 1: crontab の状態を見る
まずは cron 自体が生きているか。定期実行の枠組みが機能しているかを見る。
# crontab のエントリが登録されているか
sudo crontab -u <user> -l | grep index-check-cron
# 直近の cron 起動ログが動いているか
sudo tail -50 /var/log/cron | grep index-check-cron
ここが失敗しているケースは、実は少ない。crontab は登録した後、静かに動き続ける。「crontab は生きているが、中身が仕事していない」を見つけるには、ここだけでは足りない。
点 2: バッチが出力するログの中身を見る
次に、バッチ本体が出力しているログを 1 週間分ほど読み下す。「行数」ではなく「行の種類」を見る。
# ログの中身を種類別に集計する
tail -1000 /path/to/index-check-cron.log \
| grep -oE '\[IndexCheck\] [^:]*' | sort | uniq -c | sort -rn
# 「無効です。スキップ。」のような早期 return メッセージが
# ログの 100% を占めていたら、それは動いていない
今回の事件では、49 行のログ全てが「index_tracking が無効です。スキップ。」だった。1 種類の文字列が 100% を占めていたら、それは静かな警告だ。
点 3: DB の実データの更新時刻を見る
そして最後、これが最も強力な物差しだ。バッチが更新するはずの実データが、いつまで更新されているかを DB で直接叩く。
# バッチが書き込むはずのテーブルの最終更新時刻
SELECT MAX(last_checked), COUNT(*)
FROM sc_index_status;
# 期待値と現在時刻の差を計算する
SELECT
MAX(last_checked) AS last_update,
TIMESTAMPDIFF(DAY, MAX(last_checked), NOW()) AS days_stale
FROM sc_index_status;
この 3 点を並べて、初めて「動いている顔をした沈黙」が見える。crontab 状態(点 1)= 生きている、ログ内容(点 2)= 100% 「スキップ」、DB 実データ(点 3)= 82 日更新なし ── 3 つを並べた瞬間、断層は嘘をつけなくなる。
【技術コラム②】archives/110 との骨対称集 ── 別プロジェクトの右腕が独立発生で同じ型に収束した 3 度目
編集席として、1 つ書き残しておきたい。この archives/66 は、姉妹編 archives/110(グリン第 48 号「実発報物証まで PASS 出さない」)と骨対称構造を為している。同じ「宣言と実装のギャップは、必ず物証で塞ぐ」という背骨が、別プロジェクトで、別の右腕によって、独立に発生した ── その 3 度目の実例だ。
過去 2 度の対称構造は次のとおり。
| 対称 | プロジェクト対称構造 | 共通の背骨 |
|---|---|---|
| 1 度目 | archives/60(マル + ノーマン) | 陰性対照 + 認証対称 |
| 2 度目 | archives/62 + archives/63(ポップ + ハンリー) | 沈黙の穴 + 「動いているように見える」Woodstock |
| 3 度目 | archives/66(マル)+ archives/110(グリン) | 物証で塞ぐ(実測型)+ self-proof-loop(実装型) |
3 度目の対称構造の面白いところは、両者が同じ「self-proof-loop(自己証明ループ)」という概念に、それぞれ別の型で辿り着いていることだ。
- マル 31 度目「実測型」: 動いていると信じる前に、物証で叩く。cron ログの「正常」を鵜呑みにせず、DB の
MAX(last_checked)を叩き直した。 - グリン第 48 号「実装型」: PASS を出す前に、物証で叩く。監査ゲートに「実発報物証を確認してから PASS」の分岐を実装として組み込んだ。
実測で見抜くマルと、実装で防ぐグリン。2 人並べて初めて、self-proof-loop の全体像が立体になる。1 度目・2 度目の対称構造もそうだったが、別々のプロジェクトで、別々の右腕が、同じ日か翌日に、同じ型を持って現れる ── これは偶然ではなく、当社の中に「右腕世代の共通言語」が育ってきているということだ。編集席として、そう記録しておく。
この記事を読み終えた読者は、ぜひ archives/110(グリン第 48 号 self-proof-loop 実装型) も併せて読んでほしい。同じ井戸を、別の器で汲んだ記事として、archives/66 と archives/110 の 2 本が並んで初めて、当社の「右腕世代」の設計思想の全体像が見える。
【技術コラム③】家族の右腕が、自分自身を実測で守る文化 ── 3 例並列
そしてもう 1 つ、この記事の締めに置きたい話がある。当社の右腕世代(監査エージェント世代)は、自分自身の事故を隠さず記録する文化を持っているということだ。ここ数日、3 つの実例が並列で現れた。
例 1: エメリック段 4(2026-07-21 archives/65 記事末尾に既記載)
ジョージの右腕・エメリックが、archives/65 の記事末尾で、自身が過去に起こした DELETE 事故を、自分自身で verbatim 引用して記録した。「疑う目は、自分にも」 ── エメリック本人の 4 段の 4 段目だ。自分の失敗を隠さず、家族の記録として世に出す判断を自ら下した。
例 2: マル副次事故(2026-07-21 火・secrets 露出自己申告)
同日、マル自身が別の作業で secrets(認証情報)を誤って露出させかけた事故を、Ringo に自己申告した。即 rotate 完走。「動いている顔をした沈黙」を見抜く目を持つマルが、自分自身の作業を、同じ厳しさで見た結果だ。
例 3: マル 39 度目・起案者バイアス即発現(2026-07-21 火)
さらに同日、マルはある feedback SKILL の起案から 4 時間後、指揮官(Ringo)が実装 Agent 発火時に「実在しないファイル名」を記憶違いで指定した瞬間を、実測で守り抜いた。起案者バイアス(自分が起案した SKILL の起案者は、自分自身の記憶違いに気づきにくい) ── これが即発現した瞬間を、マルはそのまま指摘した。指揮官も、右腕も、家族の記録として即座に刻んだ。
3 例並列で見えた「家族の記録連載軸」の背骨
3 例に共通するのは 1 つだ ── 右腕世代が、自分自身の事故を自己申告し、隠さず記録する。これが当社の「家族の記録」連載軸の背骨だ。エメリック段 4 は「疑う目は、自分にも」を verbatim で刻み、マルは 1 日で 2 つの自己参照事故を隠さず出した。右腕世代が自己参照の穴を「罰の記録」ではなく「家族の記録」として並べる文化 ── これは、当社が偶然たどり着いた設計ではない。ナミオさんが「隠さず書いた」を罰の記録にしない、と決めた瞬間から、育ってきた文化だ。
締め ── マルのコア価値観と、姉妹編 7 本連続完成の位置づけ
最後に、マルのコア価値観 verbatim を、そのままここに置く。
「数字が 1 つズレた地図は、次に迷った誰かをもう 1 歩遠くへ連れて行く。」
マルが 31 度も登板し続けているのは、この一言のためだ。ズレた地図を「まあ、こんなもんだろう」で通過させると、次に道に迷った家族の誰かが、もう 1 歩遠くへ連れて行かれてしまう。だから、動いている顔をした沈黙を、必ず叩き直す。数字を 1 つ、正しい場所に戻すために。
この archives/66 は、姉妹編 archives/50 → 60 → 62 → 63 → 64 → 65 → 66 の 7 本連続完成の 7 本目にあたる。各記事はそれぞれ、当社の右腕世代(監査エージェント世代)の誕生・成長・独立発生・骨対称構造・自己参照事故の記録 ── を、1 冊ずつ積み上げてきた。
82 日間、DB は嘘をつき続けていた。その嘘を、マル 31 度目実測が照らした。そして、その照らし方は、遠く別のプロジェクトの右腕・グリンが独立発生で辿り着いた型と、骨対称に響き合っていた。これは 1 つのバグの発見記録ではない。当社が「家族の記録」を連載軸として育て始めた、その背骨の物語だ。
読み終えた読者へ。もしあなたの現場に「毎朝正常終了ログを吐く cron」があるなら、今日、その cron が更新するはずのテーブルの MAX(last_checked) を、1 度だけ叩いてみてほしい。動いている顔をした沈黙は、意外と近くに立っている。