<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>AI on nnasaki のブログ</title>
    <link>https://blog.nnasaki.com/categories/ai/</link>
    <description>Recent content in AI on nnasaki のブログ</description>
    <image>
      <title>nnasaki のブログ</title>
      <url>https://blog.nnasaki.com/ogp.png</url>
      <link>https://blog.nnasaki.com/ogp.png</link>
    </image>
    <generator>Hugo</generator>
    <language>ja-JP</language>
    <lastBuildDate>Tue, 18 Aug 2026 11:30:00 +0900</lastBuildDate>
    <atom:link href="https://blog.nnasaki.com/categories/ai/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>「受け入れた」は品質の証拠にならない。残存率という指標を手元のリポジトリで数えた</title>
      <link>https://blog.nnasaki.com/entry/2026/08/18/measure-by-survival/</link>
      <pubDate>Tue, 18 Aug 2026 11:30:00 +0900</pubDate>
      <guid>https://blog.nnasaki.com/entry/2026/08/18/measure-by-survival/</guid>
      <description>&lt;p&gt;VS Code のブログに「&lt;a href=&#34;https://code.visualstudio.com/blogs/2026/07/29/mai-code-1-flash&#34;&gt;MAI-Code-1-Flash: early results from real developer workflows&lt;/a&gt;」という記事が出ました(2026-07-29 公開、2026-07-30 取得)。新しいコーディングモデルのローンチ記事なのですが、目を引いたのはモデルの性能ではなく、性能の測り方のほうでした。&lt;/p&gt;
&lt;p&gt;AI が書いたコードの評価に、受け入れたかどうかではなく、後から見てまだ残っているかを使っています。言いたいことを先に図にすると、こうです。&lt;/p&gt;
&lt;div style=&#34;overflow-x:auto;&#34;&gt;
&lt;svg viewBox=&#34;0 0 700 300&#34; role=&#34;img&#34; aria-label=&#34;受容率は受け入れの時点で測定が終わるが、残存率はコミットの時点まで測る。測る区間の長さが違い、両者は逆を向くことがある&#34; style=&#34;width:100%;min-width:620px;height:auto;font-family:sans-serif;&#34;&gt;
  &lt;style&gt;
    .box { fill: rgba(127,127,127,.08); stroke: currentColor; stroke-width: 1; }
    .hit { fill: rgba(127,127,127,.20); stroke: currentColor; stroke-width: 1.8; }
    .line { stroke: currentColor; stroke-width: 1.2; }
    .dash { stroke: currentColor; stroke-width: 1.2; stroke-dasharray: 4 4; opacity: .6; }
    .t { fill: currentColor; font-size: 13px; }
    .tc { fill: currentColor; font-size: 14px; text-anchor: middle; }
    .tb { fill: currentColor; font-size: 16px; font-weight: bold; }
    .tbc { fill: currentColor; font-size: 16px; font-weight: bold; text-anchor: middle; }
    .note { fill: currentColor; font-size: 13px; opacity: .8; }
  &lt;/style&gt;
  &lt;line x1=&#34;50&#34; y1=&#34;64&#34; x2=&#34;660&#34; y2=&#34;64&#34; class=&#34;line&#34;/&gt;
  &lt;circle cx=&#34;70&#34; cy=&#34;64&#34; r=&#34;5&#34; fill=&#34;currentColor&#34;/&gt;
  &lt;circle cx=&#34;230&#34; cy=&#34;64&#34; r=&#34;5&#34; fill=&#34;currentColor&#34;/&gt;
  &lt;circle cx=&#34;420&#34; cy=&#34;64&#34; r=&#34;5&#34; fill=&#34;currentColor&#34;/&gt;
  &lt;circle cx=&#34;620&#34; cy=&#34;64&#34; r=&#34;6&#34; fill=&#34;currentColor&#34;/&gt;
  &lt;text x=&#34;70&#34; y=&#34;40&#34; class=&#34;tc&#34;&gt;提案&lt;/text&gt;
  &lt;text x=&#34;230&#34; y=&#34;40&#34; class=&#34;tc&#34;&gt;受け入れる&lt;/text&gt;
  &lt;text x=&#34;420&#34; y=&#34;40&#34; class=&#34;tc&#34;&gt;その後さわる&lt;/text&gt;
  &lt;text x=&#34;620&#34; y=&#34;40&#34; class=&#34;tc&#34;&gt;コミット&lt;/text&gt;
  &lt;line x1=&#34;70&#34; y1=&#34;70&#34; x2=&#34;70&#34; y2=&#34;152&#34; class=&#34;dash&#34;/&gt;
  &lt;line x1=&#34;230&#34; y1=&#34;70&#34; x2=&#34;230&#34; y2=&#34;102&#34; class=&#34;dash&#34;/&gt;
  &lt;line x1=&#34;620&#34; y1=&#34;70&#34; x2=&#34;620&#34; y2=&#34;152&#34; class=&#34;dash&#34;/&gt;
  &lt;rect x=&#34;70&#34; y=&#34;102&#34; width=&#34;160&#34; height=&#34;32&#34; rx=&#34;4&#34; class=&#34;box&#34;/&gt;
  &lt;text x=&#34;150&#34; y=&#34;124&#34; class=&#34;tbc&#34;&gt;受容率&lt;/text&gt;
  &lt;text x=&#34;244&#34; y=&#34;124&#34; class=&#34;note&#34;&gt;ここで測定が終わる。材料は差分と、読んだ数十秒だけ&lt;/text&gt;
  &lt;rect x=&#34;70&#34; y=&#34;152&#34; width=&#34;550&#34; height=&#34;32&#34; rx=&#34;4&#34; class=&#34;hit&#34;/&gt;
  &lt;text x=&#34;345&#34; y=&#34;174&#34; class=&#34;tbc&#34;&gt;残存率&lt;/text&gt;
  &lt;text x=&#34;70&#34; y=&#34;206&#34; class=&#34;note&#34;&gt;残存率は、動かして落ちた・読み返して消した … 受容の時点には無かった材料で決まる&lt;/text&gt;
  &lt;rect x=&#34;20&#34; y=&#34;228&#34; width=&#34;660&#34; height=&#34;54&#34; rx=&#34;5&#34; class=&#34;box&#34;/&gt;
  &lt;text x=&#34;36&#34; y=&#34;252&#34; class=&#34;tb&#34;&gt;測る区間が違うから、2つは逆を向くことがある&lt;/text&gt;
  &lt;text x=&#34;36&#34; y=&#34;274&#34; class=&#34;t&#34;&gt;元記事の実測: 受容率 −6% のモデルが、残存率 +4% / コミット時残存率 +6%（baseline 比）&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;p&gt;受容率は「読んで通したか」、残存率は「後から消さなかったか」。判定する材料も、判定する時点も違います。&lt;/p&gt;</description>
    </item>
    <item>
      <title>エージェント運用をグラフとして設計する。14段ロードマップの主張を2つ、手元で実測した</title>
      <link>https://blog.nnasaki.com/entry/2026/08/18/graph-engineering/</link>
      <pubDate>Tue, 18 Aug 2026 09:25:27 +0900</pubDate>
      <guid>https://blog.nnasaki.com/entry/2026/08/18/graph-engineering/</guid>
      <description>&lt;p&gt;0xMovez AI さんの「&lt;a href=&#34;https://movez.substack.com/p/graph-engineering-with-claude-14&#34;&gt;Graph Engineering with Claude: 14-Step roadmap from 0 to graph architect&lt;/a&gt;」(2026-07-25 公開、2026-07-30 取得)を読みました。直線的に走らせているエージェント運用を、処理の単位(節点)とデータが流れる経路(辺)からなるグラフとして設計し直す、という記事です。&lt;/p&gt;
&lt;p&gt;主張のうち2つを手元の環境で実際に動かして確かめたので、その結果まで書きます。&lt;/p&gt;
&lt;h2 id=&#34;記事が言っていること&#34;&gt;記事が言っていること&lt;/h2&gt;
&lt;p&gt;14段の構成です。前半は基礎(節点は1エージェント1ジョブ、辺は実際にデータが流れる依存だけ)、中盤は型(並列展開、全部揃ってから進む待ち合わせ、展開→縮約→統合のダイヤモンド、辺の上に検証者を置く)、終盤が今回試した2つです。&lt;/p&gt;
&lt;p&gt;Step 12(節点ごとにモデルを階層化する):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Not every node needs your best model. (中略) Run the boring nodes on a cheaper model and spend your expensive tokens where judgment actually lives.&lt;/p&gt;
&lt;p&gt;〔訳〕すべての節点に最良のモデルが要るわけではない。退屈な節点は安いモデルで走らせ、高価なトークンは判断が実際に住んでいる場所に使え。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Step 14(良い実行を再実行可能な定義として保存する):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When a run is good, press s to save its script into .claude/workflows/ - version-controlled, re-runnable by name, a graph anyone who clones the repo can launch.&lt;/p&gt;</description>
    </item>
    <item>
      <title>エージェントに「なんで？」と聞くのをやめて、作業のときに書かせる</title>
      <link>https://blog.nnasaki.com/entry/2026/08/15/rationale-from-the-record/</link>
      <pubDate>Sat, 15 Aug 2026 11:29:00 +0900</pubDate>
      <guid>https://blog.nnasaki.com/entry/2026/08/15/rationale-from-the-record/</guid>
      <description>&lt;p&gt;エージェントが妙な変更をしたとき、「なんでこうしたの？」と聞いている人向けです。返ってくる答えが何なのか、代わりにどこを読めばよいのかを書きます。あわせて、手元の Claude Code のセッションログに思考の中身が残っているかを数えたので、そのコマンドと出力をそのまま載せます。&lt;/p&gt;
