diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,104 @@
 
 ## [Unreleased]
 
+## [baikai 0.7.1.0] - 2026-09-23
+
+### Added
+
+- Curated GPT-6 Sol and Luna on OpenAI Responses and Claude Opus 5.5 on
+  Anthropic Messages (`openai_gpt_6_sol`, `openai_gpt_6_luna`,
+  `anthropic_claude_opus_5_5`), with endpoint compatibility and standard,
+  long-context, cache-duration, and fast-mode prices where applicable. All
+  three passed live acceptance on 2026-09-23. Sol and Luna dispatch to
+  `OpenAIResponses`, so calling them requires the
+  `Baikai.Provider.OpenAI.Responses.register` call that `baikai-openai 0.7.0.0`
+  introduced.
+
+## [baikai-kit 0.3.0.0] - 2026-09-23
+
+Closes four improvement requests from the tools that ship `baikai-kit` as their
+`kit` command: project scope resolves from a configurable root (IR-8),
+`kit status` reports local edits separately from upstream drift (IR-7),
+`kit install` without a name asks a tool-supplied chooser (IR-6), and `list`,
+`status` and `update` print versioned JSON (IR-9). A consumer raising its bound
+builds `KitConfig` with `kitConfig`, passes it to `kitCommandParser`, and
+matches on `StatusRow.conditions`; each break is at a call site the compiler
+names.
+
+### Added
+
+- `baikai-kit`: `KitConfig.projectRoot :: IO FilePath` says where project scope
+  lives. Install, status, update, uninstall and `agentDirsForSession` all derive
+  project-scope paths from it, so they agree whichever subdirectory a command
+  runs from. `kitConfig` builds a configuration with every optional field at its
+  default (project scope is the current directory, as before);
+  `projectRootByMarkers [".git", ".mytool"]` is a ready-made resolver that walks
+  up to the nearest marker and falls back to the current directory, and
+  `findProjectRoot` is the underlying walk. Resolves IR-8.
+
+- `baikai-kit`: `kit status` reports local edits. It runs the same
+  installed-file check `kit update` uses to skip an item, and shows
+  `modified` for an edited copy and `edits-unknown` for one whose sidecar
+  predates the installed-file hash. The check is exported as
+  `checkLocalEdits`, returning `LocalEdits` (`Unedited`, `Edited`,
+  `EditsUnknown`). Resolves IR-7.
+
+- `baikai-kit`: `kit install` with no name asks a chooser the tool supplies in
+  the new `KitConfig.chooseItem :: Maybe (KitManifest -> IO (Maybe Text))`
+  field. The engine refreshes the kit, passes the whole manifest, and installs
+  what the chooser returns; a cancelled choice prints
+  `No item chosen; nothing installed.` and exits 0. With no chooser (the
+  `kitConfig` default) the command fails with the new `KitItemNameRequired`
+  error, which tells the user to pass `NAME`. The engine ships no picker.
+  `KitCommand` derives `Eq`, and `kit install --help` names the tool's
+  `.<tool>/agents` directory. Resolves IR-6.
+
+- `baikai-kit`: `kit list`, `kit status` and `kit update` accept `--json` and
+  print exactly one versioned JSON document on stdout
+  (`{"formatVersion": 1, "document": "kit-list" | "kit-status" | "kit-update", …}`);
+  warnings and the first-clone notice go to stderr, and a failed command writes
+  nothing to stdout. The shapes are written by explicit encoders —
+  `Baikai.Kit.Json.listDocument`, `statusDocument`, `updateDocument`, and
+  `kitJsonFormatVersion` — so library callers get the same values, and they are
+  pinned by golden tests. `Baikai.Kit.Command.OutputFormat` selects the mode,
+  and `Baikai.Kit.Status.InstalledCopy` / `installedCopies` report where each
+  item is installed. Resolves IR-9.
+
+### Changed
+
+- `baikai-kit`: `KitConfig` gains the strict field `projectRoot`, so a record
+  literal must set it; build the configuration with
+  `kitConfig toolName repoUrl providers` instead and override fields with record
+  update syntax. `KitConfig`'s `Show` instance is now hand-written and prints
+  `<IO FilePath>` for the resolver. __Breaking__.
+
+- `baikai-kit`: `kit status` conditions compose, and `dirty` is renamed
+  `changed-upstream` (it meant the upstream sources changed without a version
+  bump, not local edits); `dirty+outdated` now reads
+  `outdated+changed-upstream`. `StatusRow.state :: KitState` is replaced by
+  `StatusRow.conditions :: [KitCondition]` (sorted; empty means up to date),
+  `renderState` by `conditionLabel` and `renderConditions`, and `classify`
+  returns `[KitCondition]`. `KitUpToDate`, `KitDirty` and `KitDirtyOutdated`
+  are gone; match on the list instead. __Breaking__.
+
+- `baikai-kit`: `KitInstall` takes `Maybe Text` (`Nothing` asks the chooser),
+  `kitCommandParser` takes the `KitConfig` (migration: `kitCommandParser`
+  becomes `kitCommandParser myKitConfig`), `KitConfig` gains the `chooseItem`
+  field (set by `kitConfig`), and `KitError` gains `KitItemNameRequired`.
+  __Breaking__.
+
+- `baikai-kit`: `KitList`, `KitStatus` and `KitUpdate` gain a trailing
+  `OutputFormat` field (`HumanOutput` for the previous behaviour).
+  __Breaking__.
+
+## [baikai-effectful 0.4.0.2] - 2026-09-15
+
+### Changed (dependencies)
+
+- Requires `effectful-core ^>=2.7` (was `^>=2.6`). No API change: none of the
+  2.7 breaking APIs (`LocalEnv`'s second type parameter, `SharedSuffix`,
+  `KnownEffects`, the ticked strict modules) are used.
+
 ## [baikai 0.7.0.0] - 2026-09-08
 
 ### Added
