diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,113 @@
 
 ## [Unreleased]
 
+## [baikai 0.10.0.0] - 2026-10-25
+
+### Added
+
+- `ThinkingNone` (`none`) explicitly requests reasoning off; `Nothing` still
+  leaves provider defaults untouched. Anthropic compatibility records declare
+  `supportsThinkingDisabled`; legacy records conservatively default to False.
+- Endpoint-specific `NativeCachePolicy` records distinguish modern, legacy and
+  unsupported native OpenAI cache controls. Policies survive legacy JSON and
+  catalog refresh; Luna Responses Long has verified 12h base and tier rates.
+- Evidence schema 2.8 includes the `none` preference and content-free native
+  cache controls and input structure. Digest rules and the separation of
+  requested, translated and observed reasoning are unchanged.
+
+### Changed (breaking)
+
+- `ThinkingLevel` gains `ThinkingNone` as its least constructor. Update exhaustive
+  matches. Anthropic and OpenAI compatibility records gain fields; use the
+  default records or update explicit record construction.
+- All seven dependent packages now require `baikai ^>=0.10.0` and release
+  independently below. The unchanged adapters take dependency-only patch bumps.
+
+## [baikai-claude 0.7.3.0] - 2026-10-25
+
+### Added
+
+- Export `injectSystemCacheControl` for shared system-prefix cache markers.
+- `ThinkingNone` sends catalog-gated `thinking: {"type": "disabled"}` without
+  effort, display or a budget. Unsupported off requests remain visible
+  adjustments and fail strict evidence before dispatch. A host with no thinking
+  controls is not assumed to be a non-reasoning model.
+
+### Fixed
+
+- Short and long `cacheRetention` mark non-empty system prompts so fresh
+  conversations with different first questions can reuse the tools-and-system
+  prefix. System, last-tool and automatic markers share the effective TTL,
+  including host downgrades, and use at most three breakpoints. Empty or absent
+  system prompts and disabled caching keep their existing shape. Regression
+  coverage includes tool compatibility and an isolated live shared-prefix case.
+  Implements issue #2 and the approach in PR #3.
+
+### Changed
+
+- Require `baikai ^>=0.10.0`.
+
+## [baikai-openai 0.7.3.0] - 2026-10-25
+
+### Added
+
+- Export `applyNativeCache` for validated native cache plans.
+- OpenAI-compatible Chat (including Ollama) and Responses carry `none` where
+  supported. Z.ai and Qwen emit `enable_thinking: false`; unsupported off
+  requests remain visible adjustments and fail strict evidence before dispatch.
+
+### Fixed
+
+- Native OpenAI Short caching marks shared non-empty system prefixes on
+  catalog-supported Responses and Chat bindings. Unsupported native requests
+  fail locally. Effective duration reaches terminal pricing, partial usage
+  and evidence.
+- Funded live prefix checks pass for Luna Responses Short/Long and GPT-5.6 Chat
+  Short. Luna Long uses verified 12h base and tier rates; unsupported Chat Long
+  and unverified modern bindings remain locally refused.
+
+### Changed
+
+- Require `baikai ^>=0.10.0`. Catalog effort policies distinguish GPT-5/o-series
+  models that cannot disable reasoning, Sol/Luna that accept none, and
+  Astra/GPT-6.1 Sol that do not.
+
+## [baikai-typesafe 0.1.0.1] - 2026-10-25
+
+### Changed
+
+- Require `baikai ^>=0.10.0`. Dependency-only update; no package API change.
+
+## [baikai-trace-otel 0.4.1.1] - 2026-10-25
+
+### Changed
+
+- Require `baikai ^>=0.10.0`. Dependency-only update; no package API change.
+
+## [baikai-effectful 0.4.0.5] - 2026-10-25
+
+### Changed
+
+- Require `baikai ^>=0.10.0`. Dependency-only update; no package API change.
+
+## [baikai-kit 0.4.0.3] - 2026-10-25
+
+### Changed
+
+- Require `baikai ^>=0.10.0`. Dependency-only update; no package API change.
+
+## [baikai-agent 0.2.0.4] - 2026-10-25
+
+### Fixed
+
+- Layered job configuration accepts `thinking "none"` through the shared
+  canonical parser, keeping explicit off distinct from an absent preference.
+
+### Changed
+
+- Require `baikai ^>=0.10.0`, `baikai-claude ^>=0.7.3` and
+  `baikai-openai ^>=0.7.3` for explicit-off handling in both vendor renderers.
+
 ## [baikai 0.9.0.0] - 2026-10-25
 
 ### Added
diff --git a/baikai.cabal b/baikai.cabal
--- a/baikai.cabal
+++ b/baikai.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.4
 name: baikai
-version: 0.9.0.0
+version: 0.10.0.0
 synopsis: Unified Haskell interface for multiple AI providers
 description:
   baikai provides a unified, provider-agnostic Haskell interface for working
diff --git a/data/models/anthropic.json b/data/models/anthropic.json
--- a/data/models/anthropic.json
+++ b/data/models/anthropic.json
@@ -22,7 +22,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": false
       },
       "enabled": true
     },
@@ -45,7 +46,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": false
+        "supportsForcedToolChoice": false,
+        "supportsThinkingDisabled": false
       },
       "enabled": true
     },
@@ -67,7 +69,8 @@
         "thinkingStyle": "budget",
         "supportsSamplingParameters": true,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -90,7 +93,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -112,7 +116,8 @@
         "thinkingStyle": "budget",
         "supportsSamplingParameters": true,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -134,7 +139,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": true,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -156,7 +162,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -180,7 +187,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": true,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -204,7 +212,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": true,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -228,7 +237,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": true,
-        "supportsForcedToolChoice": false
+        "supportsForcedToolChoice": false,
+        "supportsThinkingDisabled": false
       },
       "enabled": true
     },
@@ -250,7 +260,8 @@
         "thinkingStyle": "budget",
         "supportsSamplingParameters": true,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -272,7 +283,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": true,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -294,7 +306,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": true
+        "supportsForcedToolChoice": true,
+        "supportsThinkingDisabled": true
       },
       "enabled": true
     },
@@ -317,7 +330,8 @@
         "thinkingStyle": "adaptive",
         "supportsSamplingParameters": false,
         "supportsFastMode": false,
-        "supportsForcedToolChoice": false
+        "supportsForcedToolChoice": false,
+        "supportsThinkingDisabled": false
       },
       "enabled": true
     }
diff --git a/data/models/openai.json b/data/models/openai.json
--- a/data/models/openai.json
+++ b/data/models/openai.json
@@ -17,7 +17,11 @@
       },
       "contextWindow": 1047576,
       "maxOutputTokens": 32768,
-      "enabled": true
+      "enabled": true,
+      "compat": {
+        "kind": "openai-completions",
+        "nativeCachePolicy": {"tag": "NativeCacheLegacy", "contents": [true, true]}
+      }
     },
     {
       "id": "gpt-4.1-mini",
@@ -92,6 +96,10 @@
       },
       "contextWindow": 400000,
       "maxOutputTokens": 128000,
+      "compat": {
+        "kind": "openai-completions",
+        "supportedReasoningEfforts": ["minimal", "low", "medium", "high"]
+      },
       "enabled": true
     },
     {
@@ -107,6 +115,10 @@
       },
       "contextWindow": 400000,
       "maxOutputTokens": 128000,
+      "compat": {
+        "kind": "openai-completions",
+        "supportedReasoningEfforts": ["minimal", "low", "medium", "high"]
+      },
       "enabled": true
     },
     {
@@ -122,6 +134,10 @@
       },
       "contextWindow": 400000,
       "maxOutputTokens": 128000,
+      "compat": {
+        "kind": "openai-completions",
+        "supportedReasoningEfforts": ["minimal", "low", "medium", "high"]
+      },
       "enabled": true
     },
     {
@@ -212,7 +228,11 @@
       },
       "contextWindow": 1050000,
       "maxOutputTokens": 128000,
-      "enabled": true
+      "enabled": true,
+      "compat": {
+        "kind": "openai-completions",
+        "nativeCachePolicy": {"tag": "NativeCacheLegacy", "contents": [false, true]}
+      }
     },
     {
       "id": "gpt-5.6",
@@ -227,7 +247,11 @@
       },
       "contextWindow": 1050000,
       "maxOutputTokens": 128000,
-      "enabled": true
+      "enabled": true,
+      "compat": {
+        "kind": "openai-completions",
+        "nativeCachePolicy": {"tag": "NativeCacheModern", "contents": [false, true]}
+      }
     },
     {
       "id": "gpt-5.6-luna",
@@ -290,6 +314,7 @@
       "api": "openai-responses",
       "pricingPolicy": {"inputTiers": [{"inputAbove": 272000, "rates": {"input": 20.0, "output": 75.0, "cacheRead": 2.0, "cacheWrite": 25.0}}]},
       "compat": {
+        "nativeCachePolicy": {"tag": "NativeCacheModern", "contents": [false, true]},
         "kind": "openai-responses",
         "supportsSamplingParameters": false,
         "supportsLongCacheRetention": false,
@@ -312,13 +337,14 @@
       "contextWindow": 1050000,
       "maxOutputTokens": 128000,
       "api": "openai-responses",
-      "pricingPolicy": {"inputTiers": [{"inputAbove": 272000, "rates": {"input": 0.2, "output": 0.75, "cacheRead": 0.02, "cacheWrite": 0.25}}]},
+      "pricingPolicy": {"inputTiers": [{"inputAbove": 272000, "rates": {"input": 0.2, "output": 0.75, "cacheRead": 0.02, "cacheWrite": 0.25}, "longCacheWriteCost": 0.5}], "longCacheWriteCost": 0.25},
       "compat": {
+        "nativeCachePolicy": {"tag": "NativeCacheModern", "contents": [true, true]},
         "kind": "openai-responses",
         "supportsSamplingParameters": false,
-        "supportsLongCacheRetention": false,
+        "supportsLongCacheRetention": true,
         "supportsPromptCacheOptions": true,
-        "supportedReasoningEfforts": ["low", "medium", "high", "xhigh", "max"]
+        "supportedReasoningEfforts": ["none", "low", "medium", "high", "xhigh", "max"]
       },
       "enabled": true
     },
@@ -338,11 +364,12 @@
       "api": "openai-responses",
       "pricingPolicy": {"inputTiers": [{"inputAbove": 272000, "rates": {"input": 4.0, "output": 15.0, "cacheRead": 0.4, "cacheWrite": 5.0}}]},
       "compat": {
+        "nativeCachePolicy": {"tag": "NativeCacheModern", "contents": [false, true]},
         "kind": "openai-responses",
         "supportsSamplingParameters": false,
         "supportsLongCacheRetention": false,
         "supportsPromptCacheOptions": true,
-        "supportedReasoningEfforts": ["low", "medium", "high", "xhigh", "max"]
+        "supportedReasoningEfforts": ["none", "low", "medium", "high", "xhigh", "max"]
       },
       "enabled": true
     },
@@ -362,6 +389,7 @@
       "api": "openai-responses",
       "pricingPolicy": {"inputTiers": [{"inputAbove": 272000, "rates": {"input": 4.0, "output": 15.0, "cacheRead": 0.2, "cacheWrite": 5.0}}]},
       "compat": {
+        "nativeCachePolicy": {"tag": "NativeCacheModern", "contents": [false, true]},
         "kind": "openai-responses",
         "supportsSamplingParameters": false,
         "supportsLongCacheRetention": false,
@@ -383,6 +411,10 @@
       },
       "contextWindow": 200000,
       "maxOutputTokens": 100000,
+      "compat": {
+        "kind": "openai-completions",
+        "supportedReasoningEfforts": ["low", "medium", "high"]
+      },
       "enabled": true
     },
     {
@@ -398,6 +430,10 @@
       },
       "contextWindow": 200000,
       "maxOutputTokens": 100000,
+      "compat": {
+        "kind": "openai-completions",
+        "supportedReasoningEfforts": ["low", "medium", "high"]
+      },
       "enabled": true
     },
     {
@@ -413,6 +449,10 @@
       },
       "contextWindow": 200000,
       "maxOutputTokens": 100000,
+      "compat": {
+        "kind": "openai-completions",
+        "supportedReasoningEfforts": ["low", "medium", "high"]
+      },
       "enabled": true
     },
     {
@@ -428,6 +468,10 @@
       },
       "contextWindow": 200000,
       "maxOutputTokens": 100000,
+      "compat": {
+        "kind": "openai-completions",
+        "supportedReasoningEfforts": ["low", "medium", "high"]
+      },
       "enabled": true
     }
   ]
diff --git a/fetch/FetchModelsCore.hs b/fetch/FetchModelsCore.hs
--- a/fetch/FetchModelsCore.hs
+++ b/fetch/FetchModelsCore.hs
@@ -65,7 +65,7 @@
   )
 where
 
-import Baikai.Compat (AnthropicThinkingStyle (..), OpenAICompletionsCompat (..), OpenAIResponsesCompat (..), defaultOpenAIResponsesCompat)
+import Baikai.Compat (AnthropicThinkingStyle (..), NativeCachePolicy (..), OpenAICompletionsCompat (..), OpenAIResponsesCompat (..), defaultOpenAICompletionsCompat, defaultOpenAIResponsesCompat)
 import Baikai.Model (InputModality (..))
 import Baikai.Model qualified as Model
 import Baikai.Prelude
@@ -204,6 +204,8 @@
   { thinkingStyle :: !AnthropicThinkingStyle,
     supportsSamplingParameters :: !Bool,
     supportsForcedToolChoice :: !Bool,
+    -- | Whether the generation accepts @thinking: {"type": "disabled"}@.
+    supportsThinkingDisabled :: !Bool,
     fastModeCost :: !(Maybe CatalogCost)
   }
   deriving stock (Eq, Show, Generic)
