Skip to content

Establish consistent strategy for mutable containers in frozen Pydantic models #113

@Aureliolo

Description

@Aureliolo

Problem

Multiple frozen models contain dict[str, Any] fields with documented warnings:

# Note: The ``parameters_schema`` dict is shallowly immutable under the
# frozen model — reassignment is prevented but contents can still be
# mutated.  Callers should treat it as read-only.

This appears on:

  • ToolDefinition.parameters_schema
  • ToolCall.arguments
  • ToolExecutionResult.metadata
  • Various config models

The current approach is inconsistent:

  • BaseTool does copy.deepcopy on property access (expensive, see related issue)
  • ToolInvoker does dict(tool_call.arguments) (shallow copy — nested refs still shared)
  • Most models just document "please don't mutate" and hope for the best

Pydantic's frozen=True is confirmed to be shallow — nested mutable objects can still be mutated in-place.

Options to Evaluate

Approach Pros Cons
A. Document-only Zero overhead, honest No enforcement, bugs possible
B. MappingProxyType at construction O(1), prevents top-level mutation Shallow — nested dicts still mutable
C. Recursive freeze utility True deep immutability Complex, perf overhead at construction
D. Deep-copy at boundary only Isolation where it matters Must identify all boundaries correctly

Recommendation

Option D — deep-copy only at system boundaries (when passing data to tool execute(), when serializing for persistence), with MappingProxyType for the common read-only access path. This balances safety and performance.

Acceptance Criteria

  • Decision documented (ADR or DESIGN_SPEC update)
  • Chosen strategy applied consistently across all affected models
  • Remove or update all "callers should treat it as read-only" comments
  • ToolInvoker boundary handling aligned with chosen strategy
  • Tests verify immutability guarantees at boundaries

Metadata

Metadata

Assignees

No one assigned

    Labels

    prio:mediumShould do, but not blockingscope:smallLess than 1 day of workspec:architectureDESIGN_SPEC Section 15 - Technical Architecturespec:toolsDESIGN_SPEC Section 11 - Tool & Capability Systemtype:researchEvaluate options, make tech decisions

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions