Просмотр исходного кода

refactor(apiproxy)!: remove settings and credentials RPCs

imccyu 4 недель назад
Родитель
Сommit
fd7f2065b2

+ 78 - 1
packages/extensions/tool-cordis/src/api-catalog.ts

@@ -736,6 +736,32 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
       },
     ],
   },
+  {
+    key: 'credentialsController',
+    summary: 'Host service backing the generated `ctx.remote.credentials` namespace.',
+    description: 'Host service backing the generated `ctx.remote.credentials` namespace. It carries every wire obligation the credential seam itself does not: the batch fan-out bound, the field-by-field view projection, the reference-grammar guard, and the refusal mapping. Secret values cross in one direction only — no method here returns one.',
+    methods: [
+      {
+        signature: '@Remote async describe(refs: string[]): Promise<Record<string, CredentialInfo>>',
+        description: 'Describe several references for one configuration surface. Batched because a settings page describes every reference its rows name at once, and one round trip keeps those rows from settling separately.',
+        parameters: [{ name: 'refs', description: 'reference names, at most {@link MAX_DESCRIBE_REFS}; a name outside the grammar rejects the whole call as `bad-request`.' }],
+        returns: 'one view per requested name, keyed by that name.',
+        throws: ['TypertRemoteFailure when the request is invalid or no credential provider is mounted.'],
+      },
+      {
+        signature: '@Remote async set(ref: string, value: string): Promise<void>',
+        description: 'Store one value from a configuration surface. The value crosses the wire in this direction only: no read path returns it.',
+        parameters: [{ name: 'ref', description: 'reference name to store under.' }, { name: 'value', description: 'the non-empty secret value.' }],
+        throws: ['TypertRemoteFailure when the request is invalid, no provider is mounted, or the provider refuses the write.'],
+      },
+      {
+        signature: '@Remote async unset(ref: string): Promise<void>',
+        description: 'Remove one reference from a configuration surface.',
+        parameters: [{ name: 'ref', description: 'reference name to remove.' }],
+        throws: ['TypertRemoteFailure when the request is invalid, no provider is mounted, or the provider refuses the write.'],
+      },
+    ],
+  },
   {
     key: 'deepseekLlmApiExtensions',
     summary: 'Registry of independently owned top-level fields for official DeepSeek requests.',
@@ -1870,6 +1896,41 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
       },
     ],
   },