&lt;p&gt;きっかけは X の投稿です。そこで挙げられていた理由（thinking が直近ターンしか文脈に入らない）は、公式ドキュメントに当たるとモデルによって違いました。ただし、どちらのモデルでもやることは変わりません。なぜ変わらないのかまで書きます。&lt;/p&gt;
&lt;h2 id=&#34;まとめ&#34;&gt;まとめ&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;エージェントに「なんで？」と聞くのをやめます。代わりに、依頼するときに「変更ごとに、その根拠を1行で添えて」と書いておいて、あとでその記録を読みます。理由は、聞いてから作らせるのではなく、作業した時点で書かせるほうが確かだからです。&lt;/li&gt;
&lt;li&gt;聞いて返ってくる説明は、そのとき作られたものです。ヒントを与えて答えを変えさせた実験で、そのヒントを使ったと自分で書いたのは 25% でした（Claude 3.7 Sonnet での測定。新しいモデルで同じ数字になるとは限りません）。&lt;/li&gt;
&lt;li&gt;Claude Code を使っているなら、自分のセッションログを開いてみてください。既定では、考えた形跡だけがあって中身が空です（数えたら 6,319 個すべてが 0 文字でした）。設定を入れると、画面で対話しながら進めた分は残ります。&lt;code&gt;-p&lt;/code&gt; を付けて実行した分は残りません。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;⚠ 「セッションログ」「思考」「対話モード」が何を指すかは、本文で順に説明します。まとめだけで分からなくても、読み進めれば分かるようになります。&lt;/p&gt;
&lt;h2 id=&#34;きっかけの投稿&#34;&gt;きっかけの投稿&lt;/h2&gt;
&lt;p&gt;もとは、LLM に理由を尋ねたときの応答についての投稿です（&lt;a href=&#34;https://x.com/golden_lucky/status/2082805277737505171&#34;&gt;@golden_lucky&lt;/a&gt;、2026-07-30 投稿、2026-08-15 取得）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「なんでこうしたの？」ってLLMに言うと「すみません考えが足りませんでした」みたいなこと言ってくるけど、そうじゃなくて理由を聞いてるんだよ、理由を答えてくれよ、人間になるなよ&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;これを引用して、原因と対策を述べた投稿がこちらです（&lt;a href=&#34;https://x.com/Hi_Noguchi/status/2083208558452281704&#34;&gt;@Hi_Noguchi&lt;/a&gt;、2026-07-31 投稿、2026-08-15 取得）。長いので要点だけ引きます。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;少なくとも Claude についていうと、「なんで」かは Claude 側も「知らない」。というのも thinking の内容が直近ターンのものしかコンテクストウィンドウに入っていないため。&lt;/p&gt;
&lt;p&gt;なので Claude は過去の自分のアウトプットだけを見て、事後推測するしかないというわけ。だからそれっぽい「ウソ」ついたりする。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;対策として、&lt;code&gt;showThinkingSummaries&lt;/code&gt; を有効にしてセッションログ（jsonl）に記録される thinking summary を振り返らせること、その自動投入先として DuckDB や hooks が挙げられています。&lt;/p&gt;
&lt;p&gt;言っていることには納得しました。理由を聞く相手を、エージェント本人から記録へ移すという話です。そのうえで、記録に何がどう入るのかを確かめました。&lt;/p&gt;
&lt;h2 id=&#34;エージェントとのやりとりで思考はどう扱われているのか&#34;&gt;エージェントとのやりとりで、思考はどう扱われているのか&lt;/h2&gt;
&lt;h3 id=&#34;1回目と2回目に何が行き来しているのか&#34;&gt;1回目と2回目に、何が行き来しているのか&lt;/h3&gt;
&lt;p&gt;先に用語を分けます。この記事で「説明」と呼んでいるのは、あとから「なんで？」と聞いたときに返ってくる文章のことです。モデルが答える前に内部でやっている推論のほうは「思考」と呼び、API では &lt;code&gt;thinking&lt;/code&gt; ブロックとして扱われます。別物です。&lt;/p&gt;
&lt;p&gt;以下は Anthropic の &lt;a href=&#34;https://docs.claude.com/en/docs/build-with-claude/thinking&#34;&gt;Extended thinking&lt;/a&gt;（2026-08-15 取得）に書かれている API の挙動です。Claude Code のようなハーネス越しに使っているときも、下ではこのやりとりが起きています。&lt;/p&gt;</description>
    </item>
    <item>
      <title>エージェントハーネスの grep は grep ではなかった。「0件でした」を信じていたら、本文は全文入っていた</title>
      <link>https://blog.nnasaki.com/entry/2026/08/15/grep-that-lies-twice/</link>
      <pubDate>Sat, 15 Aug 2026 10:00:00 +0900</pubDate>
      <guid>https://blog.nnasaki.com/entry/2026/08/15/grep-that-lies-twice/</guid>
      <description>&lt;p&gt;&lt;strong&gt;エージェントに調べ物をさせて、その結果を信じてよいか確かめている人向けです。&lt;/strong&gt; 「原文を取ってきて、この語句を &lt;code&gt;grep&lt;/code&gt; して件数を報告せよ」という指示は、裏取りのやり方としてかなり筋がよく見えます。実際、私はそれを規約に書いて1週間ほど運用していました(明文化したのは 2026-07-26 です)。その規約が破れたので、破れ方と直し方を書きます。手元で最小再現まで取れたので、コマンドと出力をそのまま載せます。&lt;/p&gt;