diff --git a/baikai.cabal b/baikai.cabal
--- a/baikai.cabal
+++ b/baikai.cabal
@@ -1,7 +1,7 @@
-cabal-version:   3.4
-name:            baikai
-version:         0.7.0.0
-synopsis:        Unified Haskell interface for multiple AI providers
+cabal-version: 3.4
+name: baikai
+version: 0.7.1.0
+synopsis: Unified Haskell interface for multiple AI providers
 description:
   baikai provides a unified, provider-agnostic Haskell interface for working
   with multiple AI providers. It abstracts chat and streaming completions, tool
@@ -9,21 +9,27 @@
   concrete provider implementations supplied by companion packages such as
   @baikai-claude@ and @baikai-openai@.
 
-category:        AI
-license:         BSD-3-Clause
-license-file:    LICENSE
-author:          Nadeem Bitar
-maintainer:      nadeem@gmail.com
-copyright:       (c) 2026 Nadeem Bitar
-build-type:      Simple
-tested-with:     GHC ==9.12.4
+category: AI
+license: BSD-3-Clause
+license-file: LICENSE
+author: Nadeem Bitar
+maintainer: nadeem@gmail.com
+copyright: (c) 2026 Nadeem Bitar
+build-type: Simple
+tested-with: ghc ==9.12.4
 extra-doc-files: CHANGELOG.md
 
 common common-options
   ghc-options:
-    -Wall -Wcompat -Widentities -Wincomplete-uni-patterns
-    -Wincomplete-record-updates -Wredundant-constraints
-    -fhide-source-paths -Wmissing-export-lists -Wpartial-fields
+    -Wall
+    -Wcompat
+    -Widentities
+    -Wincomplete-uni-patterns
+    -Wincomplete-record-updates
+    -Wredundant-constraints
+    -fhide-source-paths
+    -Wmissing-export-lists
+    -Wpartial-fields
     -Wmissing-deriving-strategies
 
   -- Exhaustiveness is an error, not a warning. A non-exhaustive match
@@ -38,10 +44,11 @@
   -- fail the build on warnings that are stylistic or that a future GHC
   -- invents, and would push people toward blanket suppression.
   ghc-options:
-    -Werror=incomplete-patterns -Werror=incomplete-uni-patterns
+    -Werror=incomplete-patterns
+    -Werror=incomplete-uni-patterns
     -Werror=incomplete-record-updates
 
-  default-language:   GHC2024
+  default-language: GHC2024
   default-extensions:
     DeriveAnyClass
     DuplicateRecordFields
@@ -49,8 +56,8 @@
     OverloadedStrings
 
 library
-  import:          common-options
-  hs-source-dirs:  src
+  import: common-options
+  hs-source-dirs: src
   exposed-modules:
     Baikai
     Baikai.Agent