+  {
+    key: 'settingsController',
+    summary: 'Host service backing the generated `ctx.remote.settings` namespace.',
+    description: 'Host service backing the generated `ctx.remote.settings` namespace. Every remote read uses `redactSecrets: true`, so a `role(\'secret\')` field cannot ride a response. Writes expose the settings service\'s merge, replacement, and path-addressed operations, and classify every provider refusal as `settings-conflict` or `settings-rejected` with the service\'s message.',
+    methods: [
+      {
+        signature: '@Remote describe(): SettingsDescribeValue',
+        description: 'Describe every registered namespace for a configuration page: redacted layered values plus the serialized schema the page renders its form from.',
+        parameters: [],
+        returns: 'provider writability, local-document presence, and one view per namespace.',
+        throws: ['TypertRemoteFailure when no settings provider is mounted.'],
+      },
+      {
+        signature: '@Remote update( ns: string, patch: Record<string, JsonValue>, expectedRevision: number | undefined, ): Promise<SettingsNamespaceView>',
+        description: 'Merge a patch into one namespace\'s stored user section.',
+        parameters: [{ name: 'ns', description: 'namespace key to write.' }, { name: 'patch', description: 'fields to merge into the user section.' }, { name: 'expectedRevision', description: 'revision the caller read; `undefined` writes unconditionally.' }],
+        returns: 'the namespace\'s redacted view after the write.',
+        throws: ['TypertRemoteFailure when the request is invalid, no provider is mounted, or the provider refuses the write.'],
+      },
+      {
+        signature: '@Remote replace( ns: string, section: Record<string, JsonValue>, expectedRevision: number | undefined, ): Promise<SettingsNamespaceView>',
+        description: 'Replace one namespace\'s stored user section wholesale.',
+        parameters: [{ name: 'ns', description: 'namespace key to write.' }, { name: 'section', description: 'complete replacement user section.' }, { name: 'expectedRevision', description: 'revision the caller read; `undefined` writes unconditionally.' }],
+        returns: 'the namespace\'s redacted view after the write.',
+        throws: ['TypertRemoteFailure when the request is invalid, no provider is mounted, or the provider refuses the write.'],
+      },
+      {
+        signature: '@Remote async mutate( ns: string, ops: SettingsPathOpView[], expectedRevision: number | undefined, ): Promise<SettingsNamespaceView>',
+        description: 'Apply path-addressed edits to one namespace\'s user section, resolved against the section as stored rather than against whatever the caller last read, then answer with that namespace\'s new redacted view.',
+        parameters: [{ name: 'ns', description: 'namespace key to write.' }, { name: 'ops', description: 'the edits to apply, in order.' }, { name: 'expectedRevision', description: 'revision the caller read; `undefined` writes unconditionally.' }],
+        returns: 'the namespace\'s redacted view after the write.',
+        throws: ['TypertRemoteFailure when the request is invalid, no provider is mounted, or the provider refuses the write.'],
+      },
+    ],
+  },
   {
     key: 'shell',
     summary: 'Abstract bash execution service.',
@@ -4455,7 +4516,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [
   },
   {
     name: 'RpcErrorDetailsMap',
-    declaration: 'export interface RpcErrorDetailsMap {\n    \'bad-request\': {\n        issues: ZodIssue[];\n    };\n    \'cancelled\': {};\n    \'session-not-found\': {\n        sessionId: SessionId;\n    };\n    \'invalid-time-zone\': {\n        value: string;\n    };\n    \'agent-preset-read-only\': {\n        agentPreset: string;\n        reason: string;\n    };\n    \'agent-preset-locked\': {\n        sessionId: SessionId;\n        agentPreset: string;\n    };\n    \'agent-preset-not-found\': {\n        agentPreset: string;\n        available: readonly string[];\n    };\n    \'agent-preset-invalid\': {\n        agentPreset: string;\n        reason: string;\n    };\n    \'agent-busy\': {\n        reason: string;\n    };\n    \'settings-rejected\': {\n        ns: string;\n    };\n    \'settings-conflict\': {\n        ns: string;\n        expected: number;\n        actual: number;\n    };\n    \'credential-rejected\': {\n        ref: string;\n    };\n    \'model-discovery-failed\': {\n        settingsNs: string;\n        baseURL?: string;\n    };\n    \'internal\': {};\n}',
+    declaration: 'export interface RpcErrorDetailsMap {\n    \'bad-request\': {\n        issues: ZodIssue[];\n    };\n    \'cancelled\': {};\n    \'session-not-found\': {\n        sessionId: SessionId;\n    };\n    \'invalid-time-zone\': {\n        value: string;\n    };\n    \'agent-preset-read-only\': {\n        agentPreset: string;\n        reason: string;\n    };\n    \'agent-preset-locked\': {\n        sessionId: SessionId;\n        agentPreset: string;\n    };\n    \'agent-preset-not-found\': {\n        agentPreset: string;\n        available: readonly string[];\n    };\n    \'agent-preset-invalid\': {\n        agentPreset: string;\n        reason: string;\n    };\n    \'agent-busy\': {\n        reason: string;\n    };\n    \'model-discovery-failed\': {\n        settingsNs: string;\n        baseURL?: string;\n    };\n    \'internal\': {};\n}',
   },
   {
     name: 'RpcId',
@@ -4973,6 +5034,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [
     name: 'SettingsDescribeOptions',
     declaration: 'export interface SettingsDescribeOptions {\n    redactSecrets?: boolean;\n}',
   },
+  {
+    name: 'SettingsDescribeValue',
+    declaration: 'export interface SettingsDescribeValue {\n    writable: boolean;\n    hasDocument: boolean;\n    namespaces: SettingsNamespaceView[];\n}',
+  },
   {
     name: 'SettingsDescriptor',
     declaration: 'export interface SettingsDescriptor {\n    ns: SettingsNamespace;\n    schema: unknown;\n    value: unknown;\n    revision: number;\n    base?: unknown;\n    user?: unknown;\n    applies: SettingsApplies;\n    secrets?: RedactedSecret[];\n}',
@@ -4981,14 +5046,26 @@ export const TYPE_API: readonly TypeApiEntry[] = [
     name: 'SettingsNamespace',
     declaration: 'export type SettingsNamespace = Branded<\'SettingsNamespace\'>;',
   },
+  {
+    name: 'SettingsNamespaceView',
+    declaration: 'export interface SettingsNamespaceView {\n    ns: string;\n    schema: JsonValue;\n    value: JsonValue;\n    base?: JsonValue;\n    user?: JsonValue;\n    applies: \'live\' | \'restart\';\n    secrets: SettingsSecretView[];\n    revision: number;\n}',
+  },
   {
     name: 'SettingsPathOp',
     declaration: 'export type SettingsPathOp = {\n    op: \'set\';\n    path: readonly string[];\n    value: unknown;\n} | {\n    op: \'unset\';\n    path: readonly string[];\n};',
   },
+  {
+    name: 'SettingsPathOpView',
+    declaration: 'export type SettingsPathOpView = {\n    op: \'set\';\n    path: string[];\n    value: JsonValue;\n} | {\n    op: \'unset\';\n    path: string[];\n};',
+  },
   {
     name: 'SettingsRegisterOptions',
     declaration: 'export interface SettingsRegisterOptions<T> {\n    base?: Partial<T>;\n    applies?: SettingsApplies;\n    validate?: (value: T) => void;\n}',
   },
+  {
+    name: 'SettingsSecretView',
+    declaration: 'export interface SettingsSecretView {\n    path: string[];\n    set: boolean;\n}',
+  },
   {
     name: 'SettingsUpdateSource',
     declaration: 'export type SettingsUpdateSource = \'update\' | \'provider\';',

+ 1 - 1
packages/host/apiproxy/package.json

@@ -51,7 +51,6 @@
     "@deepseek-ai/dsh-api-session-controller": "workspace:^",
     "@deepseek-ai/dsh-brand": "workspace:^",
     "@deepseek-ai/dsh-commands": "workspace:^",
-    "@deepseek-ai/dsh-credentials": "workspace:^",
     "@deepseek-ai/dsh-host-directory-picker": "workspace:^",
     "@deepseek-ai/dsh-llm": "workspace:^",
     "@deepseek-ai/dsh-native-command": "workspace:^",
@@ -74,6 +73,7 @@
   "devDependencies": {
     "@deepseek-ai/cordis": "workspace:^",
     "@deepseek-ai/dsh-agent-presets": "workspace:^",
+    "@deepseek-ai/dsh-credentials": "workspace:^",
     "@deepseek-ai/dsh-invariants": "workspace:^",
     "@deepseek-ai/dsh-typert-protocol": "workspace:^",
     "@deepseek-ai/dsh-typert-registry": "workspace:^"

+ 1 - 143
packages/host/apiproxy/src/api-proxy.ts

@@ -14,10 +14,7 @@ import {
   InvalidPresetIdError, PresetExistsError,
   PresetNotWritableError, UnknownPresetError,
 } from '@deepseek-ai/dsh-agent-presets'
-import type {
-  ApiProxy, ConfigurableProviderView, CredentialView,
-  SettingsNamespaceView,
-} from './api/index.ts'
+import type { ApiProxy, ConfigurableProviderView } from './api/index.ts'
 import { buildModelCatalog } from '@deepseek-ai/dsh-api-session-controller'
 import { SessionQueryError } from '@deepseek-ai/dsh-session-query'
 import {
@@ -33,12 +30,6 @@ import type { SessionRawArtifact } from '@deepseek-ai/dsh-session-persistence'
 // Type-only edges: resolve the command-change stream and `ctx.get('skills')`.
 import type {} from '@deepseek-ai/dsh-commands'
 import type {} from '@deepseek-ai/dsh-skill'
-// The settings/credentials seams: brand guards run at this wire boundary; the
-// service reads stay optional (`ctx.get`) so a composition without either
-// provider still serves every other domain.
-import { SettingsConflictError, settingsNamespace } from '@deepseek-ai/dsh-settings'
-import type { SettingsDescriptor, SettingsNamespace, SettingsPathOp } from '@deepseek-ai/dsh-settings'
-import { credentialRef } from '@deepseek-ai/dsh-credentials'
 import type { ScopeKey } from '@deepseek-ai/dsh-scope'
 import type { RpcError, RpcRequest, RpcResponse } from './api/rpc.ts'
 import { canOpenNativePath, openNativePath, openNativeTextFile } from './native-path-opener.ts'
@@ -187,79 +178,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
     return defaults.openPath !== undefined || canOpenNativePath()
   }
 
-  /** Missing-service report shared by the credentials domain. */
-  function credentialsAbsent(): RpcError {
-    return { code: 'internal', message: 'credentials service is absent: this deployment does not mount a credential provider (e.g. @deepseek-ai/dsh-credentials-local) in its composition', details: {} }
-  }
-
-  /** Map one redacted settings descriptor to its wire view. */
-  function namespaceView(descriptor: SettingsDescriptor): SettingsNamespaceView {
-    return {
-      ns: String(descriptor.ns),
-      schema: descriptor.schema,
-      value: descriptor.value,
-      ...descriptor.base === undefined ? {} : { base: descriptor.base },
-      ...descriptor.user === undefined ? {} : { user: descriptor.user },
-      applies: descriptor.applies,
-      secrets: (descriptor.secrets ?? []).map(secret => ({ path: [...secret.path], set: secret.set })),
-      revision: descriptor.revision,
-    }
-  }
 
-  /**
-   * Run one settings write (merge or wholesale replace) and acknowledge with
-   * the namespace's new redacted view. Every seam refusal — unknown or invalid
-   * namespace, read-only provider, schema validation, storage — becomes one
-   * `settings-rejected` carrying the seam's own message.
-   */
-  async function settingsWrite(
-    request: RpcRequest<unknown>,
-    ns: string,
-    mode: 'update' | 'replace' | 'mutate',
-    section: object,
-    expectedRevision?: number,
-  ): Promise<RpcResponse<SettingsNamespaceView>> {
-    const settings = ctx.get('settings')
-    if (settings === undefined) return err(request, settingsAbsent())
-    const rejected = (error: unknown): RpcResponse<SettingsNamespaceView> => {
-      // A stale writer is its own outcome, not a malformed request: the client
-      // must re-read and re-apply rather than treat the write as invalid.
-      if (error instanceof SettingsConflictError) {
-        return err(request, {
-          code: 'settings-conflict',
-          message: error.message,
-          details: { ns, expected: error.expected, actual: error.actual },
-        })
-      }
-      return err(request, {
-        code: 'settings-rejected',
-        message: error instanceof Error ? error.message : String(error),
-        details: { ns },
-      })
-    }
-    let branded: SettingsNamespace
-    try {
-      branded = settingsNamespace(ns)
-    } catch (error: unknown) {
-      // A malformed name can address no registration, so it fails exactly as
-      // an unregistered one does.
-      return rejected(error)
-    }
-    try {
-      if (mode === 'update') await settings.update(branded, section, expectedRevision)
-      else if (mode === 'replace') await settings.replace(branded, section, expectedRevision)
-      else await settings.mutate(branded, section as SettingsPathOp[], expectedRevision)
-    } catch (error: unknown) {
-      return rejected(error)
-    }
-    const descriptor = settings.describe({ redactSecrets: true }).find(candidate => candidate.ns === branded)
-    if (descriptor === undefined) {
-      // The write committed but the namespace vanished before this read: only
-      // a concurrent registrant disposal can produce it.
-      return err(request, { code: 'internal', message: `settings namespace "${ns}" was disposed after the ${mode}`, details: {} })
-    }
-    return ok(request, namespaceView(descriptor))
-  }
 
   return {
     host: {
@@ -383,15 +302,6 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
     },
 
     settings: {
-      describe(request) {
-        const settings = ctx.get('settings')
-        if (settings === undefined) return Promise.resolve(err(request, settingsAbsent()))
-        return Promise.resolve(ok(request, {
-          writable: settings.writable,
-          hasDocument: settings.documentPath !== undefined,
-          namespaces: settings.describe({ redactSecrets: true }).map(namespaceView),
-        }))
-      },
       async openDocument(request, signal) {
         const settings = ctx.get('settings')
         if (settings === undefined) return err(request, settingsAbsent())
@@ -435,58 +345,6 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
         }
         return openTextFile(request, path, signal)
       },
-      update: request => settingsWrite(request, request.payload.ns, 'update', request.payload.patch, request.payload.expectedRevision),
-      replace: request => settingsWrite(request, request.payload.ns, 'replace', request.payload.section, request.payload.expectedRevision),
-      mutate: request => settingsWrite(request, request.payload.ns, 'mutate', request.payload.ops, request.payload.expectedRevision),
-    },
-
-    credentials: {
-      async describe(request) {
-        const credentials = ctx.get('credentials')
-        if (credentials === undefined) return err(request, credentialsAbsent())
-        const entries = await Promise.all(request.payload.refs.map(async (ref) => {
-          const info = await credentials.describe(credentialRef(ref))
-          const view: CredentialView = {
-            configured: info.configured,
-            ...info.source === undefined ? {} : { source: info.source },
-            writable: info.writable,
-          }
-          return [ref, view] as const
-        }))
-        return ok(request, { credentials: Object.fromEntries(entries) })
-      },
-
-      async set(request) {
-        const credentials = ctx.get('credentials')
-        if (credentials === undefined) return err(request, credentialsAbsent())
-        const { ref, value } = request.payload
-        try {
-          await credentials.set(credentialRef(ref), value)
-        } catch (error: unknown) {
-          return err(request, {
-            code: 'credential-rejected',
-            message: error instanceof Error ? error.message : String(error),
-            details: { ref },
-          })
-        }
-        return ok(request, {})
-      },
-
-      async unset(request) {
-        const credentials = ctx.get('credentials')
-        if (credentials === undefined) return err(request, credentialsAbsent())
-        const { ref } = request.payload
-        try {
-          await credentials.unset(credentialRef(ref))
-        } catch (error: unknown) {
-          return err(request, {
-            code: 'credential-rejected',
-            message: error instanceof Error ? error.message : String(error),
-            details: { ref },
-          })
-        }
-        return ok(request, {})
-      },
     },
 
     llm: {

+ 0 - 48
packages/host/apiproxy/src/api/credentials.schema.ts

@@ -1,48 +0,0 @@
-/**
- * credentials domain zod schemas (names derived from map keys:
- * credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …).
- * The reference-name pattern mirrors the seam's `credentialRef` guard so an
- * invalid name fails as `bad-request` before reaching the service.
- */
-
-import { z } from 'zod'
-import type { RequestPayload, ResponseValue } from './rpc-map.ts'
-import type { Wire } from './rpc.schema.ts'
-import type { CredentialView } from './credentials.ts'
-
-/** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */
-export const credentialRefNameSchema = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/)
-
-/** CredentialView entry of credentials.describe. */
-export const credentialViewSchema = z.object({
-  configured: z.boolean(),
-  source: z.string().optional(),
-  writable: z.boolean(),
-}) satisfies z.ZodType<Wire<CredentialView>>
-
-/** credentials.describe request payload. */
-export const credentialsDescribeRequestSchema = z.object({
-  refs: z.array(credentialRefNameSchema).max(64),
-}) satisfies z.ZodType<Wire<RequestPayload<'credentials.describe'>>>
-
-/** credentials.describe response value. */
-export const credentialsDescribeValueSchema = z.object({
-  credentials: z.record(z.string(), credentialViewSchema),
-}) satisfies z.ZodType<Wire<ResponseValue<'credentials.describe'>>>
-
-/** credentials.set request payload: the one direction a value crosses this wire. */
-export const credentialsSetRequestSchema = z.object({
-  ref: credentialRefNameSchema,
-  value: z.string().min(1),
-}) satisfies z.ZodType<Wire<RequestPayload<'credentials.set'>>>
-
-/** credentials.set response value. */
-export const credentialsSetValueSchema = z.object({}) satisfies z.ZodType<Wire<ResponseValue<'credentials.set'>>>
-
-/** credentials.unset request payload. */
-export const credentialsUnsetRequestSchema = z.object({
-  ref: credentialRefNameSchema,
-}) satisfies z.ZodType<Wire<RequestPayload<'credentials.unset'>>>
-
-/** credentials.unset response value. */
-export const credentialsUnsetValueSchema = z.object({}) satisfies z.ZodType<Wire<ResponseValue<'credentials.unset'>>>

+ 0 - 44
packages/host/apiproxy/src/api/credentials.ts

@@ -1,44 +0,0 @@
-/**
- * credentials domain contract: the web face of the credential-reference seam
- * (`ctx.credentials`). Reads are structurally value-free — a credential view
- * carries configured/source/writable and has no slot for the value — and the
- * value crosses the wire in exactly one direction, inside `credentials.set`.
- * There is no enumeration method by design: clients learn which references
- * exist from settings schemas and values (`apiKeyEnv` fields).
- */
-
-import type { RpcRequest, RpcResponse } from './rpc.ts'
-
-/** Wire view of one credential reference's state. */
-export interface CredentialView {
-  /** Whether any layer currently supplies a non-empty value. */
-  configured: boolean
-  /** Winning layer when configured (`env`, `file`, …); provider vocabulary. */
-  source?: string
-  /** Whether `credentials.set`/`credentials.unset` can affect this reference. */
-  writable: boolean
-}
-
-/** Credentials-domain unary methods (the map keys credentials.* of RpcMethodMap). */
-export interface CredentialsApi {
-  /**
-   * Describe the named references (batch): configured state, winning source,
-   * and writability — never values. An invalid reference name is a
-   * `bad-request`; an unknown-but-valid one describes as unconfigured.
-   */
-  describe(request: RpcRequest<{ refs: string[] }>): Promise<RpcResponse<{ credentials: Record<string, CredentialView> }>>
-
-  /**
-   * Store one credential value in the writable layer. Rejected with
-   * `credential-rejected` while a read-only layer (the live environment)
-   * shadows the reference — the write would otherwise appear to succeed while
-   * resolution keeps returning the shadowing value.
-   */
-  set(request: RpcRequest<{ ref: string; value: string }>): Promise<RpcResponse<{}>>
-
-  /**
-   * Remove one credential from the writable layer; same shadowing rejection
-   * as `set`. Unsetting an absent reference succeeds (idempotent).
-   */
-  unset(request: RpcRequest<{ ref: string }>): Promise<RpcResponse<{}>>
-}

+ 1 - 4
packages/host/apiproxy/src/api/index.ts

@@ -8,7 +8,6 @@ import type { HostApi } from './host.ts'
 import type { AgentPresetsApi } from './agent-presets.ts'
 import type { SkillsApi } from './skills.ts'
 import type { SettingsApi } from './settings.ts'
-import type { CredentialsApi } from './credentials.ts'
 import type { LlmApi } from './llm.ts'
 import type { DownloadsApi } from './downloads.ts'
 
@@ -18,7 +17,6 @@ export interface ApiProxy {
   skills: SkillsApi
   agentPresets: AgentPresetsApi
   settings: SettingsApi
-  credentials: CredentialsApi
   llm: LlmApi
   /** Host-only download surfaces (GET, no wire envelope); absent from IApiClient. */
   downloads: DownloadsApi
@@ -32,8 +30,7 @@ export type {
 export type { HostApi } from './host.ts'
 export type { SkillsApi, SkillEntry } from './skills.ts'
 export type { AgentPresetsApi } from './agent-presets.ts'
-export type { SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView } from './settings.ts'
-export type { CredentialsApi, CredentialView } from './credentials.ts'
+export type { SettingsApi } from './settings.ts'
 export type { ConfigurableProviderView, DiscoveredModelView, LlmApi } from './llm.ts'
 export type { DownloadsApi } from './downloads.ts'
 

+ 1 - 1
packages/host/apiproxy/src/api/llm.schema.ts

@@ -103,7 +103,7 @@ export const llmDiscoverModelsRequestSchema = z.object({
   api: z.string().min(1).optional(),
   // Write-only at the host: used for this one interrogation, never stored and
   // never returned. It does ride the client's outgoing envelope like every
-  // other secret-bearing payload (`credentials.set`, `settings.update`), which
+  // other secret-bearing payload (`settings/update`), which
   // `subscribeEnvelopes()` observers can see — redacting that tap is a
   // configuration-plane-wide change, not this method's to make alone.
   apiKey: z.string().min(1).optional(),

+ 0 - 8
packages/host/apiproxy/src/api/rpc-map.ts

@@ -7,7 +7,6 @@ import type { HostApi } from './host.ts'
 import type { AgentPresetsApi } from './agent-presets.ts'
 import type { SkillsApi } from './skills.ts'
 import type { SettingsApi } from './settings.ts'
-import type { CredentialsApi } from './credentials.ts'
 import type { LlmApi } from './llm.ts'
 import type { RpcResponse } from './rpc.ts'
 
@@ -21,14 +20,7 @@ export interface RpcMethodMap {
   'host.openPath': HostApi['openPath']
   'skill.list': SkillsApi['list']
   'agentPreset.openDocument': AgentPresetsApi['openDocument']
-  'settings.describe': SettingsApi['describe']
   'settings.openDocument': SettingsApi['openDocument']
-  'settings.update': SettingsApi['update']
-  'settings.replace': SettingsApi['replace']
-  'settings.mutate': SettingsApi['mutate']
-  'credentials.describe': CredentialsApi['describe']
-  'credentials.set': CredentialsApi['set']
-  'credentials.unset': CredentialsApi['unset']
   'llm.providers': LlmApi['providers']
   'llm.models': LlmApi['models']
   'llm.discoverModels': LlmApi['discoverModels']

+ 0 - 3
packages/host/apiproxy/src/api/rpc.schema.ts

@@ -41,9 +41,6 @@ export const rpcErrorSchema: z.ZodType<RpcError> = z.discriminatedUnion('code',
   z.object({ code: z.literal('agent-preset-not-found'), message: z.string(), details: z.object({ agentPreset: z.string(), available: z.array(z.string()) }) }),
   z.object({ code: z.literal('agent-preset-invalid'), message: z.string(), details: z.object({ agentPreset: z.string(), reason: z.string() }) }),
   z.object({ code: z.literal('agent-busy'), message: z.string(), details: z.object({ reason: z.string() }) }),
-  z.object({ code: z.literal('settings-rejected'), message: z.string(), details: z.object({ ns: z.string() }) }),
-  z.object({ code: z.literal('settings-conflict'), message: z.string(), details: z.object({ ns: z.string(), expected: z.number(), actual: z.number() }) }),
-  z.object({ code: z.literal('credential-rejected'), message: z.string(), details: z.object({ ref: z.string() }) }),
   z.object({ code: z.literal('model-discovery-failed'), message: z.string(), details: z.object({ settingsNs: z.string(), baseURL: z.string().optional() }) }),
   z.object({ code: z.literal('internal'), message: z.string(), details: z.object({}) }),
 ]) as unknown as z.ZodType<RpcError>

+ 0 - 13
packages/host/apiproxy/src/api/rpc.ts

@@ -36,19 +36,6 @@ export interface RpcErrorDetailsMap {
   'agent-preset-not-found': { agentPreset: string; available: readonly string[] }
   'agent-preset-invalid': { agentPreset: string; reason: string }
   'agent-busy': { reason: string }
-  /**
-   * A settings write was refused (schema validation, unknown namespace,
-   * read-only provider, or storage failure); the message is the seam's text.
-   */
-  'settings-rejected': { ns: string }
-  /**
-   * A settings write carried an `expectedRevision` the namespace has already
-   * moved past: another writer (tab, editor, or an external file edit) landed
-   * first. The details carry both revisions so a client can re-read and retry.
-   */
-  'settings-conflict': { ns: string; expected: number; actual: number }
-  /** A credential write was refused (read-only shadowing layer or storage failure); the message is the seam's own text. */
-  'credential-rejected': { ref: string }
   /**
    * Interrogating a draft provider endpoint did not produce a model listing:
    * no adapter family serves the namespace, the protocol has no listing this

+ 2 - 67
packages/host/apiproxy/src/api/settings.schema.ts

@@ -1,40 +1,11 @@
 /**
- * settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema /
- * settingsDescribeValueSchema / settingsUpdate* / settingsReplace*).
+ * settings domain zod schemas (names derived from map keys:
+ * settingsOpenDocumentRequestSchema / settingsOpenDocumentValueSchema).
  */
 
 import { z } from 'zod'
 import type { RequestPayload, ResponseValue } from './rpc-map.ts'
 import type { Wire } from './rpc.schema.ts'
-import type { SettingsNamespaceView, SettingsPathOpView, SettingsSecretView } from './settings.ts'
-
-/** One redacted secret slot. */
-export const settingsSecretViewSchema = z.object({
-  path: z.array(z.string()),
-  set: z.boolean(),
-}) satisfies z.ZodType<Wire<SettingsSecretView>>
-
-/** SettingsNamespaceView row of settings.describe and the write responses. */
-export const settingsNamespaceViewSchema = z.object({
-  ns: z.string().min(1),
-  schema: z.unknown(),
-  value: z.unknown(),
-  base: z.unknown().optional(),
-  user: z.unknown().optional(),
-  applies: z.union([z.literal('live'), z.literal('restart')]),
-  secrets: z.array(settingsSecretViewSchema),
-  revision: z.number(),
-}) satisfies z.ZodType<Wire<SettingsNamespaceView>>
-
-/** settings.describe request payload. */
-export const settingsDescribeRequestSchema = z.object({}) satisfies z.ZodType<Wire<RequestPayload<'settings.describe'>>>
-
-/** settings.describe response value. */
-export const settingsDescribeValueSchema = z.object({
-  writable: z.boolean(),
-  hasDocument: z.boolean(),
-  namespaces: z.array(settingsNamespaceViewSchema),
-}) satisfies z.ZodType<Wire<ResponseValue<'settings.describe'>>>
 
 /** settings.openDocument request payload. */
 export const settingsOpenDocumentRequestSchema = z.object({}) satisfies z.ZodType<Wire<RequestPayload<'settings.openDocument'>>>
@@ -43,39 +14,3 @@ export const settingsOpenDocumentRequestSchema = z.object({}) satisfies z.ZodTyp
 export const settingsOpenDocumentValueSchema = z.object({
   opened: z.literal(true),
 }) satisfies z.ZodType<Wire<ResponseValue<'settings.openDocument'>>>
-
-/** settings.update request payload. */
-export const settingsUpdateRequestSchema = z.object({
-  ns: z.string().min(1),
-  patch: z.record(z.string(), z.unknown()),
-  expectedRevision: z.number().optional(),
-}) satisfies z.ZodType<Wire<RequestPayload<'settings.update'>>>
-
-/** settings.update response value: the namespace's new redacted view. */
-export const settingsUpdateValueSchema = settingsNamespaceViewSchema satisfies z.ZodType<Wire<ResponseValue<'settings.update'>>>
-
-/** settings.replace request payload. */
-export const settingsReplaceRequestSchema = z.object({
-  ns: z.string().min(1),
-  section: z.record(z.string(), z.unknown()),
-  expectedRevision: z.number().optional(),
-}) satisfies z.ZodType<Wire<RequestPayload<'settings.replace'>>>
-
-/** One path-addressed edit of settings.mutate. */
-export const settingsPathOpSchema = z.discriminatedUnion('op', [
-  z.object({ op: z.literal('set'), path: z.array(z.string()), value: z.unknown() }),
-  z.object({ op: z.literal('unset'), path: z.array(z.string()) }),
-]) as unknown as z.ZodType<Wire<SettingsPathOpView>>
-
-/** settings.mutate request payload. */
-export const settingsMutateRequestSchema = z.object({
-  ns: z.string().min(1),
-  ops: z.array(settingsPathOpSchema),
-  expectedRevision: z.number().optional(),
-}) satisfies z.ZodType<Wire<RequestPayload<'settings.mutate'>>>
-
-/** settings.mutate response value: the namespace's new redacted view. */
-export const settingsMutateValueSchema = settingsNamespaceViewSchema satisfies z.ZodType<Wire<ResponseValue<'settings.mutate'>>>
-
-/** settings.replace response value. */
-export const settingsReplaceValueSchema = settingsNamespaceViewSchema satisfies z.ZodType<Wire<ResponseValue<'settings.replace'>>>

+ 5 - 89
packages/host/apiproxy/src/api/settings.ts

@@ -1,69 +1,15 @@
 /**
- * settings domain contract: the web face of the user-settings seam
- * (`ctx.settings`). Every payload that leaves this domain is redacted by the
- * seam (`describe({ redactSecrets: true })` semantics): `role('secret')`
- * fields never ride a response in any layer, and the `secrets` slot list is
- * how a form learns a write-only field exists and whether it is configured.
+ * settings domain contract: what remains of the web face of the user-settings
+ * seam (`ctx.settings`) once the redacted read and the path-addressed write
+ * moved to the `settings` Remote namespace. Only the local-document handoff
+ * stays here, because opening a Host file is a platform action rather than a
+ * settings read.
  */
 
 import type { RpcRequest, RpcResponse } from './rpc.ts'
 
-/** One schema-declared secret slot inside a redacted namespace value. */
-export interface SettingsSecretView {
-  /** Path from the section root to the removed field. */
-  path: string[]
-  /** Whether the slot currently holds a value (the value itself never rides). */
-  set: boolean
-}
-
-/** Wire view of one registered settings namespace. */
-export interface SettingsNamespaceView {
-  /** Namespace key (`llm-deepseek`, `llm-pi-ai`, …). */
-  ns: string
-  /** Serialized schemastery schema envelope (`schema.toJSON()`); rehydrate with `new Schema(json)`. */
-  schema: unknown
-  /** Redacted resolved value (schema defaults → composition base → user layer). */
-  value: unknown
-  /** Redacted composition base layer, when the registrant declared one. */
-  base?: unknown
-  /** Redacted raw user section, when one exists; a field's presence here marks it user-overridden. */
-  user?: unknown
-  /** When the owner applies changes. */
-  applies: 'live' | 'restart'
-  /** Every schema-declared secret slot with its configured state. */
-  secrets: SettingsSecretView[]
-  /**
-   * Monotonic revision of the raw user section this view was read at. Send it
-   * back as `expectedRevision` on a write so a stale editor is refused rather
-   * than silently overwriting a concurrent change.
-   */
-  revision: number
-}
-
-/**
- * One path-addressed edit carried by `settings.mutate`. `set` writes the
- * value at the path (creating intermediate objects); `unset` removes it. The
- * empty path addresses the section root.
- */
-export type SettingsPathOpView =
-  | { op: 'set'; path: string[]; value: unknown }
-  | { op: 'unset'; path: string[] }
-
 /** Settings-domain unary methods (the map keys settings.* of RpcMethodMap). */
 export interface SettingsApi {
-  /**
-   * Describe every registered namespace: redacted layered values plus the
-   * serialized schema a client renders its form from. `hasDocument` reports
-   * whether a file-backed provider owns a local document without exposing its
-   * Host path. Connection requires the browser session used by every Host API
-   * method; `writable: false` tells the client to disable every write control.
-   */
-  describe(request: RpcRequest<{}>): Promise<RpcResponse<{
-    writable: boolean
-    hasDocument: boolean
-    namespaces: SettingsNamespaceView[]
-  }>>
-
   /**
    * Materialize the configured local document when absent and ask the Host to
    * hand it to the platform text-document opener. macOS forces a text editor;
@@ -73,34 +19,4 @@ export interface SettingsApi {
   openDocument(
     request: RpcRequest<{}>, signal: AbortSignal,
   ): Promise<RpcResponse<{ opened: true }>>
-
-  /**
-   * Merge a patch into one namespace's user layer (validate → persist →
-   * commit). Secret-role fields may be INCLUDED in the patch (write-only
-   * direction); a form that leaves a secret untouched simply omits it and the
-   * merge preserves the stored value. Responds with the namespace's new
-   * redacted view; a schema or storage rejection is `settings-rejected`.
-   */
-  update(request: RpcRequest<{ ns: string; patch: object; expectedRevision?: number }>): Promise<RpcResponse<SettingsNamespaceView>>
-
-  /**
-   * Replace one namespace's user section wholesale — the removal/reset path a
-   * merge cannot express (`section: {}` resets to composition defaults). Keys
-   * absent from `section` are dropped, secrets included: a client must first
-   * fold the descriptor's `user` layer (and re-supply any secret it wants to
-   * keep) or accept the reset.
-   */
-  replace(request: RpcRequest<{ ns: string; section: object; expectedRevision?: number }>): Promise<RpcResponse<SettingsNamespaceView>>
-
-  /**
-   * Apply path-addressed edits to one namespace's user section, resolved
-   * against the section as stored — NOT against whatever the caller last
-   * read. This is the removal path for any client holding the redacted
-   * descriptor: it names the field it means, so a secret the wire never
-   * returned cannot be deleted as a side effect. `replace` remains the
-   * deliberate wholesale reset.
-   */
-  mutate(
-    request: RpcRequest<{ ns: string; ops: SettingsPathOpView[]; expectedRevision?: number }>,
-  ): Promise<RpcResponse<SettingsNamespaceView>>
 }

+ 1 - 31
packages/host/apiproxy/src/fetch/client.ts

@@ -20,12 +20,8 @@ import {
   agentPresetOpenDocumentValueSchema,
 } from '../api/agent-presets.schema.ts'
 import {
-  settingsDescribeValueSchema, settingsMutateValueSchema, settingsOpenDocumentValueSchema,
-  settingsReplaceValueSchema, settingsUpdateValueSchema,
+  settingsOpenDocumentValueSchema,
 } from '../api/settings.schema.ts'
-import {
-  credentialsDescribeValueSchema, credentialsSetValueSchema, credentialsUnsetValueSchema,
-} from '../api/credentials.schema.ts'
 import { llmDiscoverModelsValueSchema, llmModelsValueSchema, llmProvidersValueSchema } from '../api/llm.schema.ts'
 
 /**
@@ -52,16 +48,7 @@ export interface IApiClient {
     openDocument(payload: RequestPayload<'agentPreset.openDocument'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'agentPreset.openDocument'>>>
   }
   settings: {
-    describe(payload: RequestPayload<'settings.describe'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'settings.describe'>>>
     openDocument(payload: RequestPayload<'settings.openDocument'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'settings.openDocument'>>>
-    update(payload: RequestPayload<'settings.update'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'settings.update'>>>
-    replace(payload: RequestPayload<'settings.replace'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'settings.replace'>>>
-    mutate(payload: RequestPayload<'settings.mutate'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'settings.mutate'>>>
-  }
-  credentials: {
-    describe(payload: RequestPayload<'credentials.describe'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'credentials.describe'>>>
-    set(payload: RequestPayload<'credentials.set'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'credentials.set'>>>
-    unset(payload: RequestPayload<'credentials.unset'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'credentials.unset'>>>
   }
   llm: {
     providers(payload: RequestPayload<'llm.providers'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'llm.providers'>>>
@@ -79,14 +66,7 @@ const UNARY_VALUE_SCHEMAS: { [K in keyof RpcMethodMap]: z.ZodType<Wire<ResponseV
   'host.openPath': hostOpenPathValueSchema,
   'skill.list': skillListValueSchema,
   'agentPreset.openDocument': agentPresetOpenDocumentValueSchema,
-  'settings.describe': settingsDescribeValueSchema,
   'settings.openDocument': settingsOpenDocumentValueSchema,
-  'settings.update': settingsUpdateValueSchema,
-  'settings.replace': settingsReplaceValueSchema,
-  'settings.mutate': settingsMutateValueSchema,
-  'credentials.describe': credentialsDescribeValueSchema,
-  'credentials.set': credentialsSetValueSchema,
-  'credentials.unset': credentialsUnsetValueSchema,
   'llm.providers': llmProvidersValueSchema,
   'llm.models': llmModelsValueSchema,
   'llm.discoverModels': llmDiscoverModelsValueSchema,
@@ -232,17 +212,7 @@ export abstract class AbstractApiClient implements IApiClient {
   }
 
   readonly settings: IApiClient['settings'] = {
-    describe: (payload, signal) => this.callUnary('settings.describe', payload, signal),
     openDocument: (payload, signal) => this.callUnary('settings.openDocument', payload, signal),
-    update: (payload, signal) => this.callUnary('settings.update', payload, signal),
-    replace: (payload, signal) => this.callUnary('settings.replace', payload, signal),
-    mutate: (payload, signal) => this.callUnary('settings.mutate', payload, signal),
-  }
-
-  readonly credentials: IApiClient['credentials'] = {
-    describe: (payload, signal) => this.callUnary('credentials.describe', payload, signal),
-    set: (payload, signal) => this.callUnary('credentials.set', payload, signal),
-    unset: (payload, signal) => this.callUnary('credentials.unset', payload, signal),
   }
 
   readonly llm: IApiClient['llm'] = {

+ 1 - 12
packages/host/apiproxy/src/fetch/handler.ts

@@ -22,12 +22,8 @@ import {
   agentPresetOpenDocumentRequestSchema,
 } from '../api/agent-presets.schema.ts'
 import {
-  settingsDescribeRequestSchema, settingsMutateRequestSchema, settingsOpenDocumentRequestSchema,
-  settingsReplaceRequestSchema, settingsUpdateRequestSchema,
+  settingsOpenDocumentRequestSchema,
 } from '../api/settings.schema.ts'
-import {
-  credentialsDescribeRequestSchema, credentialsSetRequestSchema, credentialsUnsetRequestSchema,
-} from '../api/credentials.schema.ts'
 import { llmDiscoverModelsRequestSchema, llmModelsRequestSchema, llmProvidersRequestSchema } from '../api/llm.schema.ts'
 
 /**
@@ -51,14 +47,7 @@ const UNARY_ROUTES: UnaryRoutes = {
   'host.openPath': { schema: hostOpenPathRequestSchema, invoke: (api, r, signal) => api.host.openPath(r, signal) },
   'skill.list': { schema: skillListRequestSchema, invoke: (api, r) => api.skills.list(r) },
   'agentPreset.openDocument': { schema: agentPresetOpenDocumentRequestSchema, invoke: (api, r, signal) => api.agentPresets.openDocument(r, signal) },
-  'settings.describe': { schema: settingsDescribeRequestSchema, invoke: (api, r) => api.settings.describe(r) },
   'settings.openDocument': { schema: settingsOpenDocumentRequestSchema, invoke: (api, r, signal) => api.settings.openDocument(r, signal) },
-  'settings.update': { schema: settingsUpdateRequestSchema, invoke: (api, r) => api.settings.update(r) },
-  'settings.replace': { schema: settingsReplaceRequestSchema, invoke: (api, r) => api.settings.replace(r) },
-  'settings.mutate': { schema: settingsMutateRequestSchema, invoke: (api, r) => api.settings.mutate(r) },
-  'credentials.describe': { schema: credentialsDescribeRequestSchema, invoke: (api, r) => api.credentials.describe(r) },
-  'credentials.set': { schema: credentialsSetRequestSchema, invoke: (api, r) => api.credentials.set(r) },
-  'credentials.unset': { schema: credentialsUnsetRequestSchema, invoke: (api, r) => api.credentials.unset(r) },
   'llm.providers': { schema: llmProvidersRequestSchema, invoke: (api, r) => api.llm.providers(r) },
   'llm.models': { schema: llmModelsRequestSchema, invoke: (api, r) => api.llm.models(r) },
   'llm.discoverModels': { schema: llmDiscoverModelsRequestSchema, invoke: (api, r, signal) => api.llm.discoverModels(r, signal) },

+ 0 - 2
packages/host/apiproxy/src/index.ts

@@ -77,7 +77,6 @@ export class ApiProxyService extends Service implements ApiProxy {
   readonly skills: ApiProxy['skills']
   readonly agentPresets: ApiProxy['agentPresets']
   readonly settings: ApiProxy['settings']
-  readonly credentials: ApiProxy['credentials']
   readonly llm: ApiProxy['llm']
   readonly downloads: ApiProxy['downloads']
 
@@ -95,7 +94,6 @@ export class ApiProxyService extends Service implements ApiProxy {
     this.skills = api.skills
     this.agentPresets = api.agentPresets
     this.settings = api.settings
-    this.credentials = api.credentials
     this.llm = api.llm
     this.downloads = api.downloads
   }

+ 8 - 281
packages/host/apiproxy/tests/api-proxy-config.spec.ts

@@ -1,8 +1,7 @@
 /**
- * Settings/credentials/llm RPC domains and their owner events over
- * createApiProxy: layered redacted describe, write-path rejection mapping,
- * value-free credential views, the directory/live-route merge, and the three
- * invalidation frames (settings/credentials/models changed).
+ * Settings and llm RPC domains and their owner events over createApiProxy:
+ * layered redacted describe, write-path rejection mapping, the
+ * directory/live-route merge, and the settings and model invalidation frames.
  */
 
 import { describe, expect, it, vi } from 'vitest'
@@ -240,18 +239,6 @@ async function captureSettingsUpdates(
   }
 }
 
-/** Observe credential commits while one API operation runs. */
-async function captureCredentialUpdates(ctx: Context, run: () => Promise<void>): Promise<CredentialRef[]> {
-  const updates: CredentialRef[] = []
-  const dispose = ctx.on('credentials/reference-updated', (ref) => { updates.push(ref) })
-  try {
-    await run()
-    return updates
-  } finally {
-    dispose()
-  }
-}
-
 /** Count model-adapter topology commits while one API operation runs. */
 async function countAdapterUpdates(ctx: Context, run: () => Promise<void>): Promise<number> {
   let updates = 0
@@ -273,32 +260,11 @@ describe('settings domain', () => {
   it('reports an actionable error when no settings provider is mounted', async () => {
     const ctx = await harness({ settings: false })
     const api = createApiProxy(ctx, DEFAULTS)
-    const error = expectErr(await api.settings.describe(request({})))
+    const error = expectErr(await api.settings.openDocument(request({}), new AbortController().signal))
     expect(error.code).toBe('internal')
     expect(error.message).toContain('dsh-settings-file')
   })
 
-  it('describes layered redacted namespaces with their secret slots', async () => {
-    const ctx = await harness({ settings: {
-      doc: { 'llm-deepseek': { apiKey: 'user-secret', baseURL: 'https://user' } },
-      documentPath: '/tmp/custom-settings.yaml',
-    } })
-    ctx.settings.register(NS, AdapterConfig, { base: { baseURL: 'https://base' } })
-    const api = createApiProxy(ctx, DEFAULTS)
-    const value = expectOk(await api.settings.describe(request({})))
-    expect(value.writable).toBe(true)
-    expect(value.hasDocument).toBe(true)
-    expect(value.namespaces).toHaveLength(1)
-    const view = value.namespaces[0]!
-    expect(view.ns).toBe('llm-deepseek')
-    expect(view.applies).toBe('live')
-    expect((view.schema as { refs?: unknown }).refs).toBeDefined()
-    expect(view.value).toEqual({ apiKeyEnv: 'DEEPSEEK_API_KEY', baseURL: 'https://user' })
-    expect(view.base).toEqual({ baseURL: 'https://base' })
-    expect(view.user).toEqual({ baseURL: 'https://user' })
-    expect(view.secrets).toEqual([{ path: ['apiKey'], set: true }])
-    expect(JSON.stringify(value)).not.toContain('user-secret')
-  })
 
   it('opens the provider-resolved document without accepting a browser path', async () => {
     const ctx = await harness({ settings: {
@@ -322,7 +288,7 @@ describe('settings domain', () => {
   it('refuses to open settings when the provider has no local document', async () => {
     const ctx = await harness()
     const api = createApiProxy(ctx, DEFAULTS)
-    expect(expectOk(await api.settings.describe(request({}))).hasDocument).toBe(false)
+    expect(ctx.settings.documentPath).toBeUndefined()
     const error = expectErr(await api.settings.openDocument(request({}), new AbortController().signal))
     expect(error.code).toBe('internal')
     expect(error.message).toContain('no local document')
@@ -356,141 +322,9 @@ describe('settings domain', () => {
     expect(opened).toEqual([])
   })
 
-  it('serves every registered namespace, including one this repository never named', async () => {
-    // Registering IS the exposure: a plugin distributed outside this
-    // repository configures itself from the browser without a change here.
-    // The plane stays browser-authenticated and secret-redacted, and which
-    // surface renders a namespace is the browser's decision, not this proxy's.
-    const ctx = await harness()
-    ctx.settings.register(NS, AdapterConfig)
-    ctx.settings.register(settingsNamespace('some-other-plugin'), z.object({ secretPath: z.string() }))
-    ctx.settings.register(settingsNamespace('permission'), z.object({
-      defaultPreset: z.union(['read-only', 'workspace-write']).required(),
-    }), {
-      base: { defaultPreset: 'read-only' },
-    })
-    ctx.settings.register(settingsNamespace('ui-theme'), z.object({
-      preference: z.union(['light', 'dark', 'system']).default('system'),
-    }))
-    ctx.settings.register(settingsNamespace('locale'), z.object({
-      preference: z.union(['zh', 'en']).required(false),
-    }))
-    ctx.settings.register(settingsNamespace('ui-conversation'), z.object({
-      busyEnter: z.union(['queue', 'steer']).default('queue'),
-    }))
-    ctx.settings.register(settingsNamespace('shell'), z.object({
-      timeoutMs: z.number().default(120_000),
-    }))
-    ctx.settings.register(settingsNamespace('agent-loop'), z.object({
-      maxParallelToolCalls: z.number().default(10),
-    }))
-    ctx.settings.register(settingsNamespace('web-search-deepseek'), z.object({
-      baseURL: z.string(),
-    }))
-    const api = createApiProxy(ctx, DEFAULTS)
-
-    const value = expectOk(await api.settings.describe(request({})))
-    expect(value.namespaces.map(view => view.ns)).toEqual([
-      'llm-deepseek', 'some-other-plugin', 'permission', 'ui-theme', 'locale',
-      'ui-conversation', 'shell', 'agent-loop', 'web-search-deepseek',
-    ])
-    const permission = expectOk(await api.settings.mutate(request({
-      ns: 'permission',
-      ops: [{ op: 'set', path: ['defaultPreset'], value: 'workspace-write' }],
-    })))
-    expect(permission.value).toEqual({ defaultPreset: 'workspace-write' })
-    const theme = expectOk(await api.settings.mutate(request({
-      ns: 'ui-theme',
-      ops: [{ op: 'set', path: ['preference'], value: 'dark' }],
-    })))
-    expect(theme.value).toEqual({ preference: 'dark' })
-    const locale = expectOk(await api.settings.mutate(request({
-      ns: 'locale',
-      ops: [{ op: 'set', path: ['preference'], value: 'en' }],
-    })))
-    expect(locale.value).toEqual({ preference: 'en' })
-    const conversation = expectOk(await api.settings.mutate(request({
-      ns: 'ui-conversation',
-      ops: [{ op: 'set', path: ['busyEnter'], value: 'steer' }],
-    })))
-    expect(conversation.value).toEqual({ busyEnter: 'steer' })
-    const bash = expectOk(await api.settings.mutate(request({
-      ns: 'shell',
-      ops: [{ op: 'set', path: ['timeoutMs'], value: 5_000 }],
-    })))
-    expect(bash.value).toEqual({ timeoutMs: 5_000 })
-    const agentLoop = expectOk(await api.settings.mutate(request({
-      ns: 'agent-loop',
-      ops: [{ op: 'set', path: ['maxParallelToolCalls'], value: 2 }],
-    })))
-    expect(agentLoop.value).toEqual({ maxParallelToolCalls: 2 })
-    const webSearch = expectOk(await api.settings.mutate(request({
-      ns: 'web-search-deepseek',
-      ops: [{ op: 'set', path: ['baseURL'], value: 'https://search.test/v1' }],
-    })))
-    expect(webSearch.value).toEqual({ baseURL: 'https://search.test/v1' })
-
-    const other = expectOk(await api.settings.update(request({
-      ns: 'some-other-plugin',
-      patch: { secretPath: '/etc/shadow' },
-    })))
-    expect(other.value).toEqual({ secretPath: '/etc/shadow' })
-    expect(ctx.settings.describe().find(d => String(d.ns) === 'some-other-plugin')?.value)
-      .toEqual({ secretPath: '/etc/shadow' })
-  })
-
-  it('serves product preference namespaces without invalidating the model catalog', async () => {
-    const ctx = await harness()
-    ctx.settings.register(settingsNamespace('ui-onboarding'), z.object({ welcomeNoticeVersion: z.string() }))
-    ctx.settings.register(settingsNamespace('ui-theme'), z.object({
-      preference: z.union(['light', 'dark', 'system']).default('system'),
-    }))
-    const api = createApiProxy(ctx, DEFAULTS)
-    expect(expectOk(await api.settings.describe(request({}))).namespaces.map(view => view.ns))
-      .toEqual(['ui-onboarding', 'ui-theme'])
-    const updates = await captureSettingsUpdates(ctx, async () => {
-      expectOk(await api.settings.mutate(request({
-        ns: 'ui-onboarding',
-        ops: [{ op: 'set', path: ['welcomeNoticeVersion'], value: 'v1' }],
-      })))
-      expectOk(await api.settings.mutate(request({
-        ns: 'ui-theme',
-        ops: [{ op: 'set', path: ['preference'], value: 'dark' }],
-      })))
-    })
-    expect(updates).toEqual([
-      expectedSettingsUpdate('ui-onboarding'),
-      expectedSettingsUpdate('ui-theme'),
-    ])
-  })
-
-  it('serves the agent-preset namespace, so a browser preset picker can persist its choice', async () => {
-    const ctx = await harness()
-    ctx.settings.register(settingsNamespace('agent-presets'), z.object({ default: z.string() }))
-    const api = createApiProxy(ctx, DEFAULTS)
 
-    expectOk(await api.settings.update(request({ ns: 'agent-presets', patch: { default: 'minimal' } })))
 
-    // Both browser surfaces that offer the choice — the General row and the
-    // management section — write the default through `settings.update`, so a
-    // namespace outside this boundary makes the picker move and then silently
-    // forget, which is worse than refusing the control.
-    expect(ctx.settings.describe().find(view => String(view.ns) === 'agent-presets')?.value)
-      .toEqual({ default: 'minimal' })
-  })
 
-  it('keeps serving a provider namespace whose directory entry is gone', async () => {
-    // The configurable-provider directory says what the Models page can offer,
-    // not what a user may configure: a dormant route's stored section is still
-    // theirs to edit, and losing the entry must not strand it.
-    const ctx = await harness({ configurableProviders: false })
-    ctx.settings.register(NS, AdapterConfig)
-    const api = createApiProxy(ctx, DEFAULTS)
-    expect(expectOk(await api.settings.describe(request({}))).namespaces.map(view => view.ns))
-      .toEqual(['llm-deepseek'])
-    expect(expectOk(await api.settings.update(request({ ns: 'llm-deepseek', patch: { baseURL: 'https://x' } }))).value)
-      .toMatchObject({ baseURL: 'https://x' })
-  })
 
   it('forwards a provider settings change for model-catalog consumers', async () => {
     // Editing `models` changes no route, so llm/adapters-updated never fires
@@ -500,13 +334,12 @@ describe('settings domain', () => {
     // overridden.
     const ctx = await harness()
     ctx.settings.register(NS, AdapterConfig, { base: { baseURL: 'https://base' } })
-    const api = createApiProxy(ctx, DEFAULTS)
     const updates = await captureSettingsUpdates(ctx, async () => {
-      await api.settings.update(request({ ns: 'llm-deepseek', patch: { baseURL: 'https://base' } }))
+      await ctx.settings.update(settingsNamespace('llm-deepseek'), { baseURL: 'https://base' })
     })
     expect(updates).toEqual([expectedSettingsUpdate('llm-deepseek')])
     // The resolved value never moved: base already said https://base.
-    expect(expectOk(await api.settings.describe(request({}))).namespaces[0]!.value)
+    expect(ctx.settings.describe().find(view => String(view.ns) === 'llm-deepseek')?.value)
       .toEqual({ apiKeyEnv: 'DEEPSEEK_API_KEY', baseURL: 'https://base' })
   })
 
@@ -538,116 +371,11 @@ describe('settings domain', () => {
     expect(updates).toEqual([expectedSettingsUpdate('agent-default-model')])
   })
 
-  it('maps a stale expectedRevision to settings-conflict carrying both revisions', async () => {
-    const ctx = await harness()
-    ctx.settings.register(NS, AdapterConfig)
-    const api = createApiProxy(ctx, DEFAULTS)
-    const opened = expectOk(await api.settings.describe(request({}))).namespaces[0]!.revision
-    expect(expectOk(await api.settings.update(request({ ns: 'llm-deepseek', patch: { baseURL: 'https://first' }, expectedRevision: opened })))
-      .revision).toBe(opened + 1)
-    const error = expectErr(await api.settings.update(request({ ns: 'llm-deepseek', patch: { baseURL: 'https://second' }, expectedRevision: opened })))
-    expect(error.code).toBe('settings-conflict')
-    expect(error.details).toEqual({ ns: 'llm-deepseek', expected: opened, actual: opened + 1 })
-    // The refused write changed nothing.
-    expect(expectOk(await api.settings.describe(request({}))).namespaces[0]!.user).toEqual({ baseURL: 'https://first' })
-  })
-
-  it('updates the user layer, answers with the new redacted view, and broadcasts the frame', async () => {
-    const ctx = await harness()
-    ctx.settings.register(NS, AdapterConfig, { base: { baseURL: 'https://base' } })
-    const api = createApiProxy(ctx, DEFAULTS)
-    const updates = await captureSettingsUpdates(ctx, async () => {
-      const view = expectOk(await api.settings.update(request({ ns: 'llm-deepseek', patch: { apiKey: 'sk-new', baseURL: 'https://next' } })))
-      expect(view.value).toEqual({ apiKeyEnv: 'DEEPSEEK_API_KEY', baseURL: 'https://next' })
-      expect(view.user).toEqual({ baseURL: 'https://next' })
-      expect(view.secrets).toEqual([{ path: ['apiKey'], set: true }])
-      expect(JSON.stringify(view)).not.toContain('sk-new')
-    })
-    expect(updates).toEqual([expectedSettingsUpdate('llm-deepseek')])
-  })
-
-  it('replace resets the user layer wholesale', async () => {
-    const ctx = await harness({ settings: { doc: { 'llm-deepseek': { baseURL: 'https://user' } } } })
-    ctx.settings.register(NS, AdapterConfig)
-    const api = createApiProxy(ctx, DEFAULTS)
-    const view = expectOk(await api.settings.replace(request({ ns: 'llm-deepseek', section: {} })))
-    expect(view.value).toEqual({ apiKeyEnv: 'DEEPSEEK_API_KEY' })
-    expect(view.user).toEqual({})
-  })
-
-  it.each([
-    ['an invalid namespace name', 'Not A Namespace', {}],
-    ['a schema-invalid patch', 'llm-deepseek', { baseURL: 42 }],
-  ])('rejects %s as settings-rejected', async (_case, ns, patch) => {
-    const ctx = await harness()
-    ctx.settings.register(NS, AdapterConfig)
-    const api = createApiProxy(ctx, DEFAULTS)
-    const error = expectErr(await api.settings.update(request({ ns, patch })))
-    expect(error.code).toBe('settings-rejected')
-    expect(error.details).toEqual({ ns })
-  })
 
-  it('answers an unregistered namespace as the seam does, and a malformed one alike', async () => {
-    // A name no registration answers and a name no registration could answer
-    // fold into the same rejection: the proxy adds no boundary of its own, so
-    // the seam's own refusal is the whole answer.
-    const ctx = await harness()
-    ctx.settings.register(NS, AdapterConfig)
-    const api = createApiProxy(ctx, DEFAULTS)
-    const unknown = expectErr(await api.settings.update(request({ ns: 'unknown-ns', patch: {} })))
-    const malformed = expectErr(await api.settings.update(request({ ns: 'Not A Namespace', patch: {} })))
-    expect(unknown.code).toBe('settings-rejected')
-    expect(unknown.message).toContain('is not registered')
-    expect(malformed.code).toBe(unknown.code)
-  })
 
-  it('maps a read-only provider refusal onto the same rejection', async () => {
-    const ctx = await harness({ settings: { readOnly: true } })
-    ctx.settings.register(NS, AdapterConfig)
-    const api = createApiProxy(ctx, DEFAULTS)
-    const value = expectOk(await api.settings.describe(request({})))
-    expect(value.writable).toBe(false)
-    const error = expectErr(await api.settings.update(request({ ns: 'llm-deepseek', patch: {} })))
-    expect(error.code).toBe('settings-rejected')
-    expect(error.message).toContain('read-only')
-  })
-})
 
-describe('credentials domain', () => {
-  it('reports an actionable error when no credential provider is mounted', async () => {
-    const ctx = await harness({ credentials: false })
-    const api = createApiProxy(ctx, DEFAULTS)
-    const error = expectErr(await api.credentials.describe(request({ refs: ['A'] })))
-    expect(error.code).toBe('internal')
-    expect(error.message).toContain('dsh-credentials-local')
-  })
 
-  it('describes value-free views and flips state through set/unset with frames', async () => {
-    const ctx = await harness()
-    const api = createApiProxy(ctx, DEFAULTS)
-    const before = expectOk(await api.credentials.describe(request({ refs: ['OPENAI_API_KEY'] })))
-    expect(before.credentials).toEqual({ OPENAI_API_KEY: { configured: false, writable: true } })
-    const updates = await captureCredentialUpdates(ctx, async () => {
-      expectOk(await api.credentials.set(request({ ref: 'OPENAI_API_KEY', value: 'sk-secret' })))
-      const after = expectOk(await api.credentials.describe(request({ refs: ['OPENAI_API_KEY'] })))
-      expect(after.credentials).toEqual({ OPENAI_API_KEY: { configured: true, source: 'file', writable: true } })
-      expect(JSON.stringify(after)).not.toContain('sk-secret')
-      expectOk(await api.credentials.unset(request({ ref: 'OPENAI_API_KEY' })))
-    })
-    expect(updates).toEqual(['OPENAI_API_KEY', 'OPENAI_API_KEY'])
-  })
 
-  it('maps a shadowed write onto credential-rejected for set and unset alike', async () => {
-    const ctx = await harness({ credentials: { shadowed: ['DEEPSEEK_API_KEY'] } })
-    const api = createApiProxy(ctx, DEFAULTS)
-    const described = expectOk(await api.credentials.describe(request({ refs: ['DEEPSEEK_API_KEY'] })))
-    expect(described.credentials['DEEPSEEK_API_KEY']).toEqual({ configured: true, source: 'env', writable: false })
-    const setError = expectErr(await api.credentials.set(request({ ref: 'DEEPSEEK_API_KEY', value: 'x' })))
-    expect(setError.code).toBe('credential-rejected')
-    expect(setError.details).toEqual({ ref: 'DEEPSEEK_API_KEY' })
-    const unsetError = expectErr(await api.credentials.unset(request({ ref: 'DEEPSEEK_API_KEY' })))
-    expect(unsetError.code).toBe('credential-rejected')
-  })
 })
 
 describe('llm domain', () => {
@@ -734,8 +462,7 @@ describe('llm.discoverModels', () => {
     }])
     // Interrogating a draft is a read: no namespace gained a section, and no
     // credential reference was written.
-    expect(expectOk(await api.settings.describe(request({}))).namespaces.map(view => view.ns))
-      .not.toContain('llm-pi-ai')
+    expect(ctx.settings.describe().map(view => String(view.ns))).not.toContain('llm-pi-ai')
   })
 
   it('carries the route being edited so an adapter can answer from its own registry', async () => {

+ 3 - 61
packages/host/apiproxy/tests/client-handler.spec.ts

@@ -19,7 +19,6 @@ function scriptedApi(overrides: {
   skills?: Partial<ApiProxy['skills']>
   agentPresets?: Partial<ApiProxy['agentPresets']>
   settings?: Partial<ApiProxy['settings']>
-  credentials?: Partial<ApiProxy['credentials']>
   llm?: Partial<ApiProxy['llm']>
 } = {}): ApiProxy {
   const err = <T>(r: RpcRequest<unknown>): Promise<RpcResponse<T>> =>
@@ -38,19 +37,9 @@ function scriptedApi(overrides: {
       ...overrides.agentPresets,
     },
     settings: {
-      describe: r => ok(r, { writable: true, hasDocument: false, namespaces: [] }),
       openDocument: r => ok(r, { opened: true as const }),
-      update: err,
-      replace: err,
-      mutate: err,
       ...overrides.settings,
     },
-    credentials: {
-      describe: r => ok(r, { credentials: {} }),
-      set: err,
-      unset: err,
-      ...overrides.credentials,
-    },
     llm: {
       providers: r => ok(r, { providers: [] }),
       models: r => ok(r, {
@@ -291,18 +280,9 @@ describe('envelope tap', () => {
 })
 
 describe('config unary surface', () => {
-  it('round-trips every settings/credentials/llm method with its own payload and value shape', async () => {
+  it('round-trips every settings/llm method with its own payload and value shape', async () => {
     const seen: { method: string; payload: unknown }[] = []
     const record = recorderInto(seen)
-    const view = {
-      ns: 'llm-deepseek',
-      schema: { uid: 1, refs: { 1: { type: 'object' } } },
-      value: { baseURL: 'https://next' },
-      user: { baseURL: 'https://next' },
-      applies: 'live' as const,
-      secrets: [{ path: ['apiKey'], set: true }],
-      revision: 0,
-    }
     const providerRow = {
       provider: 'openai',
       displayName: 'openai',
@@ -313,16 +293,7 @@ describe('config unary surface', () => {
     const group = { id: 'deepseek-official', name: 'DeepSeek', models: [{ id: 'deepseek-v4-flash', name: 'Flash' }] }
     const api = scriptedApi({
       settings: {
-        describe: record('settings.describe', r => ok(r, { writable: true, hasDocument: false, namespaces: [view] })),
         openDocument: record('settings.openDocument', r => ok(r, { opened: true as const })),
-        update: record('settings.update', r => ok(r, view)),
-        replace: record('settings.replace', r => ok(r, view)),
-        mutate: record('settings.mutate', r => ok(r, view)),
-      },
-      credentials: {
-        describe: record('credentials.describe', r => ok(r, { credentials: { OPENAI_API_KEY: { configured: true, source: 'file', writable: true } } })),
-        set: record('credentials.set', r => ok(r, {})),
-        unset: record('credentials.unset', r => ok(r, {})),
       },
       llm: {
         providers: record('llm.providers', r => ok(r, { providers: [providerRow] })),
@@ -337,23 +308,7 @@ describe('config unary surface', () => {
     })
     const c = client(api)
 
-    const described = await c.settings.describe({})
-    expect(described.result).toEqual({ ok: true, value: { writable: true, hasDocument: false, namespaces: [view] } })
     expect((await c.settings.openDocument({})).result).toEqual({ ok: true, value: { opened: true } })
-    const updated = await c.settings.update({ ns: 'llm-deepseek', patch: { baseURL: 'https://next' } })
-    expect(updated.result).toEqual({ ok: true, value: view })
-    const replaced = await c.settings.replace({ ns: 'llm-deepseek', section: {} })
-    expect(replaced.result).toEqual({ ok: true, value: view })
-    const mutated = await c.settings.mutate({
-      ns: 'llm-deepseek',
-      ops: [{ op: 'unset', path: ['baseURL'] }],
-      expectedRevision: 0,
-    })
-    expect(mutated.result).toEqual({ ok: true, value: view })
-    const creds = await c.credentials.describe({ refs: ['OPENAI_API_KEY'] })
-    expect(creds.result).toEqual({ ok: true, value: { credentials: { OPENAI_API_KEY: { configured: true, source: 'file', writable: true } } } })
-    expect((await c.credentials.set({ ref: 'OPENAI_API_KEY', value: 'sk-x' })).result).toEqual({ ok: true, value: {} })
-    expect((await c.credentials.unset({ ref: 'OPENAI_API_KEY' })).result).toEqual({ ok: true, value: {} })
     const providers = await c.llm.providers({})
     expect(providers.result).toEqual({ ok: true, value: { providers: [providerRow] } })
     const models = await c.llm.models({})
@@ -375,29 +330,16 @@ describe('config unary surface', () => {
     expect(discovered.result).toEqual({ ok: true, value: { models: [{ id: 'acme-large', contextWindow: 65536 }] } })
 
     expect(seen.map(call => call.method)).toEqual([
-      'settings.describe', 'settings.openDocument', 'settings.update', 'settings.replace', 'settings.mutate',
-      'credentials.describe', 'credentials.set', 'credentials.unset',
+      'settings.openDocument',
       'llm.providers', 'llm.models', 'llm.discoverModels',
     ])
-    expect(seen[2]?.payload).toEqual({ ns: 'llm-deepseek', patch: { baseURL: 'https://next' } })
-    expect(seen[4]?.payload)
-      .toEqual({ ns: 'llm-deepseek', ops: [{ op: 'unset', path: ['baseURL'] }], expectedRevision: 0 })
-    expect(seen[6]?.payload).toEqual({ ref: 'OPENAI_API_KEY', value: 'sk-x' })
     // The draft crosses whole, credential included: the host needs it for this
     // one interrogation and stores none of it.
-    expect(seen[10]?.payload).toEqual({
+    expect(seen[3]?.payload).toEqual({
       settingsNs: 'llm-pi-ai',
       baseURL: 'https://gateway.acme.example/v1',
       api: 'openai-completions',
       apiKey: 'probe-key',
     })
   })
-
-  it('rejects an invalid credential reference name at the carrier boundary', async () => {
-    const api = scriptedApi()
-    const response = await client(api).credentials.set({ ref: 'not a var', value: 'x' })
-    expect(response.result.ok).toBe(false)
-    if (response.result.ok) throw new Error('unreachable')
-    expect(response.result.error.code).toBe('bad-request')
-  })
 })

+ 3 - 26
packages/host/apiproxy/tests/fetch-carrier.spec.ts

@@ -33,31 +33,8 @@ function fakeApi(overrides: Partial<{ crashOn: string }> = {}): ApiProxy {
       },
     },
     settings: {
-      async describe(request) {
-        return { rpcId: request.rpcId, result: { ok: true, value: { writable: true, hasDocument: false, namespaces: [] } } }
-      },
       async openDocument(request) {
-        return { rpcId: request.rpcId, result: { ok: true, value: { opened: true as const } } }
-      },
-      async update(request) {
-        return { rpcId: request.rpcId, result: { ok: false, error: { code: 'settings-rejected', message: 'stub', details: { ns: request.payload.ns } } } }
-      },
-      async replace(request) {
-        return { rpcId: request.rpcId, result: { ok: false, error: { code: 'settings-rejected', message: 'stub', details: { ns: request.payload.ns } } } }
-      },
-      async mutate(request) {
-        return { rpcId: request.rpcId, result: { ok: false, error: { code: 'settings-rejected', message: 'stub', details: { ns: request.payload.ns } } } }
-      },
-    },
-    credentials: {
-      async describe(request) {
-        return { rpcId: request.rpcId, result: { ok: true, value: { credentials: {} } } }
-      },
-      async set(request) {
-        return { rpcId: request.rpcId, result: { ok: true, value: {} } }
-      },
-      async unset(request) {
-        return { rpcId: request.rpcId, result: { ok: true, value: {} } }
+        return { rpcId: request.rpcId, result: { ok: false, error: { code: 'internal', message: 'stub', details: {} } } }
       },
     },
     llm: {
@@ -102,9 +79,9 @@ describe('unary round trip (handler ⇄ client, no network)', () => {
   })
 
   it('carries a business error as 200 + error result', async () => {
-    const response = await client().settings.update({ ns: 'test', patch: {} })
+    const response = await client().settings.openDocument({})
     expect(response.result.ok).toBe(false)
-    if (!response.result.ok) expect(response.result.error.code).toBe('settings-rejected')
+    if (!response.result.ok) expect(response.result.error.code).toBe('internal')
   })
 
   it('round-trips the agent-preset document opener', async () => {

+ 0 - 4
packages/host/apiproxy/tests/rpc-schemas.spec.ts

@@ -37,10 +37,6 @@ describe('rpcErrorSchema', () => {
     expect(rpcErrorSchema.parse({ code: 'agent-preset-not-found', message: 'm', details: { agentPreset: 'p', available: [] } }).code).toBe('agent-preset-not-found')
     expect(rpcErrorSchema.parse({ code: 'agent-preset-invalid', message: 'm', details: { agentPreset: 'p', reason: 'bad' } }).code).toBe('agent-preset-invalid')
     expect(rpcErrorSchema.parse({ code: 'agent-busy', message: 'm', details: { reason: 'r' } }).code).toBe('agent-busy')
-    expect(rpcErrorSchema.parse({ code: 'settings-rejected', message: 'm', details: { ns: 'n' } }).code).toBe('settings-rejected')
-    expect(rpcErrorSchema.parse({ code: 'settings-conflict', message: 'm', details: { ns: 'n', expected: 1, actual: 2 } }).code).toBe('settings-conflict')
-    // The credentials producer still emits this code, so the branch has to stay.
-    expect(rpcErrorSchema.parse({ code: 'credential-rejected', message: 'm', details: { ref: 'r' } }).code).toBe('credential-rejected')
     expect(rpcErrorSchema.parse({ code: 'model-discovery-failed', message: 'm', details: { settingsNs: 'n' } }).code).toBe('model-discovery-failed')
     expect(rpcErrorSchema.parse({ code: 'internal', message: 'm', details: {} }).code).toBe('internal')
   })