&lt;p&gt;先にまとめです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;エージェントハーネスは、あなたが呼んだつもりのコマンドを別物に差し替えていることがあります。&lt;/strong&gt; 私の環境で &lt;code&gt;grep&lt;/code&gt; を呼ぶと、それは GNU/BSD の grep ではなくシェル関数で &lt;code&gt;ugrep -I&lt;/code&gt; に差し替わっていました(Claude Code 2.1.220 / macOS / zsh、2026-08-02 時点)。&lt;code&gt;-I&lt;/code&gt; はバイナリ扱いのファイルを飛ばすオプションで、&lt;strong&gt;NUL バイトが1個でもあると、何も出力せず終了コード1&lt;/strong&gt; を返します。&lt;code&gt;grep -c&lt;/code&gt; が出すはずの &lt;code&gt;0&lt;/code&gt; すら出ません&lt;/li&gt;
&lt;li&gt;そして &lt;code&gt;grep -c&lt;/code&gt; が数えているのは&lt;strong&gt;行数であって出現回数ではありません&lt;/strong&gt;。圧縮された1行の HTML では、何を探しても件数が &lt;code&gt;1&lt;/code&gt; になります&lt;/li&gt;
&lt;li&gt;この2つが重なった結果、サブエージェントが「本文は取得できていません(ヒット0件)」と報告してきました。&lt;strong&gt;実際には本文が全文入っていました&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;差し替えの中身はハーネスごとに違うはずですが、&lt;strong&gt;「自分が指定したコマンドが、その名前どおりのものとは限らない」という形&lt;/strong&gt;は、どのハーネスでも同じだと思います。以下、私の環境での実測です。&lt;/p&gt;
&lt;h2 id=&#34;なぜ件数を報告せよにしていたか&#34;&gt;なぜ「件数を報告せよ」にしていたか&lt;/h2&gt;
&lt;p&gt;先に背景を書きます。読み飛ばして構いません。&lt;/p&gt;
&lt;p&gt;エージェントに文章を書かせると、もっともらしい嘘が混ざります。厄介なのは、&lt;strong&gt;書いた本人にそれが検出できない&lt;/strong&gt;ことです。自分の出力を自分で検算しても、生成したときと同じ経路をたどって同じ結論に戻ります。&lt;/p&gt;
&lt;p&gt;そこで「書く人」と「原典に当たり直す人」を分けて、後者には次の形で報告させていました。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;該当句を生 HTML に対して &lt;code&gt;grep -c&lt;/code&gt; し、&lt;strong&gt;ヒット数&lt;/strong&gt;を報告せよ。バイト数は同一性の証明にならない(動的サイトはリクエストごとに揺れる)。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;バイト数を退けているのは、それが証拠にならないからです。同じ URL でも日をまたぐと変わります。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ U&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;https://x.com/kimuai08/status/2082428727401869753
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -sL -A &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Mozilla/5.0&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$U&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -o x.html -w &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%{size_download} bytes\n&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;362384 bytes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;2026-08-02 取得です。前日 2026-08-01 に同じコマンドで取ったときは 362,678 バイト、同日に User-Agent を Chrome のものに変えたときは 367,448 バイトでした。&lt;strong&gt;どれも「取れた」のに、数字は一致しません。&lt;/strong&gt; だから「その語句が原文に在るか」という形の証拠、つまり &lt;code&gt;grep&lt;/code&gt; の件数に寄せていた、という経緯です。&lt;/p&gt;</description>
    </item>
    <item>
      <title>CLAUDE.md のどの行を消してよいか、ビルドの Red/Green で決める</title>
      <link>https://blog.nnasaki.com/entry/2026/08/07/prompt-subtraction-needs-a-gate/</link>
      <pubDate>Fri, 07 Aug 2026 10:26:00 +0900</pubDate>
      <guid>https://blog.nnasaki.com/entry/2026/08/07/prompt-subtraction-needs-a-gate/</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; や &lt;code&gt;AGENTS.md&lt;/code&gt;、&lt;code&gt;copilot-instructions.md&lt;/code&gt; が膨らんできて、削りたいが怖くて削れない人向けです。&lt;/strong&gt; 削ってよい行を、勘ではなく CI の終了コードで判定する方法を書きます。手元のリポジトリで9通り実測したので、その手順と結果をそのまま載せます。&lt;/p&gt;