@@ -100,84 +107,90 @@
   -- it so an evidence record can name the build that produced it,
   -- centrally rather than through a literal in each of the five
   -- packages that construct evidence.
-  other-modules:   Paths_baikai
+  other-modules: Paths_baikai
   autogen-modules: Paths_baikai
   build-depends:
-    , aeson              ^>=2.2
-    , base               >=4.20  && <5
-    , base16-bytestring  ^>=1.0
-    , base64-bytestring  ^>=1.2
-    , bytestring         ^>=0.12
-    , case-insensitive   ^>=1.2
-    , containers         ^>=0.7
-    , cryptohash-sha256  ^>=0.11
-    , directory          ^>=1.3
-    , filepath           ^>=1.5
-    , generic-lens       ^>=2.3
-    , http-client        ^>=0.7
-    , http-client-tls    >=0.3   && <0.5
-    , http-types         ^>=0.12
-    , lens               ^>=5.3
-    , openai             ^>=2.5
-    , process            ^>=1.6
-    , scientific         ^>=0.3
-    , servant-client     ^>=0.20
-    , stm                ^>=2.5
-    , streamly           >=0.11  && <0.13
-    , streamly-core      >=0.3   && <0.5
-    , text               ^>=2.1
-    , time               ^>=1.14
-    , tls                >=2.2   && <2.5
-    , unliftio-core      ^>=0.2
-    , vector             ^>=0.13
+    aeson ^>=2.2,
+    base >=4.20 && <5,
+    base16-bytestring ^>=1.0,
+    base64-bytestring ^>=1.2,
+    bytestring ^>=0.12,
+    case-insensitive ^>=1.2,
+    containers ^>=0.7,
+    cryptohash-sha256 ^>=0.11,
+    directory ^>=1.3,
+    filepath ^>=1.5,
+    generic-lens ^>=2.3,
+    http-client ^>=0.7,
+    http-client-tls >=0.3 && <0.5,
+    http-types ^>=0.12,
+    lens ^>=5.3,
+    openai ^>=2.5,
+    process ^>=1.6,
+    scientific ^>=0.3,
+    servant-client ^>=0.20,
+    stm ^>=2.5,
+    streamly >=0.11 && <0.13,
+    streamly-core >=0.3 && <0.5,
+    text ^>=2.1,
+    time ^>=1.14,
+    tls >=2.2 && <2.5,
+    unliftio-core ^>=0.2,
+    vector ^>=0.13,
 
 executable baikai-gen-models
-  import:         common-options
+  import: common-options
   hs-source-dirs: gen
-  main-is:        GenModels.hs
-  other-modules:  GenModelsCore
+  main-is: GenModels.hs
+  other-modules: GenModelsCore
   build-depends:
-    , aeson       ^>=2.2
-    , baikai
-    , base        >=4.20  && <5
-    , bytestring  ^>=0.12
-    , containers  ^>=0.7
-    , directory   ^>=1.3
-    , filepath    ^>=1.5
-    , scientific  ^>=0.3
-    , text        ^>=2.1
+    aeson ^>=2.2,
+    baikai,
+    base >=4.20 && <5,
+    bytestring ^>=0.12,
+    containers ^>=0.7,
+    directory ^>=1.3,
+    filepath ^>=1.5,
+    scientific ^>=0.3,
+    text ^>=2.1,
 
 executable baikai-fetch-models
-  import:         common-options
+  import: common-options
   hs-source-dirs: fetch
-  main-is:        FetchModels.hs
-  other-modules:  FetchModelsCore
-
+  main-is: FetchModels.hs
+  other-modules: FetchModelsCore
   -- The main module is named @FetchModels@ (not @Main@) so the pure
   -- core can be compiled into the test suite alongside its own
   -- @Main.hs@ without a module-name clash.
-  ghc-options:    -main-is FetchModels
+  ghc-options:
+    -main-is
+    FetchModels
+
   build-depends:
-    , aeson            ^>=2.2
-    , baikai
-    , base             >=4.20  && <5
-    , bytestring       ^>=0.12
-    , containers       ^>=0.7
-    , directory        ^>=1.3
-    , filepath         ^>=1.5
-    , generic-lens     ^>=2.3
-    , http-client      ^>=0.7
-    , http-client-tls  >=0.3   && <0.5
-    , lens             ^>=5.3
-    , scientific       ^>=0.3
-    , text             ^>=2.1
-    , vector           ^>=0.13
+    aeson ^>=2.2,
+    baikai,
+    base >=4.20 && <5,
+    bytestring ^>=0.12,
+    containers ^>=0.7,
+    directory ^>=1.3,
+    filepath ^>=1.5,
+    generic-lens ^>=2.3,
+    http-client ^>=0.7,
+    http-client-tls >=0.3 && <0.5,
+    lens ^>=5.3,
+    scientific ^>=0.3,
+    text ^>=2.1,
+    vector ^>=0.13,
 
 test-suite baikai-test
-  import:             common-options
-  type:               exitcode-stdio-1.0
-  hs-source-dirs:     test fetch gen
-  main-is:            Main.hs
+  import: common-options
+  type: exitcode-stdio-1.0
+  hs-source-dirs:
+    test
+    fetch
+    gen
+
+  main-is: Main.hs
   other-modules:
     AgentAssetsSpec
     AgentSpec
@@ -209,29 +222,29 @@
 
   build-tool-depends: baikai:baikai-gen-models
   build-depends:
-    , aeson
-    , baikai
-    , base
-    , bytestring
-    , case-insensitive
-    , containers
-    , directory
-    , filepath
-    , generic-lens
-    , http-client
-    , http-types
-    , lens
-    , openai
-    , process
-    , scientific
-    , servant-client
-    , stm
-    , streamly-core     >=0.3 && <0.5
-    , tasty
-    , tasty-hunit
-    , tasty-quickcheck
-    , temporary
-    , text
-    , time
-    , tls
-    , vector
+    aeson,
+    baikai,
+    base,
+    bytestring,
+    case-insensitive,
+    containers,
+    directory,
+    filepath,
+    generic-lens,
+    http-client,
+    http-types,
+    lens,
+    openai,
+    process,
+    scientific,
+    servant-client,
+    stm,
+    streamly-core >=0.3 && <0.5,
+    tasty,
+    tasty-hunit,
+    tasty-quickcheck,
+    temporary,
+    text,
+    time,
+    tls,
+    vector,
diff --git a/fetch/FetchModelsCore.hs b/fetch/FetchModelsCore.hs
--- a/fetch/FetchModelsCore.hs
+++ b/fetch/FetchModelsCore.hs
@@ -259,13 +259,19 @@
   }
   deriving stock (Generic)
 
--- | Curation include set for OpenAI: the chat-completions-compatible
--- current line. Responses-API-only ids (@*-pro@, @*-codex@,
--- @*-deep-research@) are deliberately absent.
+-- | Curation include set for OpenAI's current Chat and Responses lines.
+-- Responses-only ids outside the text and function-tool scope
+-- (@*-pro@, @*-codex@, @*-deep-research@) are deliberately absent.
 openaiInclude :: Map Text (Maybe CatalogModelCompat)
 openaiInclude =
-  Map.insert "gpt-6-astra" (Just (CatalogResponsesCompat astraResponsesFacts)) $
-    Map.fromList
+  Map.union
+    ( Map.fromList
+        [ ("gpt-6-astra", Just (CatalogResponsesCompat astraResponsesFacts)),
+          ("gpt-6-sol", Just (CatalogResponsesCompat gpt6ResponsesFacts)),
+          ("gpt-6-luna", Just (CatalogResponsesCompat gpt6ResponsesFacts))
+        ]
+    )
+    $ Map.fromList
       [ (model, Nothing)
       | model <-
           [ "gpt-5.6",
@@ -293,6 +299,11 @@
           ]
       ]
   where
+    -- 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
     -- 2026-09-07: native tools require Responses; only modern 30m cache TTL.
     -- https://developers.openai.com/api/docs/guides/latest-model
     astraResponsesFacts =
@@ -322,6 +333,13 @@
       -- docs/plans/60-... named this id as the one the include set did not
       -- yet carry, and stated the facts it would have to arrive with.
       ("claude-opus-5", fastAdaptive),
+      -- 2026-09-23: always-on adaptive thinking; forced tool choice is
+      -- rejected. Nondefault sampling is rejected on Claude 4.7 and later;
+      -- fast mode is supported on the Claude API.
+      -- https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5
+      -- https://platform.claude.com/docs/en/claude_api_primer
+      -- https://platform.claude.com/docs/en/build-with-claude/fast-mode
+      ("claude-opus-5-5", opus55Facts),
       -- 2026-08-27: adaptive-only, sampling parameters rejected with a
       -- 400 — same source.
       ("claude-opus-4-8", fastAdaptive),
@@ -353,8 +371,9 @@
       ("claude-fable-5-1", adaptiveNoSampling & #supportsForcedToolChoice .~ False)
     ]
   where
-    -- 2026-09-07: all curated predecessors accept forced choice (subject to
-    -- their separate manual-thinking constraint); only Fable 5.1 rejects it.
+    opus55Facts = adaptiveNoSampling & #supportsForcedToolChoice .~ 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-09-07: Opus 5 and 4.8 only; cache multipliers stack on fast rates.
@@ -620,17 +639,23 @@
   where
     c = m ^. #cost
 
--- | Provider documentation verified 2026-09-07. These rules supplement base
+-- | Provider documentation verified 2026-09-23. These rules supplement base
 -- models.dev rates, which do not describe the full request billing policy.
 -- https://developers.openai.com/api/docs/models/gpt-6-astra
+-- https://developers.openai.com/api/docs/models/gpt-6-sol
+-- https://developers.openai.com/api/docs/models/gpt-6-luna
 -- https://platform.claude.com/docs/en/models/fable-5-1/overview
+-- https://platform.claude.com/docs/en/models/opus-5-5/overview
 -- https://platform.claude.com/docs/en/build-with-claude/fast-mode
 pricingPolicies :: Map (Text, Text) Model.PricingPolicy
 pricingPolicies =
   Map.fromList
-    [ (("anthropic", "claude-opus-5"), Model.PricingPolicy [] (Just 10)),
+    [ (("anthropic", "claude-opus-5-5"), Model.PricingPolicy [] (Just 8)),
+      (("anthropic", "claude-opus-5"), Model.PricingPolicy [] (Just 10)),
       (("anthropic", "claude-opus-4-8"), Model.PricingPolicy [] (Just 10)),
       (("openai", "gpt-6-astra"), Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 20 75 2 25)] Nothing),
+      (("openai", "gpt-6-sol"), Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 4 15 0.4 5)] Nothing),
+      (("openai", "gpt-6-luna"), Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 0.2 0.75 0.02 0.25)] Nothing),
       (("anthropic", "claude-fable-5-1"), Model.PricingPolicy [] (Just 20))
     ]
 
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
@@ -361,6 +361,49 @@
             }
     }
 
+anthropic_claude_opus_5_5 :: Model
+anthropic_claude_opus_5_5 =
+  emptyModel
+    { modelId = "claude-opus-5-5",
+      name = "Claude Opus 5.5",
+      api = AnthropicMessages,
+      provider = "anthropic",
+      baseUrl = "https://api.anthropic.com",
+      reasoning = True,
+      input = [InputText, InputImage],
+      cost =
+        ModelCost
+          { inputCost = 4 % 1,
+            outputCost = 20 % 1,
+            cacheReadCost = 1 % 5,
+            cacheWriteCost = 5 % 1
+          },
+      fastModeCost =
+        Just
+          ( ModelCost
+              { inputCost = 8 % 1,
+                outputCost = 40 % 1,
+                cacheReadCost = 2 % 5,
+                cacheWriteCost = 10 % 1
+              }
+          ),
+      pricingPolicy = Just (PricingPolicy [] (Just (8 % 1))),
+      contextWindow = 1000000,
+      maxOutputTokens = 128000,
+      headers = Map.empty,
+      compat =
+        CompatAnthropicMessages
+          defaultAnthropicMessagesCompat
+            { supportsLongCacheRetention = True,
+              supportsCacheControlOnTools = True,
+              sendSessionAffinityHeaders = False,
+              thinkingStyle = AnthropicThinkingAdaptive,
+              supportsSamplingParameters = False,
+              supportsFastMode = True,
+              supportsForcedToolChoice = False
+            }
+    }
+
 anthropic_claude_sonnet_4_5 :: Model
 anthropic_claude_sonnet_4_5 =
   emptyModel
@@ -998,6 +1041,70 @@
             }
     }
 
+openai_gpt_6_luna :: Model
+openai_gpt_6_luna =
+  emptyModel
+    { modelId = "gpt-6-luna",
+      name = "GPT-6 Luna",
+      api = OpenAIResponses,
+      provider = "openai",
+      baseUrl = "https://api.openai.com",
+      reasoning = True,
+      input = [InputText, InputImage],
+      cost =
+        ModelCost
+          { inputCost = 1 % 10,
+            outputCost = 1 % 2,
+            cacheReadCost = 1 % 100,
+            cacheWriteCost = 1 % 8
+          },
+      fastModeCost = Nothing,
+      pricingPolicy = Just (PricingPolicy [InputPriceTier 272000 (ModelCost (1 % 5) (3 % 4) (1 % 50) (1 % 4))] Nothing),
+      contextWindow = 1050000,
+      maxOutputTokens = 128000,
+      headers = Map.empty,
+      compat =
+        CompatOpenAIResponses
+          defaultOpenAIResponsesCompat
+            { supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax],
+              supportsSamplingParameters = False,
+              supportsLongCacheRetention = False,
+              supportsPromptCacheOptions = True
+            }
+    }
+
+openai_gpt_6_sol :: Model
+openai_gpt_6_sol =
+  emptyModel
+    { modelId = "gpt-6-sol",
+      name = "GPT-6 Sol",
+      api = OpenAIResponses,
+      provider = "openai",
+      baseUrl = "https://api.openai.com",
+      reasoning = True,
+      input = [InputText, InputImage],
+      cost =
+        ModelCost
+          { inputCost = 2 % 1,
+            outputCost = 10 % 1,
+            cacheReadCost = 1 % 5,
+            cacheWriteCost = 5 % 2
+          },
+      fastModeCost = Nothing,
+      pricingPolicy = Just (PricingPolicy [InputPriceTier 272000 (ModelCost (4 % 1) (15 % 1) (2 % 5) (5 % 1))] Nothing),
+      contextWindow = 1050000,
+      maxOutputTokens = 128000,
+      headers = Map.empty,
+      compat =
+        CompatOpenAIResponses
+          defaultOpenAIResponsesCompat
+            { supportedReasoningEfforts = Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax],
+              supportsSamplingParameters = False,
+              supportsLongCacheRetention = False,
+              supportsPromptCacheOptions = True
+            }
+    }
+
 openai_o1 :: Model
 openai_o1 =
   emptyModel
@@ -1159,6 +1266,7 @@
     anthropic_claude_opus_4_7,
     anthropic_claude_opus_4_8,
     anthropic_claude_opus_5,
+    anthropic_claude_opus_5_5,
     anthropic_claude_sonnet_4_5,
     anthropic_claude_sonnet_4_6,
     anthropic_claude_sonnet_5,
@@ -1183,6 +1291,8 @@
     openai_gpt_5_mini,
     openai_gpt_5_nano,
     openai_gpt_6_astra,
+    openai_gpt_6_luna,
+    openai_gpt_6_sol,
     openai_o1,
     openai_o3,
     openai_o3_mini,
diff --git a/src/Baikai/Provider/Transport/Classify.hs b/src/Baikai/Provider/Transport/Classify.hs
--- a/src/Baikai/Provider/Transport/Classify.hs
+++ b/src/Baikai/Provider/Transport/Classify.hs
@@ -61,6 +61,7 @@
     ePIPE,
     eTIMEDOUT,
   )
+
 -- Qualified: its 'IOErrorType' has a constructor named @OtherError@,
 -- which collides with the 'ErrorCategory' constructor of that name.
 import GHC.IO.Exception qualified as IOE
diff --git a/src/Baikai/Trace.hs b/src/Baikai/Trace.hs
--- a/src/Baikai/Trace.hs
+++ b/src/Baikai/Trace.hs
@@ -65,6 +65,7 @@
     summarizeContext,
   )
 import Baikai.Error (BaikaiError, providerError)
+
 -- 'Baikai.Evidence.CallStatus' has a @CallFailed@ constructor and so
 -- does 'Baikai.Trace.Event.TraceEvent'. They mean different things and
 -- both belong in this module, so the status constructors stay behind
diff --git a/test/CatalogSpec.hs b/test/CatalogSpec.hs
--- a/test/CatalogSpec.hs
+++ b/test/CatalogSpec.hs
@@ -60,6 +60,19 @@
             c.supportsSamplingParameters @?= False
             c.supportedReasoningEfforts @?= Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax]
           _ -> assertFailure "Astra needs explicit OpenAI endpoint facts",
+      testCase "Sol and Luna select Responses with explicit endpoint facts" $
+        mapM_
+          ( \mid -> do
+              [api m | m <- allModels, modelId m == mid] @?= [OpenAIResponses]
+              case [compat m | m <- allModels, modelId m == mid] of
+                [CompatOpenAIResponses c] -> do
+                  c.supportsPromptCacheOptions @?= True
+                  c.supportsLongCacheRetention @?= False
+                  c.supportsSamplingParameters @?= False
+                  c.supportedReasoningEfforts @?= Just [ThinkingLow, ThinkingMedium, ThinkingHigh, ThinkingXHigh, ThinkingMax]
+                _ -> assertFailure "GPT-6 Sol/Luna need explicit OpenAI Responses facts"
+          )
+          ["gpt-6-sol", "gpt-6-luna"],
       testCase "regenerating from data/models produces no diff" $
         withSystemTempDirectory "baikai-catalog-spec" $ \tmpDir -> do
           let regenPath = tmpDir <> "/Generated.hs"
