「設定に非推奨の項目があります」という控えめな通知が画面の隅に出たのは、受託のサイト制作で預かっている Mac のセットアップを終えた直後でした。Details を開くと、フィールド名と置き換え先と受付終了日が並んでいます。2026 年 10 月 7 日の正午、米太平洋時間。
その場で全部書き換えてしまおうと思いました。並んでいるのはほとんどが単純な改名で、エディタの置換機能で片が付きそうに見えたのです。
手が止まったのは、Claude Desktop / Cowork のチェンジログを読み直したときでした。項目の一つに、置き換え先だけでなく「配布側のバージョンを先に上げてください」という条件が添えられていたのです。
先に上げてから、書き換えます。 期限に急かされて設定ファイルだけを直すと、古い版のまま残った端末が、期限が来るより前に止まってしまうのです。
期限は一つでも、手を付けてよい時期は三つに分かれます
一覧を眺めながら、私は項目を三つの箱に分けました。
一つめは、いま書き換えてよいもの。inferenceGatewayHeaders を inferenceCustomHeaders へ、isDxtEnabled を isDesktopExtensionEnabled へ、といった素直な改名です。古い版のアプリも新しい綴りを理解しますので、早く直しても困りません。
二つめは、配っているアプリのバージョンを上げてから書き換えるもの。orgPluginSettings の record 形式から array 形式への移行がここに入ります。1.15200.0 より前の Desktop は record 形式しか読まず、array 形式を渡されるとプラグインのツールロックを強制しません。つまり設定だけを先に直すと、期限前の今この瞬間に、意図した制限が外れた端末が生まれます。
Vertex AI の inferenceCredentialKind も同じ箱です。自前のブートストラップサーバや Setup の JSON エクスポートのように、ネストした JSON で配っている場合、古い Desktop はネストされた interactive から Google のクライアント ID を落としてしまいます。サインインが通らなくなりますので、全台が新しい版になるまで oauth のまま据え置くのが正解でした——ただし、フラットな MDM キー、.mobileconfig、.reg で配っている場合は影響を受けません。配り方によって危険度が違うのです。
三つめが、私が読み落としかけた箱です。書き換えなくても、10 月 7 日を境に意味が変わる設定があります。 interactive と inferenceVertexWorkforceAudience を指定し、inferenceVertexOAuthClientId を書いていない Vertex の構成は、いまは Workforce Identity として読まれます。受付終了後は Google サインインとして読まれます。ファイルの中身は一文字も変わらないのに、解釈だけが入れ替わります。Workforce のつもりであれば workforce を明示しておく必要があります。いま思えば、私は「期限までに直せるか」ばかりを数えていて、「いつ直してよいか」をひと言も数えていなかったのかもしれません。
旧い綴りが残っているかを、箱ごとに数えます
三つの箱を頭の中で数えるのは無理だと感じましたので、仕分けをそのままスクリプトにしました。引数に管理構成の JSON を渡すと、A・B・C の箱ごとに件数と場所を出します。
#!/usr/bin/env python3
"""管理構成 JSON に残った旧い綴りを、対処の順番ごとに仕分けします。
使い方: python3 audit_config.py bootstrap.json [more.json ...]
終了コード: 0=旧綴りなし / 1=B か C の項目あり / 2=A のみ"""
import json, sys
# (旧綴り, 新綴り, 箱)
# A = 先に書き換えてよい / B = クライアントを上げてから / C = 触らなくても意味が変わる
RENAMES = [
("inferenceGatewayHeaders", "inferenceCustomHeaders", "A"),
("trustBootstrapLocalExec", "trustBootstrapDelivery", "A"),
("enduserAttribution", "endUserAttribution", "A"),
("isDxtEnabled", "isDesktopExtensionEnabled", "A"),
("isDxtSignatureRequired", "isDesktopExtensionSignatureRequired", "A"),
("authorityHost", 'azureCloud: "us-gov-high"', "A"),
]
HEADER_MAPS = ["inferenceCustomHeaders", "otlpHeaders",
"otlpResourceAttributes", "bootstrapHeaders"]
def walk(node, path=""):
"""ネストした dict / list を (パス, キー, 値) で平坦に辿ります。"""
if isinstance(node, dict):
for k, v in node.items():
here = f"{path}.{k}" if path else k
yield here, k, v
yield from walk(v, here)
elif isinstance(node, list):
for i, v in enumerate(node):
here = f"{path}[{i}]"
yield here, None, v
yield from walk(v, here)
def audit(cfg):
found = []
for path, key, value in walk(cfg):
if key is None:
continue
for old, new, bucket in RENAMES:
if key == old:
found.append((bucket, path, f"{old} -> {new}"))
# ヘッダ類は JSON オブジェクトでなければ受け付けられなくなります
if key in HEADER_MAPS and not isinstance(value, dict):
found.append(("A", path,
f"{key} が {type(value).__name__} です -> JSON オブジェクトへ"))
# record 形式の orgPluginSettings は array 形式へ。ただし配布側を先に上げます
if key == "orgPluginSettings" and isinstance(value, dict):
found.append(("B", path,
"orgPluginSettings が record 形式です -> array 形式へ"
"(配布中の Desktop を 1.15200.0 より後へ上げてから)"))
# ask-session は ask へ
if key in ("builtinToolPolicy", "toolPolicy", "permission"):
vals = value.values() if isinstance(value, dict) else [value]
if any(v == "ask-session" for v in vals):
found.append(("A", path, "ask-session -> ask"))
# Vertex: ネストした JSON で配っているなら、全台が上がるまで oauth のまま
if key == "inferenceCredentialKind" and value == "oauth":
found.append(("B", path,
'inferenceCredentialKind: "oauth" -> "interactive"'
"(ネスト配布なら全台を上げ切ってから)"))
# 触らなくても 10/07 に解釈が変わる組み合わせ
if (cfg.get("inferenceCredentialKind") == "interactive"
and "inferenceVertexWorkforceAudience" in cfg
and "inferenceVertexOAuthClientId" not in cfg):
found.append(("C", "(top level)",
"いまは Workforce Identity と読まれますが、10/07 以降は "
"Google サインインになります -> workforce を明示"))
return found
def main(paths):
buckets = {"A": [], "B": [], "C": []}
for p in paths:
with open(p, encoding="utf-8") as fh:
cfg = json.load(fh)
for bucket, path, msg in audit(cfg):
buckets[bucket].append(f"{p}:{path} {msg}")
labels = {"A": "A 先に書き換えてよいもの",
"B": "B クライアントを上げてから書き換えるもの",
"C": "C 書き換えなくても期限後に意味が変わるもの"}
for b in ("A", "B", "C"):
print(f"\n## {labels[b]} ({len(buckets[b])} 件)")
for line in buckets[b] or [" (該当なし)"]:
print(" " + line if not line.startswith(" ") else line)
if buckets["B"] or buckets["C"]:
return 1
return 2 if buckets["A"] else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))旧綴りを一通り混ぜたファイルを食わせると、こう出ます。
## A 先に書き換えてよいもの (4 件)
sample.json:inferenceGatewayHeaders inferenceGatewayHeaders -> inferenceCustomHeaders
sample.json:otlpHeaders otlpHeaders が str です -> JSON オブジェクトへ
sample.json:isDxtEnabled isDxtEnabled -> isDesktopExtensionEnabled
sample.json:managedMcpServers[0].toolPolicy ask-session -> ask
## B クライアントを上げてから書き換えるもの (1 件)
sample.json:orgPluginSettings orgPluginSettings が record 形式です -> array 形式へ(配布中の Desktop を 1.15200.0 より後へ上げてから)
## C 書き換えなくても期限後に意味が変わるもの (1 件)
sample.json:(top level) いまは Workforce Identity と読まれますが、10/07 以降は Google サインインになります -> workforce を明示walk() を再帰にしてあるのは、managedMcpServers の配下に旧い書き方が沈んでいることが多いからです。トップレベルだけを in で調べていたときは、配列の中の toolPolicy をまるごと見落としていました。終了コードを三段階に分けているのは、CI で「A だけなら通す、B か C があれば人間を呼ぶ」という扱いにしたかったからです。
旧名と新名の対応
改名だけを抜き出すと、こうなります。表にすると、置換で済むものとそうでないものの差がはっきりします。
| 旧い綴り | 置き換え先 | 箱 |
|---|---|---|
inferenceGatewayHeaders | inferenceCustomHeaders | A |
trustBootstrapLocalExec | trustBootstrapDelivery | A |
enduserAttribution | endUserAttribution | A |
isDxtEnabled | isDesktopExtensionEnabled | A |
isDxtSignatureRequired | isDesktopExtensionSignatureRequired | A |
inferenceGatewayAuthScheme: "sso" | inferenceCredentialKind: "interactive" | A |
inferenceGatewayAuthScheme: "auto" | キーを削除(bearer が既定) | A |
ask-session(ツール権限の値) | ask | A |
managedMcpServers[].scopes | scope(空白区切りの一つの文字列) | A |
transport: "builtin" | 削除(組み込みのエントリに transport は不要) | A |
authorityHost | azureCloud: "us-gov-high"(GCC High テナント) | A |
orgPluginSettings の record 形式 | array 形式 | B |
inferenceCredentialKind: "oauth"(Vertex) | "interactive" | B |
ヘッダを文字列やリストで書いている箇所——inferenceCustomHeaders、otlpHeaders、otlpResourceAttributes、bootstrapHeaders——も JSON オブジェクトに直す必要があります。私の手元では otlpHeaders を一行の文字列で書いていて、これが一番地味に見落としやすい形でした。
受付が終わった後は、無視されるのではなく閉じる側へ倒れます
ここが、私が最初に見積もりを誤ったところです。締切を過ぎた旧い綴りは「読まれずに無視される」のだろうと思っていました。実際は違います。改名されたキーの旧い名前は fail-closed の値か既定値へ落ち、不正な managedMcpServers や orgPluginSettings のエントリは、書き直すまでそのコネクタとツールポリシーが使えなくなります。
さらに、読み取れない管理構成値の扱いそのものが変わりました。以前は無視されていた値が、いまはそれが属する制限を発動させます。disabledBuiltinTools、builtinToolPolicy、coworkTabEnabled、disableBundledSkills は制限側の値へ落ち、読み取れない managedMcpServers は Code セッションを管理対象の MCP サーバーだけに制限し、認識できないツール権限値は最も制限の強い設定——組み込みツールなら ask、プラグイン配信のツールなら blocked——として適用されたうえで構成エラーとして報告されます。
壊れ方が「動かなくなる」ではなく「使えるはずのものが消える」形で出る、と言い換えられます。原因が設定ファイルにあると気づくまでに時間がかかる壊れ方です。
警告は消せますが、最後の再通知だけは消せません
非推奨の通知は 2026 年 9 月 10 日から出ており、受付終了の 24 時間前にもう一度表示されます。disableConfigDeprecationWarnings を置けば最初の表示は隠せますが、最後の 24 時間の再通知は隠せません。Details ダイアログには各フィールドと置き換え先と受付終了日が並び、Copy report ボタンで管理者向けの要約がクリップボードに入ります。私はこの要約を、そのまま仕分けの下敷きにしました。
Setup ウィンドウ側にも、受付終了が予定されている設定の下に注意書きが出るようになっています。通知を消して忘れるより、Copy report を一度押して手元に残しておくほうが、後から数えるときに楽でした。
もう一件、日付の違う期限があります。未文書化のクライアント証明書のフォールバック設定は、1.49585.0 以降のリリースがすでに読み込みません。2026 年 11 月 3 日からアプリ内に非推奨の警告が出始め、11 月 17 日に受付終了となります。こちらは警告開始日と受付終了日が別の日ですので、カレンダーには二つ入れておきました。
今日できるのは、一つ数えるところまでです
私が置いた順番は、数える、A だけ直す、配布版を確認する、B を直す、C の日付をカレンダーに入れる、の五つでした。実際に手が動いたのは最初の二つだけで、残りは 9 月末に回しています。Vertex を使っていなければ B と C は空になりますので、多くの環境では最初の二つで終わるはずです。
まずは手元の管理構成 JSON を一つ開いて、A の欄に何件出るかを数えるところから始めていただければと思います。ゼロであれば、この期限については何もしなくて済みます。
Vertex 経由で運用されている方は、クライアント ID とオーディエンスの組み合わせを先に見直しておくと、10 月 7 日を無風で通過できます。基盤側の構成についてはVertex AI × Claude エンタープライズ統合:プロンプトキャッシング・マルチモーダル・エージェント設計までにも書き残しておりますので、あわせてご覧ください。
期限のある変更は、どうしても「間に合わせる」ことばかりに目が向きます。間に合わせる前に、触ってよい時期かどうかを一度確かめる——この一手間だけは、これからも省かないでおこうと思っています。お読みいただきありがとうございました。