Skip to content

gut(config): remove remaining LLM-platform z.unknown() stubs — middleware-not-platform consolidation #2489

@alexey-pelykh

Description

@alexey-pelykh

Context

RemoteClaw is middleware that delegates LLM execution to CLI agents (Claude Code, Gemini, Codex, OpenCode). CLI agents own LLM API routing, capability detection, memory/RAG, and model-specific input handling. Any config field describing those concerns is, by definition, outside middleware's responsibility.

After the #2477-#2482 batch (#2483-#2488 PRs), 8 z.unknown().optional() stubs remain across the config schema. All 8 describe LLM-platform concerns. All 8 have zero production readers (one has a dead-end passthrough). Their existence is a fig leaf that pretends middleware has concerns it doesn't.

This issue consolidates their removal into a single hard-break cleanup. No migration infrastructure is added — the features these fields describe were gutted months ago; users carrying them in their configs see a zod strict-validation error on upgrade and must remove the stale sections manually, one-time.

Why no migrations

The fork has used Option B (rule + auto-strip migration) for schema renames (#2479, #2480, #2481). That pattern is appropriate when a field is renamed — users need a bridge. It is not appropriate for gut removals of platform concerns: auto-stripping prolongs the pretense that these fields mean anything to middleware. The correct signal is a clear rejection.

This issue also reverts #2478's Option-A additions (compat/api stubs added during the same batch where the fork pivoted to Option B — these were inconsistent with the new direction from the moment they landed).

Per-field audit

Cluster A — LLM API routing + capability flags

Zero production readers. No shadow surfaces. Added by #2478 as "kept for config parse compatibility."

# Field Location What it described
1 api (model) src/config/zod-schema.core.ts:200 LLM API protocol (openai-completions / anthropic-messages / …)
2 compat (model) src/config/zod-schema.core.ts:201 LLM capability flags (supportsTools, thinkingFormat, …)
3 api (provider) src/config/zod-schema.core.ts:218 Provider-level LLM API

Cluster B — LLM PDF processing

Zero production readers. TS types still structured (divergent from zod).

  • Zod stubs (src/config/zod-schema.agent-defaults.ts:20-22):
    • pdfModel: z.unknown().optional()
    • pdfMaxBytesMb: z.unknown().optional()
    • pdfMaxPages: z.unknown().optional()
  • Divergent TS types (src/config/types.agent-defaults.ts:125,127,129): still declare pdfModel?: AgentModelConfig, pdfMaxBytesMb?: number, pdfMaxPages?: number
  • Shadow docs: schema.help.ts:1006-1011 (4 entries), schema.labels.ts:452-455 (4 entries)

Cluster C — Top-level memory backend

Zero production readers. plugins.slots.memory and doctor.memory.status are unrelated paths (plugin-slot identifier and gateway health RPC — not memory-backend config).

  • Zod stub: src/config/zod-schema.ts:690memory: z.unknown().optional() at root of RemoteClawSchema
  • Shadow docs: schema.help.ts:862 ("Memory backend configuration (global)."), schema.labels.ts:374 (memory: "Memory")

Cluster D — RAG / memory-search

Zero production reads. Only a dead-end passthrough in agent-scope.ts (copies entry.memorySearch into ResolvedAgentConfig.memorySearch; scope.memorySearch is never read anywhere).

  • Zod stubs:
    • src/config/zod-schema.agent-defaults.ts:52memorySearch: z.unknown().optional() (defaults)
    • src/config/types.agents.ts:70-71memorySearch?: unknown (per-agent, @deprecated)
  • TS type: src/config/types.agent-defaults.ts:174memorySearch?: unknown
  • Shadow help: src/config/schema.help.ts~29 entries describing the full nested tree (sources, multimodal.{enabled,modalities,maxFileBytes}, experimental.sessionMemory, provider, model, outputDimensionality, remote.{baseUrl,apiKey,headers,batch.*}, local.modelPath, fallback, store.{path,vector.*}, chunking.{tokens,overlap}, query.{maxResults,minScore,hybrid.*})
  • Shadow labels: src/config/schema.labels.ts — ~20 mirroring entries
  • Test drift: src/config/schema.help.quality.test.ts:71-87 asserts 17 of those help paths exist — assertions must be removed
  • Dead passthrough: src/agents/agent-scope.ts:73 (type) + :179 (value copy) in ResolvedAgentConfig

Non-goals

  • No LEGACY_CONFIG_RULES entries. These fields describe functionality that doesn't exist. A rule produces a friendlier error but cannot fix strict validation on its own, so it adds code with no value.
  • No legacy.migrations.ts entries. Auto-stripping would prolong the pretense that these fields matter to middleware. We want the hard break.
  • No new stubs. Fixing compat/api means removing them, not substituting them.

Accepted consequence: existing user configs containing memory: {…}, memorySearch: {…}, pdfModel: …, pdfMaxBytesMb: …, pdfMaxPages: …, or a model/provider with api: … / compat: … will fail to load on upgrade with "Unrecognized key(s) in object: '<field>'" (zod strict-mode behavior). Users perform a one-time manual edit of their config.

Tasks

  1. Delete the 8 zod stub lines:
    • src/config/zod-schema.core.ts:200api (ModelDefinitionSchema)
    • src/config/zod-schema.core.ts:201compat (ModelDefinitionSchema)
    • src/config/zod-schema.core.ts:218api (ModelProviderSchema)
    • src/config/zod-schema.agent-defaults.ts:20-22pdfModel, pdfMaxBytesMb, pdfMaxPages
    • src/config/zod-schema.agent-defaults.ts:52memorySearch
    • src/config/zod-schema.ts:690memory
    • Remove the 4 paired // Stub kept for config parse compatibility… comment blocks introduced by prior waves.
  2. Remove paired TS type declarations:
    • src/config/types.agent-defaults.ts:125,127,129pdfModel, pdfMaxBytesMb, pdfMaxPages
    • src/config/types.agent-defaults.ts:174memorySearch
    • src/config/types.agents.ts:70-71 — per-agent memorySearch
  3. Remove paired help entries in src/config/schema.help.ts:
    • All agents.defaults.memorySearch.* (~29 entries)
    • agents.defaults.pdfModel.primary, .fallbacks, agents.defaults.pdfMaxBytesMb, agents.defaults.pdfMaxPages
    • Top-level memory (line ~862)
  4. Remove paired label entries in src/config/schema.labels.ts (~25 matching entries)
  5. Update src/config/schema.help.quality.test.ts:
    • Delete lines 71-87 (17 memorySearch.* path assertions)
  6. Remove dead passthrough in src/agents/agent-scope.ts:
    • Line 73: memorySearch?: AgentEntry["memorySearch"] — remove
    • Line 179: memorySearch: entry.memorySearch — remove
  7. Regenerate src/config/schema.base.generated.ts and docs/.generated/config-baseline.json via the project's generation command
  8. Add adversarial regression tests to src/config/config-misc.test.ts (or closest fit) verifying that strict validation rejects each removed field with "Unrecognized key". One test per cluster is sufficient; covers the hard-break contract.

Acceptance Criteria

  • rg "memorySearch|pdfModel|pdfMaxBytesMb|pdfMaxPages" src/ returns only references in the new rejection tests (no hits in zod-schema*, types.*, schema.help.ts, schema.labels.ts, agent-scope.ts, or schema.help.quality.test.ts).
  • rg "^\s+compat:\s*z\." src/config/ returns no hits.
  • rg "^\s+api:\s*z\.unknown" src/config/ returns no hits.
  • rg "^\s+memory:\s*z\.unknown" src/config/zod-schema.ts returns no hits.
  • src/config/schema.help.quality.test.ts contains zero memorySearch references.
  • src/agents/agent-scope.ts contains zero memorySearch references.
  • A config fixture like { memorySearch: { enabled: true } } fails to parse with a zod error matching /Unrecognized key.*memorySearch/ (asserted by new regression test).
  • Same adversarial parse-and-reject test for: top-level memory, pdfModel under agents.defaults, compat/api on a model definition, api on a model provider.
  • pnpm tsgo clean.
  • pnpm lint clean.
  • pnpm format:check clean.
  • pnpm test passes (expect a net decrease in assertions — memorySearch help-path block removed; new regression tests added).
  • All required CI gates pass: rebrand-gate, zombie-import-gate, stub-debt-gate, throwing-stub-callers-gate, obsolescence-audit-gate, attestation-gate, docs, build, test, lint.

Out of scope

  • src/agents/transcript-policy.ts: contains isGoogleModelApi stub at line 14 shadowing the real function in agent-helpers/google.ts, and exports applyTranscriptPolicy which has zero production callers. Entire file appears to be zombie. Separate issue — confirm death, file gut ticket.
  • Any future Option-B conversion for a truly-renamed field. This issue's no-migration policy applies specifically to gutted platform concerns; genuine renames remain a legitimate use case for rule + migration.

References

Metadata

Metadata

Assignees

Labels

gutRemoving dead upstream subsystems

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions