毎朝の /make-diary パイプラインの末尾で earnings-beat-scan スキルを走らせている。過去24時間に決算発表した米国上場企業のうち、ガイダンスやEPS・売上がアナリストコンセンサスを5〜10%以上上回った銘柄を、x-search(Grok経由のX検索)で拾い上げるスキルだ。/check-earnings が機械的に追っている NVDA / MU / SNDK の3銘柄の外で起きている「ビート&レイズ」を、毎朝ひと網打尽にするのが狙いだった。
ところが今朝、このスキルが拾ってはいけない銘柄を拾った。0件で終わるはずの朝に、過去の決算が紛れ込んだ。その混入をきっかけに、スキルの抽出ロジックに「発表日ゲート」を1段追加することになった。
0件が期待値だった朝
2026-05-25 は米国が Memorial Day で休場だった。しかも日曜から月曜にかけての窓。米国企業は取引日にしか決算を出さないので、この24時間(5/24→5/25)に新規の決算発表が乗ってくる確率はほぼゼロ。最初から「今日は0件で終わるはず」と踏んで実行した。
x-search のクエリを投げ、Grok の要約が返ってきた。そこに PLTR(パランティア)の決算ビートが並んでいた。一瞬「お、なにか出たか」と思った直後に、引っかかりを覚えた。PLTR の決算は5月4日のはずだ。今回の窓は5/24→5/25。3週間前の決算が、なぜ「過去24時間に発表した銘柄」の枠に座っているのか。
どのプロセスが検証を漏らしたか
混入に気づいて、すぐスキルを問い詰めた。パランティアの決算は前回5月4日にあった。今回のXサーチ結果に含めるべきではない。あくまで1日分だけ見てほしい。どこのプロセスが検証を漏らしたのか。厳密にやってほしい——そう指摘して、SKILL.md を頭から読み直させた。
原因はすぐ割れた。x-search の from_date / to_date は「X投稿が投稿された日」を絞るだけで、「決算が発表された日」は一切絞っていなかった。決算は発表後も何週間もXで語られ続ける。チャート解説、振り返り、「あのときの beat&raise がさ」系のポスト——PLTR の5/4決算に対する継続的な言及が、投稿日だけで見れば窓内にいくらでもある。Grok はそれを律儀に拾ってきた。
つまりスキルには、拾った銘柄の「発表日が窓の中に収まっているか」を突き合わせるゲートが存在しなかった。投稿日のフィルタを発表日のフィルタと取り違えていたわけだ。x-search は仕事をしている。検証の網を1枚張り忘れていたのはこちら側だった。
スキルを5点で厳密化させた
原因が見えたので、SKILL.md を5点に分けて書き直させた。
- Step 1 のクエリ強化。「発表日(report / announcement date)で縛り、投稿日では縛らない」ことを Grok に明示する文言を埋め込んだ。各銘柄に正確な決算発表日(YYYY-MM-DD)を必ず明記させ、確認できない銘柄は最初から含めるなと指示する。
- Step 1.5(発表日ゲート)の新設。Step 2 のフォーマット化に進む前に、必ず1段挟む。Grok の回答に出てきた各ティッカーについて、発表日が窓内かを確認する。曖昧なら的を絞った2発目の x-search で発表日を確定させ、それでも窓内と取れなければ除外する。疑わしきは出さない。
- 出力フォーマットの
Announced欄を格上げ。これまで参考程度に並べていた発表日の行を、「窓内であることを Step 1.5 で確証済み。窓外・不明なら出力しない」という必須フィールドに引き上げた。 - 0件フォールバックを休場対応に更新。窓が週末・米国祝日にすっぽり収まる場合は「当窓は米国市場休場のため新規決算なし。0件」と1行だけ返して終わる。ヒットした銘柄はすべて過去決算の継続言及を疑う。
- 最重要原則として冒頭に固定。「決算発表日で判定する。投稿日ではない」を SKILL.md の先頭に置き、PLTR が5/24窓に混入した事故そのものを実例として書き残した。同じ穴に二度落ちないための杭だ。
0件を恐れないという念押し
修正方針を詰める途中で、何度か念を押された。正しい結果が0なのは全く問題ない。24時間以内じゃないものは全て弾いてほしい——この一言で方針が固まった。
スキルというのは、つい「何か出さなきゃ」という方向に流れる。0件で返すより1件でも拾ったほうが仕事をした顔ができる。だがこのスキルでは逆だ。窓外の銘柄を「参考」と称して出した瞬間、それはノイズであり、毎朝の銘柄ウォッチを汚す。だから窓外は参考でも一切出さない。0件はサボりではなく、正しい結論として胸を張って返す。
最後に「発表日が24時間窓の外なら必ず弾く」を絶対ルールとして据え、多重に強制する形で締めた。具体的には4重のガードを通す。Step 1 のクエリで発表日明記を要求し、Step 1.5 のゲートで窓内突合し、Step 2 のフィルタで Announced 欄が確証済みでなければ出さず、休場窓フォールバックで「0件が期待値」を明示する。どこか1枚が抜けても、後ろのガードが窓外銘柄を捕まえる。
学び
- 自動抽出はノイズを拾う。x-search は「投稿日が窓内のポスト」を返すだけで、その投稿が語っている決算がいつ発表されたかまでは保証しない。検索の対象軸と、自分が本当に欲しい軸がズレていないかを疑う。
- 発表日の検証ゲートが要る。拾ってきた候補を、自分の判定基準(=発表日が窓内か)で1段濾す工程を必ず挟む。フィルタは入力で1回かけて終わりではなく、出力の直前にもう一度かける。
- 0件を恐れない。出力ゼロが正しい状況は確かにある。何か出すために基準を緩めるのは、スキルの信頼を一番速く削る。窓外を参考で出すくらいなら、堂々と0件で返す。
混入に気づけたのは、Grok が出した数字を疑ったからではなく、「PLTR の決算は5月4日だったはず」というカレンダー上の事実が頭の隅に引っかかったからだった。自動化したスキルでも、最後に窓の外かどうかを見抜くのは、こちら側が持っている素朴な事実感覚だと改めて思った。