&lt;p&gt;以下、&lt;strong&gt;規則違反を検出して CI を落とす自動検査&lt;/strong&gt;（lint、ビルド時の検査、生成物の検査など、種類は問いません）を &lt;strong&gt;「ゲート」&lt;/strong&gt; と呼びます。この記事の話は結局のところ、&lt;strong&gt;文書に書いた規則と、ゲートが見ている規則の、重なりを測る&lt;/strong&gt;というだけのことです。&lt;/p&gt;
&lt;p&gt;⚠ &lt;strong&gt;もう1つ先に読み方を。この記事の RED/GREEN は、いつもの「ビルドが通った/落ちた」ではありません。&lt;/strong&gt; &lt;strong&gt;わざと違反を仕込んだ状態&lt;/strong&gt;で CI を回すので、向きが裏返ります。&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;いつもの CI&lt;/th&gt;
          &lt;th&gt;この記事&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;RED&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;まずい&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;ゲートが仕事をした&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;GREEN&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;よい&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;誰も見ていない&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;TDD で、実装を書く前にテストを一度 RED にして「このテストはちゃんと落ちる」と確かめるのと同じ向きです。&lt;strong&gt;赤くならないテストが無意味なのと同様に、破っても GREEN のままの規則は、機械には存在していません。&lt;/strong&gt;（コードの世界では mutation testing——わざと壊したコードにテストを当てて、ちゃんと落ちるか確かめる手法——と呼ばれているものを、命令文書に当てているだけです。）&lt;/p&gt;