@@ -267,10 +269,20 @@
 openaiInclude =
   Map.union
     ( Map.fromList
-        [ ("gpt-6-astra", Just (CatalogResponsesCompat astraResponsesFacts)),
+        [ ("gpt-5.6", Just (CatalogOpenAICompat (defaultOpenAICompletionsCompat & #nativeCachePolicy .~ Just (NativeCacheModern False True)))),
+          ("gpt-5.5", Just (CatalogOpenAICompat (defaultOpenAICompletionsCompat & #nativeCachePolicy .~ Just (NativeCacheLegacy False True)))),
+          ("gpt-4.1", Just (CatalogOpenAICompat (defaultOpenAICompletionsCompat & #nativeCachePolicy .~ Just (NativeCacheLegacy True True)))),
+          ("gpt-5", Just (CatalogOpenAICompat gpt5Facts)),
+          ("gpt-5-mini", Just (CatalogOpenAICompat gpt5Facts)),
+          ("gpt-5-nano", Just (CatalogOpenAICompat gpt5Facts)),
+          ("o1", Just (CatalogOpenAICompat oSeriesFacts)),
+          ("o3", Just (CatalogOpenAICompat oSeriesFacts)),
+          ("o3-mini", Just (CatalogOpenAICompat oSeriesFacts)),
+          ("o4-mini", Just (CatalogOpenAICompat oSeriesFacts)),
+          ("gpt-6-astra", Just (CatalogResponsesCompat astraResponsesFacts)),
           ("gpt-6.1-sol", Just (CatalogResponsesCompat gpt61ResponsesFacts)),
           ("gpt-6-sol", Just (CatalogResponsesCompat gpt6ResponsesFacts)),
-          ("gpt-6-luna", Just (CatalogResponsesCompat gpt6ResponsesFacts))
+          ("gpt-6-luna", Just (CatalogResponsesCompat lunaResponsesFacts))
         ]
     )
     $ Map.fromList
@@ -301,11 +313,25 @@
           ]
       ]
   where
+    -- 2026-10-25: Endpoint cache facts from the caching guide and Chat/Responses
+    -- references: https://developers.openai.com/api/docs/guides/prompt-caching
+    -- Short and breakpoint support passed live pairs on Luna Responses and
+    -- GPT-5.6 Chat. A funded Luna Responses 12h probe completed and reported
+    -- ttl_12h_tokens; GPT-5.6 Chat rejected 12h with HTTP 400 (30m only).
+    -- Enable Long only on the probed Luna endpoint, with its published rates.
+    -- https://developers.openai.com/api/docs/pricing
+    lunaResponsesFacts = gpt6ResponsesFacts & #nativeCachePolicy .~ Just (NativeCacheModern True True) & #supportsLongCacheRetention .~ True
     -- 2026-09-23: Sol and Luna require Responses for function calling at
     -- their default reasoning effort; Chat permits it only at effort none.
     -- https://developers.openai.com/api/docs/models/gpt-6-sol
     -- https://developers.openai.com/api/docs/models/gpt-6-luna
-    gpt6ResponsesFacts = astraResponsesFacts
+    gpt6ResponsesFacts = astraResponsesFacts & #supportedReasoningEfforts .~ Just [ThinkingNone, ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax]
+    -- 2026-10-25: GPT-5 accepts minimal through high, o-series low through
+    -- high. Neither accepts none; keep this fact through catalog refreshes.
+    -- https://developers.openai.com/api/docs/models/gpt-5
+    -- https://developers.openai.com/api/docs/guides/reasoning
+    gpt5Facts = defaultOpenAICompletionsCompat & #supportedReasoningEfforts .~ Just [ThinkingMinimal, ThinkingLow, ThinkingMedium, ThinkingHigh]
+    oSeriesFacts = defaultOpenAICompletionsCompat & #supportedReasoningEfforts .~ Just [ThinkingLow, ThinkingMedium, ThinkingHigh]
     -- 2026-09-29: as Astra, tool calling requires Responses; efforts low
     -- through max (no none or minimal); sampling removed; 30m cache TTL.
     -- https://developers.openai.com/api/docs/models/gpt-6.1-sol
@@ -315,7 +341,8 @@
     -- https://developers.openai.com/api/docs/guides/latest-model
     astraResponsesFacts =
       defaultOpenAIResponsesCompat
-        { supportsPromptCacheOptions = True,
+        { nativeCachePolicy = Just (NativeCacheModern False True),
+          supportsPromptCacheOptions = True,
           supportsLongCacheRetention = False,
           supportsSamplingParameters = False,
           supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax]
@@ -372,11 +399,11 @@
       -- and sent it budget_tokens — same source.
       ("claude-sonnet-5", adaptiveNoSampling),
       -- 2026-09-29: adaptive thinking on by default; forced tool choice and
-      -- nondefault sampling return 400; no fast mode. Baikai never sends
-      -- the rejected "disabled" thinking type.
+      -- nondefault sampling return 400; no fast mode. The "disabled" thinking
+      -- type returns 400 too; its lowest setting is "between_tools".
       -- https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5
       -- https://platform.claude.com/docs/en/build-with-claude/fast-mode
-      ("claude-sonnet-5-5", adaptiveNoSampling & #supportsForcedToolChoice .~ False),
+      ("claude-sonnet-5-5", adaptiveNoSampling & #supportsForcedToolChoice .~ False & #supportsThinkingDisabled .~ False),
       -- 2026-08-27: as claude-opus-4-6 — budget deprecated but functional,
       -- sampling accepted; baikai prefers the non-deprecated shape — same
       -- source. Plan 40 left this membership to a live check that never
@@ -395,23 +422,27 @@
       -- https://platform.claude.com/docs/en/build-with-claude/effort
       ("claude-haiku-5-5", adaptiveNoSampling),
       -- 2026-08-27: adaptive-only, sampling parameters rejected — same source.
-      ("claude-fable-5", adaptiveNoSampling),
+      ("claude-fable-5", adaptiveNoSampling & #supportsThinkingDisabled .~ False),
       -- 2026-09-07: always-on adaptive thinking; omit sampling parameters.
       -- https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1
-      ("claude-fable-5-1", adaptiveNoSampling & #supportsForcedToolChoice .~ False)
+      ("claude-fable-5-1", adaptiveNoSampling & #supportsForcedToolChoice .~ False & #supportsThinkingDisabled .~ False)
     ]
   where
-    opus55Facts = adaptiveNoSampling & #supportsForcedToolChoice .~ False & #fastModeCost ?~ CatalogCost 8 40 0.4 10
+    opus55Facts = adaptiveNoSampling & #supportsForcedToolChoice .~ False & #supportsThinkingDisabled .~ False & #fastModeCost ?~ CatalogCost 8 40 0.4 10
     -- 2026-09-23: Fable 5.1 and Opus 5.5 reject forced choice; older curated
     -- models accept it subject to their separate manual-thinking constraint.
     -- https://platform.claude.com/docs/en/api/errors
     -- https://platform.claude.com/docs/en/models/fable-5-1/migration-guide
+    -- 2026-10-19: Opus 5.5, Sonnet 5.5, Fable 5 and Fable 5.1 reject
+    -- thinking {"type": "disabled"} with a 400; every other curated model
+    -- accepts it (Haiku 5.5 and Opus 5 only at effort high or below).
+    -- https://platform.claude.com/docs/en/build-with-claude/thinking-troubleshooting
     -- 2026-09-07: Opus 5 and 4.8 only; cache multipliers stack on fast rates.
     -- https://platform.claude.com/docs/en/build-with-claude/fast-mode
     fastAdaptive = adaptiveNoSampling & #fastModeCost ?~ CatalogCost 10 50 1 12.5
-    adaptiveNoSampling = AnthropicGenerationFacts AnthropicThinkingAdaptive False True Nothing
-    adaptiveWithSampling = AnthropicGenerationFacts AnthropicThinkingAdaptive True True Nothing
-    budgetWithSampling = AnthropicGenerationFacts AnthropicThinkingBudget True True Nothing
+    adaptiveNoSampling = AnthropicGenerationFacts AnthropicThinkingAdaptive False True True Nothing
+    adaptiveWithSampling = AnthropicGenerationFacts AnthropicThinkingAdaptive True True True Nothing
+    budgetWithSampling = AnthropicGenerationFacts AnthropicThinkingBudget True True True Nothing
 
 -- | OpenAI curation with a Chat default and explicit Responses overrides.
 openaiSpec :: ProviderSpec
@@ -695,7 +726,10 @@
       (("anthropic", "claude-sonnet-5-5"), Model.PricingPolicy [] (Just 4)),
       (("openai", "gpt-6.1-sol"), Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 4 15 0.2 5) Nothing] Nothing),
       (("openai", "gpt-6-sol"), Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 4 15 0.4 5) Nothing] Nothing),
-      (("openai", "gpt-6-luna"), Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 0.2 0.75 0.02 0.25) Nothing] Nothing),
+      -- 2026-10-25: Luna Responses accepts 12h. The standard pricing table
+      -- publishes 0.25/M below/at 272K and 0.50/M above, matching the
+      -- guide's total 2.5x uncached-input rate (not an added surcharge).
+      (("openai", "gpt-6-luna"), Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 0.2 0.75 0.02 0.25) (Just 0.5)] (Just 0.25)),
       (("anthropic", "claude-fable-5-1"), Model.PricingPolicy [] (Just 20)),
       (("anthropic", "claude-haiku-5-5"), Model.PricingPolicy [Model.InputPriceTier 100000 (Model.ModelCost 0.5 2.5 0.05 0.625) (Just 1)] (Just 0.2))
     ]
@@ -725,7 +759,8 @@
       <> jsonBool (facts ^. #supportsSamplingParameters)
       <> ",",
     "        \"supportsFastMode\": " <> jsonBool (maybe False (const True) (facts ^. #fastModeCost)) <> ",",
-    "        \"supportsForcedToolChoice\": " <> jsonBool (facts ^. #supportsForcedToolChoice),
+    "        \"supportsForcedToolChoice\": " <> jsonBool (facts ^. #supportsForcedToolChoice) <> ",",
+    "        \"supportsThinkingDisabled\": " <> jsonBool (facts ^. #supportsThinkingDisabled),
     "      },"
   ]
 renderModelCompat (Just (CatalogOpenAICompat facts)) =
@@ -733,6 +768,7 @@
     "        \"kind\": \"openai-completions\",",
     "        \"supportsToolCalls\": " <> jsonBool (facts ^. #supportsToolCalls) <> ",",
     "        \"supportsSamplingParameters\": " <> jsonBool (facts ^. #supportsSamplingParameters) <> ",",
+    "        \"nativeCachePolicy\": " <> maybe "null" (decodeUtf8 . LBS.toStrict . encode) (facts ^. #nativeCachePolicy) <> ",",
     "        \"supportedReasoningEfforts\": " <> maybe "null" (\xs -> "[" <> Text.intercalate ", " (map (jsonString . renderThinkingLevel) xs) <> "]") (facts ^. #supportedReasoningEfforts),
     "      },"
   ]
@@ -742,6 +778,7 @@
     "        \"supportsSamplingParameters\": " <> jsonBool (facts ^. #supportsSamplingParameters) <> ",",
     "        \"supportsLongCacheRetention\": " <> jsonBool (facts ^. #supportsLongCacheRetention) <> ",",
     "        \"supportsPromptCacheOptions\": " <> jsonBool (facts ^. #supportsPromptCacheOptions) <> ",",
+    "        \"nativeCachePolicy\": " <> maybe "null" (decodeUtf8 . LBS.toStrict . encode) (facts ^. #nativeCachePolicy) <> ",",
     "        \"supportedReasoningEfforts\": " <> maybe "null" (\xs -> "[" <> Text.intercalate ", " (map (jsonString . renderThinkingLevel) xs) <> "]") (facts ^. #supportedReasoningEfforts),
     "      },"
   ]
diff --git a/gen/GenModels.hs b/gen/GenModels.hs
--- a/gen/GenModels.hs
+++ b/gen/GenModels.hs
@@ -36,6 +36,7 @@
 import GenModelsCore
   ( checkAnthropicCompat,
     checkIdentifierCollisions,
+    checkNativeCacheCompat,
     flattenEntries,
     renderModule,
   )
@@ -60,6 +61,9 @@
     Left err -> die (Text.unpack err)
     Right () -> pure ()
   case checkAnthropicCompat allEntries of
+    Left err -> die (Text.unpack err)
+    Right () -> pure ()
+  case checkNativeCacheCompat allEntries of
     Left err -> die (Text.unpack err)
     Right () -> pure ()
   let sorted = sortOn fst allEntries
diff --git a/gen/GenModelsCore.hs b/gen/GenModelsCore.hs
--- a/gen/GenModelsCore.hs
+++ b/gen/GenModelsCore.hs
@@ -15,6 +15,7 @@
     flattenEntries,
     checkIdentifierCollisions,
     checkAnthropicCompat,
+    checkNativeCacheCompat,
     parseAnthropicThinkingStyle,
     sanitizeIdentifier,
     renderModule,
@@ -30,14 +31,17 @@
         supportsForcedToolChoice,
         supportsLongCacheRetention,
         supportsSamplingParameters,
+        supportsThinkingDisabled,
         thinkingStyle
       ),
     AnthropicThinkingStyle (..),
     CacheControlFormat (..),
     MaxTokensField (..),
+    NativeCachePolicy (..),
     OpenAICompletionsCompat
       ( cacheControlFormat,
         maxTokensField,
+        nativeCachePolicy,
         requiresThinkingAsText,
         supportedReasoningEfforts,
         supportsLongCacheRetention,
@@ -52,6 +56,7 @@
     defaultAnthropicMessagesCompat,
     defaultOpenAICompletionsCompat,
     defaultOpenAIResponsesCompat,
+    validateNativeCachePolicy,
   )
 import Baikai.Model (InputModality (..))
 import Baikai.Model qualified as Model
@@ -123,8 +128,9 @@
     _ -> pure ()
   sampling <- o .:? "supportsSamplingParameters" .!= d.supportsSamplingParameters
   long <- o .:? "supportsLongCacheRetention" .!= d.supportsLongCacheRetention
+  native <- o .:? "nativeCachePolicy"
   modern <- o .:? "supportsPromptCacheOptions" .!= d.supportsPromptCacheOptions
-  pure d {supportedReasoningEfforts = efforts, supportsSamplingParameters = sampling, supportsLongCacheRetention = long, supportsPromptCacheOptions = modern}
+  pure d {nativeCachePolicy = native, supportedReasoningEfforts = efforts, supportsSamplingParameters = sampling, supportsLongCacheRetention = long, supportsPromptCacheOptions = modern}
 
 parseOpenAICompat :: Aeson.Object -> Parser OpenAICompletionsCompat
 parseOpenAICompat o = do
@@ -133,6 +139,7 @@
   sst <- o .:? "supportsStrictMode" .!= supportsStrictMode d
   rtat <- o .:? "requiresThinkingAsText" .!= requiresThinkingAsText d
   tf <- optionalField o "thinkingFormat" parseThinkingFormat (thinkingFormat d)
+  native <- o .:? "nativeCachePolicy"
   ccf <- optionalMaybeField o "cacheControlFormat" parseCacheControlFormat (cacheControlFormat d)
   sus <- o .:? "supportsUsageInStreaming" .!= d.supportsUsageInStreaming
   slcr <- o .:? "supportsLongCacheRetention" .!= d.supportsLongCacheRetention
@@ -145,7 +152,8 @@
     _ -> pure ()
   pure
     d
-      { supportsToolCalls = stc,
+      { nativeCachePolicy = native,
+        supportsToolCalls = stc,
         supportsSamplingParameters = ssp,
         supportedReasoningEfforts = efforts,
         maxTokensField = mtf,
@@ -167,6 +175,7 @@
   ssp <- o .:? "supportsSamplingParameters" .!= d.supportsSamplingParameters
   fast <- o .:? "supportsFastMode" .!= False
   forced <- o .:? "supportsForcedToolChoice" .!= d.supportsForcedToolChoice
+  disabled <- o .:? "supportsThinkingDisabled" .!= d.supportsThinkingDisabled
   pure
     d
       { supportsLongCacheRetention = slcr,
@@ -175,7 +184,8 @@
         thinkingStyle = ts,
         supportsSamplingParameters = ssp,
         supportsFastMode = fast,
-        supportsForcedToolChoice = forced
+        supportsForcedToolChoice = forced,
+        supportsThinkingDisabled = disabled
       }
 
 -- | The catalog dialect spells the extended-thinking wire shape as a
@@ -424,6 +434,26 @@
         <> ",\"thinkingStyle\":\"budget\"|\"adaptive\""
         <> ",\"supportsSamplingParameters\":true|false}"
 
+-- | Validate native endpoint facts and modern Long pricing together.
+checkNativeCacheCompat :: [(Text, GeneratedEntry)] -> Either Text ()
+checkNativeCacheCompat entries = mapM_ checkNative (map snd entries)
+  where
+    checkNative e = do
+      let (format, policy) = case e.compat of
+            CatalogCompatOpenAI c -> (c.cacheControlFormat, c.nativeCachePolicy)
+            CatalogCompatResponses c -> (Nothing, c.nativeCachePolicy)
+            _ -> (Nothing, Nothing)
+          named = either (Left . ((e.modelId <> ": ") <>)) Right
+      named (validateNativeCachePolicy format policy)
+      case policy of
+        Just (NativeCacheModern True _) -> named $ case e.pricingPolicy of
+          Just p
+            | Just _ <- p.longCacheWriteCost,
+              all (\t -> t.longCacheWriteCost /= Nothing) (Model.inputTiers p) ->
+                Right ()
+          _ -> Left "modern Long requires base and every tier long cache-write rates"
+        _ -> Right ()
+
 -- | Replace any non-identifier character with @_@. Haskell allows
 -- letters, digits, underscore, and apostrophe; everything else
 -- (slash, dash, dot, colon, ...) becomes an underscore.
@@ -474,13 +504,16 @@
         "        supportsForcedToolChoice,",
         "        supportsLongCacheRetention,",
         "        supportsSamplingParameters,",
+        "        supportsThinkingDisabled,",
         "        thinkingStyle",
         "      ),",
         "    AnthropicThinkingStyle (..),",
         "    CacheControlFormat (..),",
+        "    NativeCachePolicy (..),",
         "    MaxTokensField (..),",
         "    OpenAICompletionsCompat",
-        "      ( cacheControlFormat,",
+        "      ( nativeCachePolicy,",
+        "        cacheControlFormat,",
         "        maxTokensField,",
         "        requiresThinkingAsText,",
         "        supportedReasoningEfforts,",
@@ -648,7 +681,8 @@
       "              supportsSamplingParameters = " <> renderBool c.supportsSamplingParameters <> ",",
       "              supportedReasoningEfforts = " <> maybe "Nothing" (\xs -> "Just [" <> Text.intercalate ", " (map (Text.pack . show) xs) <> "]") c.supportedReasoningEfforts <> ",",
       "              supportsUsageInStreaming = " <> renderBool c.supportsUsageInStreaming <> ",",
-      "              supportsLongCacheRetention = " <> renderBool c.supportsLongCacheRetention,
+      "              supportsLongCacheRetention = " <> renderBool c.supportsLongCacheRetention <> ",",
+      "              nativeCachePolicy = " <> renderNativeCache c.nativeCachePolicy,
       "            }"
     ]
   CatalogCompatResponses c ->
@@ -658,7 +692,8 @@
       "            { supportedReasoningEfforts = " <> maybe "Nothing" (\xs -> "Just [" <> Text.intercalate ", " (map (Text.pack . show) xs) <> "]") c.supportedReasoningEfforts <> ",",
       "              supportsSamplingParameters = " <> renderBool c.supportsSamplingParameters <> ",",
       "              supportsLongCacheRetention = " <> renderBool c.supportsLongCacheRetention <> ",",
-      "              supportsPromptCacheOptions = " <> renderBool c.supportsPromptCacheOptions,
+      "              supportsPromptCacheOptions = " <> renderBool c.supportsPromptCacheOptions <> ",",
+      "              nativeCachePolicy = " <> renderNativeCache c.nativeCachePolicy,
       "            }"
     ]
   CatalogCompatAnthropic c ->
@@ -671,7 +706,8 @@
       "              thinkingStyle = " <> renderAnthropicThinkingStyle c.thinkingStyle <> ",",
       "              supportsSamplingParameters = " <> renderBool c.supportsSamplingParameters <> ",",
       "              supportsFastMode = " <> renderBool c.supportsFastMode <> ",",
-      "              supportsForcedToolChoice = " <> renderBool c.supportsForcedToolChoice,
+      "              supportsForcedToolChoice = " <> renderBool c.supportsForcedToolChoice <> ",",
+      "              supportsThinkingDisabled = " <> renderBool c.supportsThinkingDisabled,
       "            }"
     ]
 
@@ -715,3 +751,7 @@
       "              }",
       "          ),"
     ]
+
+renderNativeCache :: Maybe NativeCachePolicy -> Text
+renderNativeCache Nothing = "Nothing"
+renderNativeCache (Just p) = "Just (" <> Text.pack (show p) <> ")"
diff --git a/src/Baikai/Compat.hs b/src/Baikai/Compat.hs
--- a/src/Baikai/Compat.hs
+++ b/src/Baikai/Compat.hs
@@ -33,6 +33,7 @@
         requiresThinkingAsText,
         thinkingFormat,
         cacheControlFormat,
+        nativeCachePolicy,
         supportsToolCalls,
         supportsSamplingParameters,
         supportedReasoningEfforts,
@@ -43,9 +44,11 @@
     MaxTokensField (..),
     ThinkingFormat (..),
     CacheControlFormat (..),
+    NativeCachePolicy (..),
+    validateNativeCachePolicy,
 
     -- * OpenAI Responses compat
-    OpenAIResponsesCompat (supportedReasoningEfforts, supportsSamplingParameters, supportsLongCacheRetention, supportsPromptCacheOptions),
+    OpenAIResponsesCompat (supportedReasoningEfforts, supportsSamplingParameters, supportsLongCacheRetention, supportsPromptCacheOptions, nativeCachePolicy),
     defaultOpenAIResponsesCompat,
 
     -- * Anthropic Messages compat
@@ -56,6 +59,7 @@
         thinkingStyle,
         supportsFastMode,
         supportsForcedToolChoice,
+        supportsThinkingDisabled,
         supportsSamplingParameters
       ),
     AnthropicThinkingStyle (..),
@@ -132,6 +136,25 @@
   deriving stock (Eq, Show, Generic)
   deriving anyclass (FromJSON, ToJSON)
 
+-- | Endpoint-specific native OpenAI caching. Absence on a compat record
+-- preserves its legacy behavior; explicit unsupported overrides old flags.
+-- Legacy arguments declare in_memory and 24h independently. Modern arguments
+-- declare 12h and prefix breakpoints; modern always supports the 30m default.
+-- The sum prevents mixing legacy retention with modern breakpoints.
+data NativeCachePolicy
+  = NativeCacheUnsupported
+  | NativeCacheLegacy !Bool !Bool
+  | NativeCacheModern !Bool !Bool
+  deriving stock (Eq, Show, Generic)
+  deriving anyclass (FromJSON, ToJSON)
+
+-- | Reject contradictory caller-built as well as curated endpoint facts.
+validateNativeCachePolicy :: Maybe CacheControlFormat -> Maybe NativeCachePolicy -> Either Text ()
+validateNativeCachePolicy format policy = case (format, policy) of
+  (Just _, Just _) -> Left "native and Anthropic cache controls cannot share a binding"
+  (_, Just (NativeCacheLegacy False False)) -> Left "legacy cache policy must accept at least one retention value"
+  _ -> Right ()
+
 -- | Which request shape an Anthropic-compatible host/model accepts
 -- for extended thinking. Budget-era models take
 -- @{"type":"enabled","budget_tokens":N}@; adaptive-era models take
@@ -194,10 +217,11 @@
     --   Anthropic-style cache_control marker. Consumed by
     --   @Baikai.Provider.OpenAI.Shape.injectCacheControl@ when
     --   'cacheControlFormat' is 'Just CacheControlFormatAnthropic'.
-    supportsLongCacheRetention :: !Bool
+    supportsLongCacheRetention :: !Bool,
+    nativeCachePolicy :: !(Maybe NativeCachePolicy)
   }
   deriving stock (Eq, Show, Generic)
-  deriving anyclass (FromJSON, ToJSON)
+  deriving anyclass (ToJSON)
 
 -- | OpenAI's own host: every flag at the OpenAI default.
 defaultOpenAICompletionsCompat :: OpenAICompletionsCompat
@@ -212,7 +236,8 @@
       supportsToolCalls = True,
       supportsSamplingParameters = True,
       supportedReasoningEfforts = Nothing,
-      supportsLongCacheRetention = True
+      supportsLongCacheRetention = True,
+      nativeCachePolicy = Nothing
     }
 
 -- | Model and endpoint facts for native Responses. This is separate
@@ -222,10 +247,11 @@
     supportsSamplingParameters :: !Bool,
     supportsLongCacheRetention :: !Bool,
     -- | Use prompt_cache_options rather than legacy prompt_cache_retention.
-    supportsPromptCacheOptions :: !Bool
+    supportsPromptCacheOptions :: !Bool,
+    nativeCachePolicy :: !(Maybe NativeCachePolicy)
   }
   deriving stock (Eq, Show, Generic)
-  deriving anyclass (FromJSON, ToJSON)
+  deriving anyclass (ToJSON)
 
 defaultOpenAIResponsesCompat :: OpenAIResponsesCompat
 defaultOpenAIResponsesCompat =
@@ -233,9 +259,35 @@
     { supportedReasoningEfforts = Nothing,
       supportsSamplingParameters = True,
       supportsLongCacheRetention = True,
-      supportsPromptCacheOptions = False
+      supportsPromptCacheOptions = False,
+      nativeCachePolicy = Nothing
     }
 
+-- New policy fields are optional in persisted compatibility JSON.
+instance FromJSON OpenAICompletionsCompat where
+  parseJSON = withObject "OpenAICompletionsCompat" $ \o ->
+    OpenAICompletionsCompat
+      <$> o .: "maxTokensField"
+      <*> o .: "supportsStrictMode"
+      <*> o .: "requiresThinkingAsText"
+      <*> o .: "thinkingFormat"
+      <*> o .:? "cacheControlFormat"
+      <*> o .: "supportsUsageInStreaming"
+      <*> o .: "supportsToolCalls"
+      <*> o .: "supportsSamplingParameters"
+      <*> o .:? "supportedReasoningEfforts"
+      <*> o .: "supportsLongCacheRetention"
+      <*> o .:? "nativeCachePolicy"
+
+instance FromJSON OpenAIResponsesCompat where
+  parseJSON = withObject "OpenAIResponsesCompat" $ \o ->
+    OpenAIResponsesCompat
+      <$> o .:? "supportedReasoningEfforts"
+      <*> o .: "supportsSamplingParameters"
+      <*> o .: "supportsLongCacheRetention"
+      <*> o .: "supportsPromptCacheOptions"
+      <*> o .:? "nativeCachePolicy"
+
 -- | Feature flags for one Anthropic Messages-compatible host.
 data AnthropicMessagesCompat = AnthropicMessagesCompat
   { -- | Whether the host honours Anthropic's
@@ -243,8 +295,9 @@
     --   long-retention preferences silently downgrade to ephemeral.
     --   Consumed by @Baikai.Provider.Claude.Internal.Request.computeCacheControl@
     --   for top-level cache markers and by
-    --   @Baikai.Provider.Claude.Shape.injectToolCacheControl@ for
-    --   tool cache markers.
+    --   @Baikai.Provider.Claude.Shape.injectToolCacheControl@ and
+    --   @Baikai.Provider.Claude.Shape.injectSystemCacheControl@ for
+    --   tool and system-prompt cache markers.
     supportsLongCacheRetention :: !Bool,
     -- | Whether tool definitions accept @cache_control@ markers.
     --   Consumed by
@@ -276,7 +329,15 @@
     supportsFastMode :: !Bool,
     -- | Whether this generation accepts required or named tool choice.
     -- Defaults to True; explicit catalog facts disable unsupported choices.
-    supportsForcedToolChoice :: !Bool
+    supportsForcedToolChoice :: !Bool,
+    -- | Whether this generation accepts @thinking: {"type": "disabled"}@,
+    -- which 'Baikai.ThinkingLevel.ThinkingNone' sends. Defaults to False:
+    -- unannotated and legacy records do not establish disable support.
+    -- Claude Opus 5.5, Sonnet 5.5, Fable 5 and Fable 5.1 reject it with a 400, and their catalog
+    -- records say so; there @none@ clamps to the lowest adaptive effort
+    -- and the clamp is recorded. Consumed by
+    -- @Baikai.Provider.Claude.Internal.Request.computeThinking@.
+    supportsThinkingDisabled :: !Bool
   }
   deriving stock (Eq, Show, Generic)
   deriving anyclass (ToJSON)
@@ -291,10 +352,12 @@
       thinkingStyle = AnthropicThinkingBudget,
       supportsSamplingParameters = True,
       supportsFastMode = False,
-      supportsForcedToolChoice = True
+      supportsForcedToolChoice = True,
+      supportsThinkingDisabled = False
     }
 
--- | Older persisted models predate fast-mode and forced-choice capabilities.
+-- | Older persisted models predate the fast-mode, forced-choice and
+-- disabled-thinking capabilities.
 instance FromJSON AnthropicMessagesCompat where
   parseJSON = withObject "AnthropicMessagesCompat" $ \o ->
     AnthropicMessagesCompat
@@ -305,6 +368,7 @@
       <*> o .: "supportsSamplingParameters"
       <*> o .:? "supportsFastMode" .!= False
       <*> o .:? "supportsForcedToolChoice" .!= True
+      <*> o .:? "supportsThinkingDisabled" .!= False
 
 -- | Pick a sensible compat record for an unknown OpenAI-compatible
 -- host based on its @baseUrl@. Falls back to
diff --git a/src/Baikai/Evidence.hs b/src/Baikai/Evidence.hs
--- a/src/Baikai/Evidence.hs
+++ b/src/Baikai/Evidence.hs
@@ -320,12 +320,16 @@
 -- the requested thinking level; it must not refuse one merely because
 -- a sampling parameter had nowhere to go. The six level-carrying
 -- constructors weaken thinking; the sampling and speed ones do not.
+--
+-- A model catalogued as non-reasoning already satisfies ThinkingNone.
+-- A host without controls may still reason by default: dropping none
+-- there cannot satisfy a strict caller.
 weakensThinking :: ThinkingAdjustment -> Bool
 weakensThinking = \case
   EffortClamped {} -> True
   EffortCollapsedToToggle {} -> True
   EffortOmitted {} -> True
-  ThinkingDroppedUnsupportedModel {} -> True
+  ThinkingDroppedUnsupportedModel lvl -> lvl /= ThinkingNone
   ThinkingDroppedUnsupportedHost {} -> True
   ThinkingDroppedBudgetExceeded {} -> True
   SamplingDroppedUnsupportedModel {} -> False
@@ -919,7 +923,11 @@
 -- Older error objects decode with Nothing; digest inputs are unchanged.
 -- Version 2.6 adds structured response content and optional request_problem.
 -- The canonical encoding and data-free commitment fixtures are unchanged.
-evidenceSchemaVersion = "baikai.model-call-evidence/2.6"
+-- Version 2.7 adds the explicit none thinking preference. Existing digests and
+-- observations are unchanged; a transmitted off request remains unobserved.
+-- Version 2.8 projects native cache controls and content-free Responses input
+-- structure. Envelopes lacking the new fields preserve their prior digests.
+evidenceSchemaVersion = "baikai.model-call-evidence/2.8"
 
 -- | Everything Baikai can say about one completed provider call.
 --
@@ -1270,6 +1278,10 @@
   where
     keep (k, v) = case Key.toText k of
       "messages" -> [(k, summariseMessages v)]
+      "input" -> [(k, summariseInput v)]
+      "instructions" -> [(k, charSummary v)]
+      "prompt_cache_options" -> [(k, summariseNativeControl v)]
+      "prompt_cache_retention" -> [(k, allowedString ["in_memory", "24h"] v)]
       "system" -> [(k, charSummary v)]
       "tools" -> [(k, summariseTools v)]
       "output_config" -> [(k, summariseOutputConfig v)]
@@ -1312,10 +1324,12 @@
 summariseMessage = \case
   Object m ->
     object
-      [ "role" .= roleOf (KeyMap.lookup "role" m),
-        "blocks" .= blockCount (KeyMap.lookup "content" m),
-        "chars" .= maybe 0 totalStringChars (KeyMap.lookup "content" m)
-      ]
+      ( [ "role" .= roleOf (KeyMap.lookup "role" m),
+          "blocks" .= blockCount (KeyMap.lookup "content" m),
+          "chars" .= maybe 0 totalStringChars (KeyMap.lookup "content" m)
+        ]
+          <> markerSummary (KeyMap.lookup "content" m)
+      )
   _ -> Null
   where
     roleOf = \case
@@ -1327,6 +1341,44 @@
       Just Null -> 0
       Nothing -> 0
       Just _ -> 1
+
+-- Only native policy vocabulary is configuration. Unknown nested fields,
+-- cache identities, text, replay IDs and encrypted state never enter it.
+allowedString :: [Text] -> Value -> Value
+allowedString values v@(String t) | t `elem` values = v
+allowedString _ _ = Null
+
+summariseNativeControl :: Value -> Value
+summariseNativeControl (Object o) =
+  Object
+    ( KeyMap.fromList
+        [(k, allowedString values v) | (k, values) <- [("mode", ["implicit", "explicit"]), ("ttl", ["30m", "12h"])], Just v <- [KeyMap.lookup k o]]
+    )
+summariseNativeControl _ = Null
+
+markerSummary :: Maybe Value -> [(Key.Key, Value)]
+markerSummary (Just (Array parts)) =
+  let markers =
+        [ object ["index" .= i, "control" .= summariseNativeControl marker]
+        | (i, Object part) <- zip [0 :: Int ..] (Vector.toList parts),
+          Just marker <- [KeyMap.lookup "prompt_cache_breakpoint" part]
+        ]
+   in [("cache_breakpoints", toJSON markers) | not (null markers)]
+markerSummary _ = []
+
+summariseInput :: Value -> Value
+summariseInput (Array items) = toJSON (map item (Vector.toList items))
+  where
+    item (Object o) =
+      object
+        ( [ "role" .= maybe Null (allowedString ["system", "developer", "user", "assistant"]) (KeyMap.lookup "role" o),
+            "type" .= maybe Null (allowedString ["message", "reasoning", "function_call", "function_call_output"]) (KeyMap.lookup "type" o),
+            "chars" .= totalStringChars (Object o)
+          ]
+            <> markerSummary (KeyMap.lookup "content" o)
+        )
+    item v = charSummary v
+summariseInput v = charSummary v
 
 -- | Total characters across every JSON string anywhere inside a value.
 -- Recursive on purpose: a content block's text can sit at any depth,
diff --git a/src/Baikai/Models/Generated.hs b/src/Baikai/Models/Generated.hs
--- a/src/Baikai/Models/Generated.hs
+++ b/src/Baikai/Models/Generated.hs
@@ -15,13 +15,16 @@
         supportsForcedToolChoice,
         supportsLongCacheRetention,
         supportsSamplingParameters,
+        supportsThinkingDisabled,
         thinkingStyle
       ),
     AnthropicThinkingStyle (..),
     CacheControlFormat (..),
+    NativeCachePolicy (..),
     MaxTokensField (..),
     OpenAICompletionsCompat
-      ( cacheControlFormat,
+      ( nativeCachePolicy,
+        cacheControlFormat,
         maxTokensField,
         requiresThinkingAsText,
         supportedReasoningEfforts,
@@ -99,7 +102,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = False
             }
     }
 
@@ -135,7 +139,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = False,
-              supportsForcedToolChoice = False
+              supportsForcedToolChoice = False,
+              supportsThinkingDisabled = False
             }
     }
 
@@ -171,7 +176,8 @@
               thinkingStyle = AnthropicThinkingBudget,
               supportsSamplingParameters = True,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -207,7 +213,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -243,7 +250,8 @@
               thinkingStyle = AnthropicThinkingBudget,
               supportsSamplingParameters = True,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -279,7 +287,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = True,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -315,7 +324,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -359,7 +369,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = True,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -403,7 +414,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = True,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -447,7 +459,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = True,
-              supportsForcedToolChoice = False
+              supportsForcedToolChoice = False,
+              supportsThinkingDisabled = False
             }
     }
 
@@ -483,7 +496,8 @@
               thinkingStyle = AnthropicThinkingBudget,
               supportsSamplingParameters = True,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -519,7 +533,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = True,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -555,7 +570,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = False,
-              supportsForcedToolChoice = True
+              supportsForcedToolChoice = True,
+              supportsThinkingDisabled = True
             }
     }
 
@@ -591,7 +607,8 @@
               thinkingStyle = AnthropicThinkingAdaptive,
               supportsSamplingParameters = False,
               supportsFastMode = False,
-              supportsForcedToolChoice = False
+              supportsForcedToolChoice = False,
+              supportsThinkingDisabled = False
             }
     }
 
