Debt (surfaced via tech-debt-radar — the #13822 value-floor dogfood)
ai/provider/Gemini.mjs:50 (mapToolSchema) deep-clones the tool input schema with the banned JSON.parse(JSON.stringify(...)) pattern:
const parameters = JSON.parse(JSON.stringify(tool.inputSchema || { type: 'object', properties: {} }));The clone is necessary (the following uppercaseTypes mutates it — uppercasing type, deleting additionalProperties — so the original schema must not be touched), so this is a clean replacement, not a dead clone.
Why it's debt
JSON.parse(JSON.stringify(...)) is the banned deep-clone idiom in this codebase — the canonical helper is Neo.clone(x, true) (used at ai/mcp/client/config.mjs:90; structuredClone is the other accepted native form, MetadataManager.mjs:41). The operator corrected this exact pattern previously (#13116). Neo is global in ai/provider (Base extends Neo.core.Base via Neo.setupClass), so Neo.clone is available with no new import.
Fix
const parameters = Neo.clone(tool.inputSchema || { type: 'object', properties: {} }, true);
Behavior-identical for the JSON-safe schema; canonical + consistent with the rest of ai/.
AC
Radar note
Surfaced while dogfooding #13822's corrected value-floor (route to tech-debt-radar). A shallow grep-sweep of ai/ is otherwise clean (TODO/FIXME = 0) — the operator's "50–100 lanes" is architectural debt (the deep radar's KB + memory + architectural-deviation vectors), not grep-markers; this is the one grep-surfaced item. Labeled for an SML or quick maintainer fix.
Debt (surfaced via tech-debt-radar — the #13822 value-floor dogfood)
ai/provider/Gemini.mjs:50(mapToolSchema) deep-clones the tool input schema with the bannedJSON.parse(JSON.stringify(...))pattern:const parameters = JSON.parse(JSON.stringify(tool.inputSchema || { type: 'object', properties: {} }));The clone is necessary (the following
uppercaseTypesmutates it — uppercasingtype, deletingadditionalProperties— so the original schema must not be touched), so this is a clean replacement, not a dead clone.Why it's debt
JSON.parse(JSON.stringify(...))is the banned deep-clone idiom in this codebase — the canonical helper isNeo.clone(x, true)(used atai/mcp/client/config.mjs:90;structuredCloneis the other accepted native form,MetadataManager.mjs:41). The operator corrected this exact pattern previously (#13116).Neois global inai/provider(BaseextendsNeo.core.BaseviaNeo.setupClass), soNeo.cloneis available with no new import.Fix
const parameters = Neo.clone(tool.inputSchema || { type: 'object', properties: {} }, true);Behavior-identical for the JSON-safe schema; canonical + consistent with the rest of
ai/.AC
Gemini.mjs:mapToolSchemausesNeo.clone(..., true)(orstructuredClone); noJSON.parse(JSON.stringify(...)).Radar note
Surfaced while dogfooding #13822's corrected value-floor (route to
tech-debt-radar). A shallow grep-sweep ofai/is otherwise clean (TODO/FIXME = 0) — the operator's "50–100 lanes" is architectural debt (the deep radar's KB + memory + architectural-deviation vectors), not grep-markers; this is the one grep-surfaced item. Labeled for an SML or quick maintainer fix.