&lt;p&gt;たとえるなら、&lt;code&gt;CLAUDE.md&lt;/code&gt; の一行は「ドアを閉めること」という&lt;strong&gt;張り紙&lt;/strong&gt;で、ゲートは開けっぱなしを検知する&lt;strong&gt;警報装置&lt;/strong&gt;です。この記事でやるのは、張り紙を剥がしてみて様子を見ることでは&lt;strong&gt;ありません&lt;/strong&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;張り紙（文書の規則）を1つ選ぶ。&lt;strong&gt;まだ剥がさない&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;張り紙が禁じていることを、&lt;strong&gt;コードのほうでわざとやってみる&lt;/strong&gt;（確かめたら元に戻します）&lt;/li&gt;
&lt;li&gt;警報（CI）が鳴れば &lt;strong&gt;RED&lt;/strong&gt;。機械が見張っているので、張り紙は剥がせる&lt;/li&gt;
&lt;li&gt;鳴らなければ &lt;strong&gt;GREEN&lt;/strong&gt;。見張りは張り紙しかないので、剥がせない。&lt;strong&gt;先に警報装置を作る&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;順序が肝心です。先に張り紙を剥がしても警報の配線は何も変わらないので、鳴るかどうかの確かめにはなりません。剥がすのは、鳴ると確かめたあとです。&lt;/p&gt;
&lt;h2 id=&#34;まとめ&#34;&gt;まとめ&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;判定はこれだけです。「その規則をわざと破ったとき、CI は気づくか」。&lt;/strong&gt; 気づく（RED）なら機械が同じことを言っているので、文書の行は消せます（&lt;strong&gt;ただし、その規則を破る頻度が低いときに限ります&lt;/strong&gt;。理由は後半に）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;気づかない（GREEN）は「文書に残す」ではありません。「ゲートの積み残し」です。&lt;/strong&gt; &lt;strong&gt;まずゲートを書けないか考え、書けないものだけを文書に残します。&lt;/strong&gt; 手元では GREEN 4件のうち3件を実際に書けたので、&lt;code&gt;CLAUDE.md&lt;/code&gt; から削除しました。最終的に &lt;strong&gt;9件中8件が文書から消え、残ったのは1件&lt;/strong&gt;です。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;削れる行の割合は、文書の質ではなくゲートの本数で決まります。&lt;/strong&gt; 8割削りたければ、先に8割を捕まえる機械が要ります。順序は逆にできません。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;なぜこれを測ったか&#34;&gt;なぜこれを測ったか&lt;/h2&gt;
&lt;p&gt;「Claude Code のプロンプトの 80% を削った」と題した Claude Code 作者の動画が公開されました（&lt;a href=&#34;https://www.youtube.com/watch?v=qyPCVqFUyDo&#34;&gt;YouTube&lt;/a&gt;、2026-08-07 取得）。ページの HTML には &lt;code&gt;&amp;quot;uploadDate&amp;quot;:&amp;quot;2026-07-27T10:00:30-07:00&amp;quot;&lt;/code&gt;、&lt;code&gt;itemprop=&amp;quot;duration&amp;quot; content=&amp;quot;PT35M52S&amp;quot;&lt;/code&gt; とあります。同ページの説明文によれば、出演は Boris Cherny と Diana Hu、収録は Startup School 2026 です。&lt;/p&gt;</description>
    </item>
    <item>
      <title>MCP がステートレスになった — リモートサーバを運用する側から見て何が変わるか</title>
      <link>https://blog.nnasaki.com/entry/2026/07/29/mcp-2026-07-28-stateless/</link>
      <pubDate>Wed, 29 Jul 2026 14:50:05 +0900</pubDate>
      <guid>https://blog.nnasaki.com/entry/2026/07/29/mcp-2026-07-28-stateless/</guid>
      <description>&lt;p&gt;MCP の新しい仕様 2026-07-28 が出ました。告知の一文が「MCP is now stateless, making it easier to deploy and scale remote servers」です（&lt;a href=&#34;https://x.com/ClaudeDevs/status/2082164248697069935&#34;&gt;@ClaudeDevs&lt;/a&gt;、2026-07-29 取得）。&lt;/p&gt;