@@ -670,7 +687,21 @@
       contextWindow = 1047576,
       maxOutputTokens = 32768,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Nothing,
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Just (NativeCacheLegacy True True)
+            }
     }
 
 openai_gpt_4_1_mini :: Model
@@ -800,7 +831,21 @@
       contextWindow = 400000,
       maxOutputTokens = 128000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Just [ThinkingMinimal, ThinkingLow, ThinkingMedium, ThinkingHigh],
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Nothing
+            }
     }
 
 openai_gpt_5_1 :: Model
@@ -956,7 +1001,21 @@
       contextWindow = 1050000,
       maxOutputTokens = 128000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Nothing,
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Just (NativeCacheLegacy False True)
+            }
     }
 
 openai_gpt_5_6 :: Model
@@ -982,7 +1041,21 @@
       contextWindow = 1050000,
       maxOutputTokens = 128000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Nothing,
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Just (NativeCacheModern False True)
+            }
     }
 
 openai_gpt_5_6_luna :: Model
@@ -1086,7 +1159,21 @@
       contextWindow = 400000,
       maxOutputTokens = 128000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Just [ThinkingMinimal, ThinkingLow, ThinkingMedium, ThinkingHigh],
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Nothing
+            }
     }
 
 openai_gpt_5_nano :: Model