@@ -103,6 +116,7 @@
     ("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))
diff --git a/test/FetchModelsSpec.hs b/test/FetchModelsSpec.hs
--- a/test/FetchModelsSpec.hs
+++ b/test/FetchModelsSpec.hs
@@ -162,12 +162,15 @@
         map (^. #apiOverride) (refreshed ^. #models) @?= [Just "openai-responses"]
         map (^. #compat) (refreshed ^. #models) @?= [expected]
         assertBool "explicit compat survives rendering" ("openai-responses" `Text.isInfixOf` decodeUtf8 (renderCatalog refreshed)),
-      testCase "fast rates and capability survive fetch and generator on exactly two curated models" $ do
+      testCase "fast rates and capability survive fetch and generator on curated models" $ do
         upstream <- loadUpstream
         let sample = (upstream Map.! "openai") Map.! "gpt-5.4"
         forM_ (Map.keys anthropicInclude) $ \mid -> do
           let refreshed = normalizeProvider anthropicSpec (Map.singleton mid (sample & #modelId .~ mid))
-              expected = if mid `elem` ["claude-opus-5", "claude-opus-4-8"] then Just (CatalogCost 10 50 1 12.5) else Nothing
+              expected
+                | mid == "claude-opus-5-5" = Just (CatalogCost 8 40 0.4 10)
+                | mid `elem` ["claude-opus-5", "claude-opus-4-8"] = Just (CatalogCost 10 50 1 12.5)
+                | otherwise = Nothing
           map (^. #fastModeCost) (refreshed ^. #models) @?= [expected]
           case Aeson.eitherDecode (BSL.fromStrict (renderCatalog refreshed)) of
             Left err -> assertFailure err
@@ -175,12 +178,19 @@
       testCase "curated pricing survives fetch rendering and generator parsing" $ do
         upstream <- loadUpstream
         let sample = (upstream Map.! "openai") Map.! "gpt-5.4"
-        forM_ [(openaiSpec, "gpt-6-astra", Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 20 75 2 25)] Nothing), (anthropicSpec, "claude-fable-5-1", Model.PricingPolicy [] (Just 20))] $ \(spec, mid, policy) -> do
-          let refreshed = normalizeProvider spec (Map.singleton mid (sample & #modelId .~ mid))
-          map (^. #pricingPolicy) (refreshed ^. #models) @?= [Just policy]
-          case Aeson.eitherDecode (BSL.fromStrict (renderCatalog refreshed)) of
-            Left err -> assertFailure err
-            Right catalog -> map (Gen.pricingPolicy . snd) (Gen.flattenEntries catalog) @?= [Just policy],
+        forM_
+          [ (openaiSpec, "gpt-6-astra", Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 20 75 2 25)] Nothing),
+            (openaiSpec, "gpt-6-sol", Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 4 15 0.4 5)] Nothing),
+            (openaiSpec, "gpt-6-luna", Model.PricingPolicy [Model.InputPriceTier 272000 (Model.ModelCost 0.2 0.75 0.02 0.25)] Nothing),
+            (anthropicSpec, "claude-fable-5-1", Model.PricingPolicy [] (Just 20)),
+            (anthropicSpec, "claude-opus-5-5", Model.PricingPolicy [] (Just 8))
+          ]
+          $ \(spec, mid, policy) -> do
+            let refreshed = normalizeProvider spec (Map.singleton mid (sample & #modelId .~ mid))
+            map (^. #pricingPolicy) (refreshed ^. #models) @?= [Just policy]
+            case Aeson.eitherDecode (BSL.fromStrict (renderCatalog refreshed)) of
+              Left err -> assertFailure err
+              Right catalog -> map (Gen.pricingPolicy . snd) (Gen.flattenEntries catalog) @?= [Just policy],
       testCase "OpenAI normalization filters, curates, and maps fields" $ do
         upstream <- loadUpstream
         catalogFor upstream openaiSpec @?= expectedOpenAI,
diff --git a/test/PricingPolicySpec.hs b/test/PricingPolicySpec.hs
--- a/test/PricingPolicySpec.hs
+++ b/test/PricingPolicySpec.hs
@@ -4,10 +4,11 @@
 
 import Baikai.CacheRetention (CacheRetention (..))
 import Baikai.Cost qualified as C
-import Baikai.Cost.Pricing (computeCost, computeCostAtRates, computeCostForService, computeCostWith, resolveRates)
+import Baikai.Cost.Pricing (computeCost, computeCostAtRates, computeCostAtSpeed, computeCostForService, computeCostWith, resolveRates)
 import Baikai.Evidence qualified as Ev
 import Baikai.Model qualified as M
 import Baikai.Models.Generated qualified as Models
+import Baikai.Speed (Speed (..))
 import Baikai.Usage qualified as U
 import Baikai.Usage.Normalize qualified as N
 import Control.Lens ((&), (.~))
@@ -22,7 +23,22 @@
 tests =
   testGroup
     "Pricing policy"
-    [ testCase "requested tiers never substitute for observed service" $ do
+    [ testCase "Sol and Luna prices switch the complete request above 272K" $
+        forM_ [(Models.openai_gpt_6_sol, M.ModelCost 2 10 (1 / 5) (5 / 2), M.ModelCost 4 15 (2 / 5) 5), (Models.openai_gpt_6_luna, M.ModelCost (1 / 10) (1 / 2) (1 / 100) (1 / 8), M.ModelCost (1 / 5) (3 / 4) (1 / 50) (1 / 4))] $ \(m, standard, highRates) -> do
+          forM_ [(272000, standard), (272001, highRates)] $ \(n, expected) -> do
+            let u = U.zeroUsage & #inputTokens .~ (n - 2000) & #cacheReadTokens .~ 1000 & #cacheWriteTokens .~ 1000 & #outputTokens .~ 100
+            resolveRates Nothing m u @?= Right expected
+            (computeCost m u).usd @?= (fromIntegral (n - 2000) * expected.inputCost + 1000 * expected.cacheReadCost + 1000 * expected.cacheWriteCost + 100 * expected.outputCost) / 1000000,
+      testCase "Opus 5.5 prices short, long, and observed fast cache writes" $ do
+        let m = Models.anthropic_claude_opus_5_5
+            u = U.zeroUsage & #cacheWriteTokens .~ 1000000
+            observedFast = U.observeBilling [U.BillingSpeed "fast", U.BillingServiceTier "standard"] u
+        (computeCostWith (Just CacheRetentionShort) m u).usd @?= 5
+        (computeCostWith (Just CacheRetentionLong) m u).usd @?= 8
+        (computeCostAtSpeed m SpeedFast u).usd @?= 10
+        (computeCostForService (Just CacheRetentionLong) Nothing m observedFast).usd @?= 16
+        Set.member (C.UnsupportedSpeed "fast") (computeCostForService (Just CacheRetentionLong) Nothing m observedFast).basis.estimateReasons @?= False,
+      testCase "requested tiers never substitute for observed service" $ do
         let unknown = N.normalizeUsage N.InclusiveInput (N.ReportedUsage (Just 1000) (Just 0) (Just 0) (Just 0) Nothing)
             standard = U.observeBilling [U.BillingServiceTier "default"] unknown
             priority = U.observeBilling [U.BillingServiceTier "priority"] unknown