&lt;p&gt;リモート MCP サーバを自分で運用する側から読むと、これは仕様の話というより&lt;strong&gt;配置の話&lt;/strong&gt;でした。実際に最小のサーバを書いて確かめたので、その結果まで書きます。&lt;/p&gt;
&lt;h2 id=&#34;何が変わったか&#34;&gt;何が変わったか&lt;/h2&gt;
&lt;h3 id=&#34;ステートレス化は3層にまたがっている&#34;&gt;ステートレス化は3層にまたがっている&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://modelcontextprotocol.io/specification/2026-07-28/changelog&#34;&gt;changelog&lt;/a&gt;（2026-07-29 取得）を読むと、「ステートレス」が指しているものは1か所ではありませんでした。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;セッション管理&lt;/strong&gt; — &lt;code&gt;Mcp-Session-Id&lt;/code&gt; ヘッダがプロトコルレベルで削除されました。さらに &lt;code&gt;initialize&lt;/code&gt; / &lt;code&gt;notifications/initialized&lt;/code&gt; のハンドシェイク自体が無くなり、各リクエストが &lt;code&gt;_meta&lt;/code&gt; に自分でプロトコル版とクライアント capability を載せます（&lt;code&gt;io.modelcontextprotocol/protocolVersion&lt;/code&gt;、&lt;code&gt;io.modelcontextprotocol/clientCapabilities&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;トランスポート&lt;/strong&gt; — GET のストリームエンドポイントが削除されました。サーバが公開するのは &lt;strong&gt;POST を受ける単一エンドポイントだけ&lt;/strong&gt;です。SSE は「そのリクエストにスコープされたストリーム」としてのみ残り、&lt;code&gt;Last-Event-ID&lt;/code&gt; による再開機能も削除されています。切れたら新しい request ID で送り直す、という規定になりました。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;双方向性&lt;/strong&gt; — &lt;code&gt;roots/list&lt;/code&gt; や &lt;code&gt;sampling/createMessage&lt;/code&gt; のようなサーバ起点のリクエストは Multi Round-Trip Requests（MRTR）に置き換わりました。サーバは &lt;code&gt;resultType: &amp;quot;input_required&amp;quot;&lt;/code&gt; を返し、クライアントが元のリクエストをリトライする際に応答を添えます。常時開いた双方向ストリームが要らなくなる、という形です。&lt;/p&gt;
&lt;p&gt;かわりに &lt;code&gt;server/discover&lt;/code&gt; が追加され、こちらはサーバの実装が MUST です。&lt;/p&gt;
&lt;p&gt;図にするとこうです。左が従来、右が 2026-07-28 です。&lt;/p&gt;
&lt;div style=&#34;overflow-x:auto;&#34;&gt;
&lt;svg viewBox=&#34;0 0 760 330&#34; role=&#34;img&#34; aria-label=&#34;従来のステートフルな MCP と 2026-07-28 のステートレスな MCP の対比&#34; style=&#34;width:100%;min-width:680px;height:auto;font-family:sans-serif;&#34;&gt;
  &lt;style&gt;
    .box { fill: rgba(127,127,127,.08); stroke: currentColor; stroke-width: 1; }
    .line { stroke: currentColor; stroke-width: 1; }
    .life { stroke: currentColor; stroke-width: 1; stroke-dasharray: 3 3; opacity: .5; }
    .arrow { stroke: currentColor; stroke-width: 1.2; marker-end: url(#ah); fill: none; }
    .t { fill: currentColor; font-size: 11px; }
    .tc { fill: currentColor; font-size: 11px; text-anchor: middle; }
    .title { fill: currentColor; font-size: 13px; font-weight: bold; text-anchor: middle; }
    .note { fill: currentColor; font-size: 11px; text-anchor: middle; opacity: .75; }
  &lt;/style&gt;
  &lt;defs&gt;
    &lt;marker id=&#34;ah&#34; markerWidth=&#34;8&#34; markerHeight=&#34;8&#34; refX=&#34;7&#34; refY=&#34;4&#34; orient=&#34;auto&#34;&gt;
      &lt;path d=&#34;M0,0 L8,4 L0,8 z&#34; fill=&#34;currentColor&#34;/&gt;
    &lt;/marker&gt;
  &lt;/defs&gt;
  &lt;text x=&#34;185&#34; y=&#34;20&#34; class=&#34;title&#34;&gt;従来(〜2025-11-25)&lt;/text&gt;
  &lt;text x=&#34;575&#34; y=&#34;20&#34; class=&#34;title&#34;&gt;2026-07-28&lt;/text&gt;
  &lt;!-- 左: ステートフル --&gt;
  &lt;rect x=&#34;20&#34; y=&#34;34&#34; width=&#34;90&#34; height=&#34;26&#34; class=&#34;box&#34;/&gt;
  &lt;text x=&#34;65&#34; y=&#34;51&#34; class=&#34;tc&#34;&gt;クライアント&lt;/text&gt;
  &lt;rect x=&#34;260&#34; y=&#34;34&#34; width=&#34;90&#34; height=&#34;26&#34; class=&#34;box&#34;/&gt;
  &lt;text x=&#34;305&#34; y=&#34;51&#34; class=&#34;tc&#34;&gt;サーバ&lt;/text&gt;
  &lt;line x1=&#34;65&#34; y1=&#34;60&#34; x2=&#34;65&#34; y2=&#34;270&#34; class=&#34;life&#34;/&gt;
  &lt;line x1=&#34;305&#34; y1=&#34;60&#34; x2=&#34;305&#34; y2=&#34;270&#34; class=&#34;life&#34;/&gt;
  &lt;text x=&#34;185&#34; y=&#34;82&#34; class=&#34;tc&#34;&gt;initialize / initialized&lt;/text&gt;
  &lt;path d=&#34;M65,88 L297,88&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;185&#34; y=&#34;112&#34; class=&#34;tc&#34;&gt;Mcp-Session-Id を発行&lt;/text&gt;
  &lt;path d=&#34;M305,118 L73,118&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;185&#34; y=&#34;142&#34; class=&#34;tc&#34;&gt;以後の全リクエストに Session-Id&lt;/text&gt;
  &lt;path d=&#34;M65,148 L297,148&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;185&#34; y=&#34;172&#34; class=&#34;tc&#34;&gt;GET の常時 SSE ストリーム&lt;/text&gt;
  &lt;path d=&#34;M305,178 L73,178&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;185&#34; y=&#34;202&#34; class=&#34;tc&#34;&gt;サーバ起点の要求(sampling 等)&lt;/text&gt;
  &lt;path d=&#34;M305,208 L73,208&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;185&#34; y=&#34;240&#34; class=&#34;note&#34;&gt;両端が「どのセッションか」を&lt;/text&gt;
  &lt;text x=&#34;185&#34; y=&#34;256&#34; class=&#34;note&#34;&gt;覚えている必要がある&lt;/text&gt;
  &lt;!-- 右: ステートレス --&gt;
  &lt;rect x=&#34;410&#34; y=&#34;34&#34; width=&#34;90&#34; height=&#34;26&#34; class=&#34;box&#34;/&gt;
  &lt;text x=&#34;455&#34; y=&#34;51&#34; class=&#34;tc&#34;&gt;クライアント&lt;/text&gt;
  &lt;rect x=&#34;650&#34; y=&#34;34&#34; width=&#34;90&#34; height=&#34;26&#34; class=&#34;box&#34;/&gt;
  &lt;text x=&#34;695&#34; y=&#34;51&#34; class=&#34;tc&#34;&gt;サーバ&lt;/text&gt;
  &lt;line x1=&#34;455&#34; y1=&#34;60&#34; x2=&#34;455&#34; y2=&#34;270&#34; class=&#34;life&#34;/&gt;
  &lt;line x1=&#34;695&#34; y1=&#34;60&#34; x2=&#34;695&#34; y2=&#34;270&#34; class=&#34;life&#34;/&gt;
  &lt;text x=&#34;575&#34; y=&#34;82&#34; class=&#34;tc&#34;&gt;POST(単一エンドポイント)&lt;/text&gt;
  &lt;path d=&#34;M455,88 L687,88&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;575&#34; y=&#34;104&#34; class=&#34;note&#34;&gt;_meta に版と capability を自己記述&lt;/text&gt;
  &lt;text x=&#34;575&#34; y=&#34;134&#34; class=&#34;tc&#34;&gt;resultType: complete&lt;/text&gt;
  &lt;path d=&#34;M695,140 L463,140&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;575&#34; y=&#34;164&#34; class=&#34;tc&#34;&gt;resultType: input_required&lt;/text&gt;
  &lt;path d=&#34;M695,170 L463,170&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;575&#34; y=&#34;194&#34; class=&#34;tc&#34;&gt;元リクエストをリトライ+応答添付&lt;/text&gt;
  &lt;path d=&#34;M455,200 L687,200&#34; class=&#34;arrow&#34;/&gt;
  &lt;text x=&#34;575&#34; y=&#34;216&#34; class=&#34;note&#34;&gt;(MRTR: サーバ起点の代替)&lt;/text&gt;
  &lt;text x=&#34;575&#34; y=&#34;240&#34; class=&#34;note&#34;&gt;接続をまたいで覚えるものがない。&lt;/text&gt;
  &lt;text x=&#34;575&#34; y=&#34;256&#34; class=&#34;note&#34;&gt;SSE はリクエスト内のみ&lt;/text&gt;
  &lt;line x1=&#34;380&#34; y1=&#34;30&#34; x2=&#34;380&#34; y2=&#34;300&#34; class=&#34;life&#34;/&gt;
  &lt;text x=&#34;185&#34; y=&#34;292&#34; class=&#34;note&#34;&gt;ハンドシェイク・セッション・GET ストリームがある&lt;/text&gt;
  &lt;text x=&#34;575&#34; y=&#34;292&#34; class=&#34;note&#34;&gt;各リクエストが自己完結する&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;h3 id=&#34;ステートレス化だけではない&#34;&gt;ステートレス化「だけ」ではない&lt;/h3&gt;
&lt;p&gt;ここが読み違えていたところです。changelog の major change は9件あって、破壊的なものが並んでいます。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