@@ -1112,7 +1199,21 @@
       contextWindow = 400000,
       maxOutputTokens = 128000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Just [ThinkingMinimal, ThinkingLow, ThinkingMedium, ThinkingHigh],
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Nothing
+            }
     }
 
 openai_gpt_6_1_sol :: Model
@@ -1144,7 +1245,8 @@
             { supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax],
               supportsSamplingParameters = False,
               supportsLongCacheRetention = False,
-              supportsPromptCacheOptions = True
+              supportsPromptCacheOptions = True,
+              nativeCachePolicy = Just (NativeCacheModern False True)
             }
     }
 
@@ -1177,7 +1279,8 @@
             { supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax],
               supportsSamplingParameters = False,
               supportsLongCacheRetention = False,
-              supportsPromptCacheOptions = True
+              supportsPromptCacheOptions = True,
+              nativeCachePolicy = Just (NativeCacheModern False True)
             }
     }
 
@@ -1200,17 +1303,18 @@
             cacheWriteCost = 1 % 8
           },
       fastModeCost = Nothing,
-      pricingPolicy = Just (PricingPolicy [InputPriceTier 272000 (ModelCost (1 % 5) (3 % 4) (1 % 50) (1 % 4)) Nothing] Nothing),
+      pricingPolicy = Just (PricingPolicy [InputPriceTier 272000 (ModelCost (1 % 5) (3 % 4) (1 % 50) (1 % 4)) (Just (1 % 2))] (Just (1 % 4))),
       contextWindow = 1050000,
       maxOutputTokens = 128000,
       headers = Map.empty,
       compat =
         CompatOpenAIResponses
           defaultOpenAIResponsesCompat
-            { supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax],
+            { supportedReasoningEfforts = Just [ThinkingNone, ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax],
               supportsSamplingParameters = False,
-              supportsLongCacheRetention = False,
-              supportsPromptCacheOptions = True
+              supportsLongCacheRetention = True,
+              supportsPromptCacheOptions = True,
+              nativeCachePolicy = Just (NativeCacheModern True True)
             }
     }
 
@@ -1240,10 +1344,11 @@
       compat =
         CompatOpenAIResponses
           defaultOpenAIResponsesCompat
-            { supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax],
+            { supportedReasoningEfforts = Just [ThinkingNone, ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax],
               supportsSamplingParameters = False,
               supportsLongCacheRetention = False,
-              supportsPromptCacheOptions = True
+              supportsPromptCacheOptions = True,
+              nativeCachePolicy = Just (NativeCacheModern False True)
             }
     }
 
@@ -1270,7 +1375,21 @@
       contextWindow = 200000,
       maxOutputTokens = 100000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh],
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Nothing
+            }
     }
 
 openai_o3 :: Model
@@ -1296,7 +1415,21 @@
       contextWindow = 200000,
       maxOutputTokens = 100000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh],
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Nothing
+            }
     }
 
 openai_o3_mini :: Model
@@ -1322,7 +1455,21 @@
       contextWindow = 200000,
       maxOutputTokens = 100000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh],
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Nothing
+            }
     }
 
 openai_o4_mini :: Model
@@ -1348,7 +1495,21 @@
       contextWindow = 200000,
       maxOutputTokens = 100000,
       headers = Map.empty,
-      compat = CompatNone
+      compat =
+        CompatOpenAICompletions
+          defaultOpenAICompletionsCompat
+            { maxTokensField = MaxCompletionTokensField,
+              supportsStrictMode = True,
+              requiresThinkingAsText = False,
+              thinkingFormat = ThinkingFormatOpenAI,
+              cacheControlFormat = Nothing,
+              supportsToolCalls = True,
+              supportsSamplingParameters = True,
+              supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh],
+              supportsUsageInStreaming = True,
+              supportsLongCacheRetention = True,
+              nativeCachePolicy = Nothing
+            }
     }
 
 openrouter_anthropic_claude_sonnet_4 :: Model
diff --git a/src/Baikai/Options.hs b/src/Baikai/Options.hs
--- a/src/Baikai/Options.hs
+++ b/src/Baikai/Options.hs
@@ -105,11 +105,21 @@
     -- | 'Nothing' and @Just 'CacheRetentionNone'@ are the same request:
     -- both send no cache-control marker. The constructor is kept for a
     -- caller who wants to say "no caching" explicitly.
+    --
+    -- On Anthropic Messages hosts a retention sets up to three cache
+    -- breakpoints: the top-level automatic marker (the end of the
+    -- request), the last tool definition, and the system prompt, which
+    -- is then sent as one text block carrying @cache_control@. The
+    -- system-prompt breakpoint lets requests that share a static system
+    -- prefix but differ in their messages read it from the cache.
     cacheRetention :: !(Maybe CacheRetention),
     -- | Nothing omits the speed field; standard explicitly requests standard
     -- speed. Fast is catalog-gated by Anthropic and dropped with evidence on
     -- unsupported models. See "Baikai.Speed" for availability and pricing.
     speed :: !(Maybe Speed),
+    -- | Nothing leaves the provider default; Just ThinkingNone requests off.
+    -- Unsupported requests are recorded as adjustments; strict evidence refuses
+    -- a fallback before dispatch. Translation is not proof of server execution.
     thinking :: !(Maybe ThinkingLevel),
     responseFormat :: !(Maybe ResponseFormat),
     evidence :: !(Maybe EvidenceRequest),
diff --git a/src/Baikai/ThinkingLevel.hs b/src/Baikai/ThinkingLevel.hs
--- a/src/Baikai/ThinkingLevel.hs
+++ b/src/Baikai/ThinkingLevel.hs
@@ -3,7 +3,7 @@
 -- | Provider-agnostic reasoning-effort preference.
 --
 -- Each provider maps the value to its own primitive. The canonical
--- rendering spans @minimal@ through @max@, while provider boundaries
+-- rendering spans @none@ through @max@, while provider boundaries
 -- may preserve, translate, or clamp values according to their APIs.
 -- 'thinkingTokenBudget' provides the recommended budget for
 -- token-based providers.
@@ -25,7 +25,18 @@
 -- provider's vocabulary, fine enough to influence behaviour in a
 -- meaningful way.
 data ThinkingLevel
-  = ThinkingMinimal
+  = -- | Ask for no reasoning at all. This is not the same as leaving
+    -- 'Baikai.Options.thinking' at 'Nothing': that sends nothing and
+    -- leaves the model's own default in force, which on an adaptive
+    -- Anthropic generation such as Claude Haiku 5.5 is to think. This
+    -- level asks for thinking to be turned off: Anthropic Messages
+    -- sends @thinking: {"type": "disabled"}@ to a model whose catalog
+    -- record says it accepts that ('Baikai.Compat.supportsThinkingDisabled')
+    -- and otherwise records a fallback. OpenAI sends @none@ when the
+    -- model's accepted-effort policy permits it. Strict evidence refuses
+    -- substitutions before dispatch; no mapping proves server execution.
+    ThinkingNone
+  | ThinkingMinimal
   | ThinkingLow
   | ThinkingMedium
   | ThinkingHigh
@@ -37,6 +48,7 @@
 -- | Render the canonical Baikai name for a reasoning-effort level.
 renderThinkingLevel :: ThinkingLevel -> Text
 renderThinkingLevel = \case
+  ThinkingNone -> "none"
   ThinkingMinimal -> "minimal"
   ThinkingLow -> "low"
   ThinkingMedium -> "medium"
@@ -51,6 +63,7 @@
 -- @Baikai.Agent.Cli@ — did the first time a level was added.
 parseThinkingLevel :: Text -> Maybe ThinkingLevel
 parseThinkingLevel = \case
+  "none" -> Just ThinkingNone
   "minimal" -> Just ThinkingMinimal
   "low" -> Just ThinkingLow
   "medium" -> Just ThinkingMedium
@@ -60,9 +73,11 @@
   _ -> Nothing
 
 -- | Recommended token budget for providers that take an explicit
--- count (Anthropic's @thinking.budget_tokens@).
+-- count (Anthropic's @thinking.budget_tokens@). 'ThinkingNone' asks
+-- for no budget, so it is @0@; no provider sends a budget for it.
 thinkingTokenBudget :: ThinkingLevel -> Natural
 thinkingTokenBudget = \case
+  ThinkingNone -> 0
   ThinkingMinimal -> 1024
   ThinkingLow -> 2048
   ThinkingMedium -> 8192
diff --git a/test/CatalogSpec.hs b/test/CatalogSpec.hs
--- a/test/CatalogSpec.hs
+++ b/test/CatalogSpec.hs
@@ -28,8 +28,10 @@
     supportsFastMode,
     supportsForcedToolChoice,
     supportsSamplingParameters,
+    supportsThinkingDisabled,
     thinkingStyle,
   )
+import Baikai.Compat qualified as C
 import Baikai.Model
   ( Compat (CompatAnthropicMessages, CompatOpenAIResponses),
     Model,
@@ -37,6 +39,7 @@
     compat,
     modelId,
   )
+import Baikai.Model qualified as M
 import Baikai.Models.Generated (allModels)
 import Baikai.ThinkingLevel (ThinkingLevel (..))
 import Data.ByteString qualified as BS
@@ -51,7 +54,17 @@
 tests =
   testGroup
     "Baikai.Models.Generated"
-    [ testCase "Astra selects Responses with explicit endpoint facts" $ do
+    [ testCase "native cache facts enable verified Luna Long and keep Chat gated" $ do
+        let findModel mid = case filter ((== mid) . modelId) allModels of [m] -> pure m; _ -> assertFailure "missing model"
+        luna <- findModel "gpt-6-luna"
+        chat <- findModel "gpt-5.6"
+        both <- findModel "gpt-4.1"
+        longOnly <- findModel "gpt-5.5"
+        (M.openaiResponsesCompatFor luna).nativeCachePolicy @?= Just (C.NativeCacheModern True True)
+        (M.openaiCompletionsCompatFor chat).nativeCachePolicy @?= Just (C.NativeCacheModern False True)
+        (M.openaiCompletionsCompatFor both).nativeCachePolicy @?= Just (C.NativeCacheLegacy True True)
+        (M.openaiCompletionsCompatFor longOnly).nativeCachePolicy @?= Just (C.NativeCacheLegacy False True),
+      testCase "Astra selects Responses with explicit endpoint facts" $ do
         [api m | m <- allModels, modelId m == "gpt-6-astra"] @?= [OpenAIResponses]
         case [compat m | m <- allModels, modelId m == "gpt-6-astra"] of
           [CompatOpenAIResponses c] -> do
@@ -67,9 +80,9 @@
               case [compat m | m <- allModels, modelId m == mid] of
                 [CompatOpenAIResponses c] -> do
                   c.supportsPromptCacheOptions @?= True
-                  c.supportsLongCacheRetention @?= False
+                  c.supportsLongCacheRetention @?= (mid == "gpt-6-luna")
                   c.supportsSamplingParameters @?= False
-                  c.supportedReasoningEfforts @?= Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax]
+                  c.supportedReasoningEfforts @?= Just ([ThinkingNone | mid /= "gpt-6.1-sol"] <> [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax])
                 _ -> assertFailure "GPT-6 Sol/Luna need explicit OpenAI Responses facts"
           )
           ["gpt-6-sol", "gpt-6-luna", "gpt-6.1-sol"],
@@ -103,25 +116,25 @@
 anthropicCatalogModels :: [Model]
 anthropicCatalogModels = [m | m <- allModels, api m == AnthropicMessages]
 
--- | The shipped thinking style and sampling support of each Anthropic
--- catalog id, written out by hand from
--- @baikai\/data\/models\/anthropic.json@.
-expectedAnthropicFacts :: [(Text, (AnthropicThinkingStyle, Bool, Bool, Bool))]
+-- | The shipped thinking style, sampling, forced-choice, fast-mode and
+-- disabled-thinking support of each Anthropic catalog id, written out by
+-- hand from @baikai\/data\/models\/anthropic.json@.
+expectedAnthropicFacts :: [(Text, (AnthropicThinkingStyle, Bool, Bool, Bool, Bool))]
 expectedAnthropicFacts =
-  [ ("claude-fable-5", (AnthropicThinkingAdaptive, False, True, False)),
-    ("claude-fable-5-1", (AnthropicThinkingAdaptive, False, False, False)),
-    ("claude-haiku-4-5", (AnthropicThinkingBudget, True, True, False)),
-    ("claude-haiku-5-5", (AnthropicThinkingAdaptive, False, True, False)),
-    ("claude-opus-4-5", (AnthropicThinkingBudget, True, True, False)),
-    ("claude-opus-4-6", (AnthropicThinkingAdaptive, True, True, False)),
-    ("claude-opus-4-7", (AnthropicThinkingAdaptive, False, True, False)),
-    ("claude-opus-4-8", (AnthropicThinkingAdaptive, False, True, True)),
-    ("claude-opus-5", (AnthropicThinkingAdaptive, False, True, True)),
-    ("claude-opus-5-5", (AnthropicThinkingAdaptive, False, False, True)),
-    ("claude-sonnet-4-5", (AnthropicThinkingBudget, True, True, False)),
-    ("claude-sonnet-4-6", (AnthropicThinkingAdaptive, True, True, False)),
-    ("claude-sonnet-5", (AnthropicThinkingAdaptive, False, True, False)),
-    ("claude-sonnet-5-5", (AnthropicThinkingAdaptive, False, False, False))
+  [ ("claude-fable-5", (AnthropicThinkingAdaptive, False, True, False, False)),
+    ("claude-fable-5-1", (AnthropicThinkingAdaptive, False, False, False, False)),
+    ("claude-haiku-4-5", (AnthropicThinkingBudget, True, True, False, True)),
+    ("claude-haiku-5-5", (AnthropicThinkingAdaptive, False, True, False, True)),
+    ("claude-opus-4-5", (AnthropicThinkingBudget, True, True, False, True)),
+    ("claude-opus-4-6", (AnthropicThinkingAdaptive, True, True, False, True)),
+    ("claude-opus-4-7", (AnthropicThinkingAdaptive, False, True, False, True)),
+    ("claude-opus-4-8", (AnthropicThinkingAdaptive, False, True, True, True)),
+    ("claude-opus-5", (AnthropicThinkingAdaptive, False, True, True, True)),
+    ("claude-opus-5-5", (AnthropicThinkingAdaptive, False, False, True, False)),
+    ("claude-sonnet-4-5", (AnthropicThinkingBudget, True, True, False, True)),
+    ("claude-sonnet-4-6", (AnthropicThinkingAdaptive, True, True, False, True)),
+    ("claude-sonnet-5", (AnthropicThinkingAdaptive, False, True, False, True)),
+    ("claude-sonnet-5-5", (AnthropicThinkingAdaptive, False, False, False, False))
   ]
 
 assertFacts :: Model -> IO ()
@@ -139,5 +152,5 @@
           <> show other
       )
   where
-    facts :: AnthropicMessagesCompat -> (AnthropicThinkingStyle, Bool, Bool, Bool)
-    facts c = (thinkingStyle c, c.supportsSamplingParameters, c.supportsForcedToolChoice, c.supportsFastMode)
+    facts :: AnthropicMessagesCompat -> (AnthropicThinkingStyle, Bool, Bool, Bool, Bool)
+    facts c = (thinkingStyle c, c.supportsSamplingParameters, c.supportsForcedToolChoice, c.supportsFastMode, c.supportsThinkingDisabled)
diff --git a/test/CostSpec.hs b/test/CostSpec.hs
--- a/test/CostSpec.hs
+++ b/test/CostSpec.hs
@@ -47,7 +47,12 @@
 tests =
   testGroup
     "Baikai.Cost"
-    [ fastCostTests,
+    [ testCase "synthetic native duration rates select the complete input tier once" $ do
+        let m = knownModel & #pricingPolicy .~ Just (PricingPolicy [InputPriceTier 100 (ModelCost 2 4 (1 / 5) (5 / 2)) (Just 5)] (Just (5 / 2)))
+            u = Usage.observeBilling [Usage.BillingServiceTier "default"] (zeroUsage & #cacheWriteTokens .~ 200 & #totalTokens .~ 200)
+        (computeCostForService (Just CacheRetentionShort) Nothing m u) ^. #usd @?= 1 / 2000
+        (computeCostForService (Just CacheRetentionLong) Nothing m u) ^. #usd @?= 1 / 1000,
+      fastCostTests,
       computeTests,
       attachCostTests,
       callLogTests
diff --git a/test/EvidenceSpec.hs b/test/EvidenceSpec.hs
--- a/test/EvidenceSpec.hs
+++ b/test/EvidenceSpec.hs
@@ -27,7 +27,14 @@
 tests =
   testGroup
     "Evidence"
-    [ translationDisplayTests,
+    [ testCase "native cache configuration redacts replay and records marker position" $ do
+        let marker = object ["mode" .= ("explicit" :: Text.Text), "secret" .= ("PRIVATE_CONTROL" :: Text.Text)]
+            block marked = object (["type" .= ("input_text" :: Text.Text), "text" .= ("PRIVATE_TEXT" :: Text.Text)] <> ["prompt_cache_breakpoint" .= marker | marked])
+            body marked = object ["prompt_cache_options" .= object ["ttl" .= ("30m" :: Text.Text), "cache_key" .= ("PRIVATE_KEY" :: Text.Text)], "input" .= [object ["role" .= ("developer" :: Text.Text), "content" .= [block marked]], object ["type" .= ("reasoning" :: Text.Text), "encrypted_content" .= ("PRIVATE_REPLAY" :: Text.Text), "id" .= ("PRIVATE_ID" :: Text.Text)]]]
+            projection = Text.pack (show (configurationProjection (body True)))
+        assertBool "no private content" (not ("PRIVATE" `Text.isInfixOf` projection))
+        assertBool "marker placement matters" (configurationDigest (body True) /= configurationDigest (body False)),
+      translationDisplayTests,
       canonicalTests,
       digestTests,
       usageEnvelopeTests,
@@ -271,7 +278,7 @@
   testGroup
     "usage envelope"
     [ testCase "cost basis is serialized additively without changing provider commitments" $ do
-        evidenceSchemaVersion @?= "baikai.model-call-evidence/2.6"
+        evidenceSchemaVersion @?= "baikai.model-call-evidence/2.8"
         let estimated = zeroUsage {cost = estimateCost [CacheWriteUsageNotReported] zeroCost}
         usageEnvelope estimated @?= usageEnvelope zeroUsage
         assertBool "usage JSON retains the local calculation basis" (Aeson.toJSON estimated /= Aeson.toJSON zeroUsage),
diff --git a/test/FetchModelsSpec.hs b/test/FetchModelsSpec.hs
--- a/test/FetchModelsSpec.hs
+++ b/test/FetchModelsSpec.hs
@@ -1,14 +1,18 @@
+{-# LANGUAGE OverloadedRecordDot #-}
+
 -- | Unit tests for the pure core of @baikai-fetch-models@
 -- ('FetchModelsCore'): filtering, curation, modality mapping, cost
 -- defaulting, and rendering, exercised against a checked-in
 -- models.dev-shaped fixture. No network is involved.
 module FetchModelsSpec (tests) where
 
-import Baikai.Compat (AnthropicThinkingStyle (..), defaultOpenAIResponsesCompat)
+import Baikai.Compat (AnthropicThinkingStyle (..), defaultOpenAICompletionsCompat, defaultOpenAIResponsesCompat)
+import Baikai.Compat qualified as C
 import Baikai.Model (InputModality (..))
 import Baikai.Model qualified
 import Baikai.Model qualified as Model
 import Baikai.Prelude
+import Baikai.ThinkingLevel (ThinkingLevel (..))
 import Control.Monad (forM_)
 import Data.Aeson qualified as Aeson
 import Data.Aeson.KeyMap qualified as KeyMap
@@ -67,7 +71,7 @@
               contextWindow = 400000,
               maxOutputTokens = 128000,
               apiOverride = Nothing,
-              compat = Nothing
+              compat = Just (CatalogOpenAICompat (defaultOpenAICompletionsCompat & #supportedReasoningEfforts .~ Just [ThinkingMinimal, ThinkingLow, ThinkingMedium, ThinkingHigh]))
             },
           CatalogModel
             { modelId = "gpt-5.4",
@@ -115,6 +119,7 @@
                           { thinkingStyle = AnthropicThinkingBudget,
                             supportsSamplingParameters = True,
                             supportsForcedToolChoice = True,
+                            supportsThinkingDisabled = True,
                             fastModeCost = Nothing
                           }
                       )
@@ -127,8 +132,20 @@
 tests =
   testGroup
     "Baikai.FetchModels"
-    [ testCase "per-model API and Responses compat survive normalization and rendering" $ do
+    [ testCase "curated native cache facts survive fetch rendering and generator parsing" $ do
         upstream <- loadUpstream
+        let sample = head (Map.elems (Map.findWithDefault Map.empty "openai" upstream))
+        forM_ [("gpt-6-luna", C.NativeCacheModern True True), ("gpt-5.6", C.NativeCacheModern False True), ("gpt-4.1", C.NativeCacheLegacy True True), ("gpt-5.5", C.NativeCacheLegacy False True)] $ \(mid, expected) -> do
+          let cat = normalizeProvider openaiSpec (Map.singleton mid (sample & #modelId .~ mid & #toolCall .~ True))
+          parsed <- either assertFailure pure (Aeson.eitherDecode (BSL.fromStrict (renderCatalog cat)))
+          let entries = Gen.flattenEntries parsed
+          case map (\(_, e) -> e.compat) entries of
+            [Gen.CatalogCompatOpenAI c] -> c ^. #nativeCachePolicy @?= Just expected
+            [Gen.CatalogCompatResponses c] -> c ^. #nativeCachePolicy @?= Just expected
+            _ -> assertFailure "missing native compat"
+          assertBool "generator renders policy" (Text.pack (show expected) `Text.isInfixOf` Gen.renderModule entries),
+      testCase "per-model API and Responses compat survive normalization and rendering" $ do
+        upstream <- loadUpstream
         let spec =
               openaiSpec
                 & #apiFor
@@ -157,6 +174,14 @@
               _ -> assertFailure "wrong entries"
             _ -> assertFailure "missing models"
           _ -> assertFailure "invalid rendered catalog",
+      testCase "refresh and generation preserve which OpenAI models accept none" $ do
+        upstream <- loadUpstream
+        let sample = (upstream Map.! "openai") Map.! "gpt-5.4"
+        forM_ [("gpt-5", "ThinkingMinimal"), ("o3", "ThinkingLow"), ("gpt-6-sol", "ThinkingNone"), ("gpt-6-luna", "ThinkingNone"), ("gpt-6-astra", "ThinkingLow"), ("gpt-6.1-sol", "ThinkingLow")] $ \(mid, lowest) -> do
+          let refreshed = normalizeProvider openaiSpec (Map.singleton mid (sample & #modelId .~ mid))
+          case Aeson.eitherDecode (BSL.fromStrict (renderCatalog refreshed)) of
+            Left err -> assertFailure err
+            Right catalog -> assertBool (Text.unpack mid <> " preserves its lowest effort") (("supportedReasoningEfforts = Just [" <> lowest <> ",") `Text.isInfixOf` Gen.renderModule (Gen.flattenEntries catalog)),
       testCase "refresh preserves Astra endpoint restrictions despite upstream tool support" $ do
         upstream <- loadUpstream
         let sample = (upstream Map.! "openai") Map.! "gpt-5.4"
@@ -185,7 +210,7 @@
         forM_
           [ (openaiSpec, "gpt-6-astra", Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 20 75 2 25) Nothing] Nothing),
             (openaiSpec, "gpt-6-sol", Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 4 15 0.4 5) Nothing] Nothing),
-            (openaiSpec, "gpt-6-luna", Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 0.2 0.75 0.02 0.25) Nothing] Nothing),
+            (openaiSpec, "gpt-6-luna", Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 0.2 0.75 0.02 0.25) (Just 0.5)] (Just 0.25)),
             (anthropicSpec, "claude-fable-5-1", Model.PricingPolicy [] (Just 20)),
             (anthropicSpec, "claude-opus-5-5", Model.PricingPolicy [] (Just 8))
           ]
@@ -286,14 +311,16 @@
                 "        \"thinkingStyle\": \"budget\",",
                 "        \"supportsSamplingParameters\": true,",
                 "        \"supportsFastMode\": false,",
-                "        \"supportsForcedToolChoice\": true",
+                "        \"supportsForcedToolChoice\": true,",
+                "        \"supportsThinkingDisabled\": true",
                 "      },"
               ]
               `Text.isInfixOf` rendered
           ),
-      testCase "an OpenAI model renders no compat block" $ do
+      testCase "an unconstrained OpenAI model renders no compat block" $ do
         upstream <- loadUpstream
-        let rendered = renderText (catalogFor upstream openaiSpec)
+        let catalog = catalogFor upstream openaiSpec
+            rendered = renderText (catalog & #models .~ filter ((== "gpt-5.4") . (^. #modelId)) (catalog ^. #models))
         assertBool
           "no per-model compat block (the file-level \"compat\": \"auto\" stays)"
           (not ("\"compat\": {" `Text.isInfixOf` rendered)),
diff --git a/test/GenModelsSpec.hs b/test/GenModelsSpec.hs
--- a/test/GenModelsSpec.hs
+++ b/test/GenModelsSpec.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE OverloadedRecordDot #-}
+
 module GenModelsSpec (tests) where
 
 import Baikai.Api (Api (AnthropicMessages, OpenAIChatCompletions, OpenAIResponses))
@@ -6,12 +8,15 @@
     defaultAnthropicMessagesCompat,
     supportsFastMode,
     supportsSamplingParameters,
+    supportsThinkingDisabled,
     thinkingStyle,
   )
+import Baikai.Compat qualified as C
 import Baikai.Model (InputModality (InputText))
 import Baikai.Model qualified
 import Control.Monad (forM_)
 import Data.Aeson qualified as Aeson
+import Data.Aeson.KeyMap qualified as KM
 import Data.Text (Text)
 import Data.Text qualified as Text
 import GenModelsCore
@@ -22,7 +27,31 @@
 tests =
   testGroup
     "Baikai.GenModels"
-    [ testCase "fast capability and rates must agree in both directions" $ do
+    [ testCase "legacy OpenAI runtime JSON defaults missing native policy" $ do
+        let legacy c = case Aeson.toJSON c of Aeson.Object o -> Aeson.Object (KM.delete "nativeCachePolicy" (KM.delete "cacheControlFormat" (KM.delete "supportedReasoningEfforts" o))); v -> v
+        case Aeson.fromJSON (legacy C.defaultOpenAIResponsesCompat) of
+          Aeson.Success c -> assertBool "absent Responses policy" ((c :: C.OpenAIResponsesCompat).nativeCachePolicy == Nothing)
+          Aeson.Error err -> assertFailure err
+        case Aeson.fromJSON (legacy C.defaultOpenAICompletionsCompat) of
+          Aeson.Success c -> assertBool "absent Chat policy" ((c :: C.OpenAICompletionsCompat).nativeCachePolicy == Nothing)
+          Aeson.Error err -> assertFailure err,
+      testCase "native catalog rejects contradictory controls and unpriced Long naming model" $ do
+        let conflicting = CatalogCompatOpenAI (C.defaultOpenAICompletionsCompat {C.cacheControlFormat = Just C.CacheControlFormatAnthropic, C.nativeCachePolicy = Just (C.NativeCacheModern False True)})
+            unpriced = CatalogCompatResponses (C.defaultOpenAIResponsesCompat {C.nativeCachePolicy = Just (C.NativeCacheModern True True)})
+            emptyLegacy = CatalogCompatResponses (C.defaultOpenAIResponsesCompat {C.nativeCachePolicy = Just (C.NativeCacheLegacy False False)})
+        forM_ [conflicting, unpriced, emptyLegacy] $ \block -> do
+          let c = collisionCatalog {models = [(model "invalid-cache-model") {entryCompatOverride = Just block}]}
+          case checkNativeCacheCompat (flattenEntries c) of
+            Left err -> assertBool "names model" ("invalid-cache-model" `Text.isInfixOf` err)
+            Right () -> assertFailure "invalid policy accepted",
+      testCase "legacy Anthropic model JSON does not invent disable support" $ do
+        let raw = case Aeson.toJSON (defaultAnthropicMessagesCompat {supportsThinkingDisabled = True}) of
+              Aeson.Object o -> Aeson.Object (KM.delete "supportsThinkingDisabled" o)
+              other -> other
+        case Aeson.fromJSON raw of
+          Aeson.Error err -> assertFailure err
+          Aeson.Success c -> assertBool "missing fact is conservative" (not (supportsThinkingDisabled c)),
+      testCase "fast capability and rates must agree in both directions" $ do
         forM_ [(True, Nothing), (False, Just (CostEntry 10 50 1 12.5))] $ \(supported, rates) -> do
           let block = CatalogCompatAnthropic (defaultAnthropicMessagesCompat {supportsFastMode = supported})
               catalog = (anthropicCatalog CatalogCompatAuto (Just block)) {models = [(model "claude-x") {entryCompatOverride = Just block, entryFastModeCost = rates}]}
diff --git a/test/StrictEvidenceSpec.hs b/test/StrictEvidenceSpec.hs
--- a/test/StrictEvidenceSpec.hs
+++ b/test/StrictEvidenceSpec.hs
@@ -195,6 +195,14 @@
         "a thinking budget that will not fit the output ceiling is discarded"
         (ThinkingDroppedBudgetExceeded ThinkingMax 32000 8192)
         "does not fit inside the resolved output ceiling",
+      refusesDowngrade
+        "a host without controls may still think by default when none is requested"
+        (ThinkingDroppedUnsupportedHost ThinkingNone)
+        "exposes no reasoning controls",
+      refusesDowngrade
+        "a minimum positive effort cannot satisfy explicit off"
+        (EffortClamped ThinkingNone "low")
+        "would be sent as low",
       testCase "several downgrades on one call are reported together" $
         case checkEvidenceRequirements
           (EvidenceRequired EvidenceRequestedOnly)
diff --git a/test/ThinkingLevelSpec.hs b/test/ThinkingLevelSpec.hs
--- a/test/ThinkingLevelSpec.hs
+++ b/test/ThinkingLevelSpec.hs
@@ -16,7 +16,8 @@
 
 levels :: [(String, ThinkingLevel, Text, Integer)]
 levels =
-  [ ("minimal", ThinkingMinimal, "minimal", 1024),
+  [ ("none", ThinkingNone, "none", 0),
+    ("minimal", ThinkingMinimal, "minimal", 1024),
     ("low", ThinkingLow, "low", 2048),
     ("medium", ThinkingMedium, "medium", 8192),
     ("high", ThinkingHigh, "high", 16384),
