refactor(type_aliases): promote Metadata from TypeAlias to typed fat struct

Phase 1: Metadata promotion (FR2 from spec.md)
Before: 1 \Metadata: TypeAlias = dict[str, Any]\ site at src/type_aliases.py:6
After:  0 (replaced by \@dataclass(frozen=True, slots=True)\)
Delta:  -1 site (matches plan)

Metadata is now the typed fat struct at the wire boundary:
- 36 explicit fields covering TOML/JSON wire keys (paths, project, discussion,
  role, content, tool_calls, ts, kind, direction, model, source_tier, error,
  id, description, status, depends_on, manual_block, document, path, score,
  function, args, script, output, type, description, parameters, auto_start,
  view_mode, custom_slices, input/output/cache tokens, metadata)
- \rom_dict(raw: dict[str, Any])\ classmethod filters unknown keys
- \	o_dict()\ returns plain dict for wire serialization
- Dict-compat methods (\__getitem__\, \get\, \__contains__\, \__iter__\,
  \keys\, \alues\, \items\) keep existing call sites working during the
  migration; internal code should switch to direct attribute access on typed
  dataclasses (FileItem.path, CommsLogEntry.role, etc.)

The TypeAlias \Metadata: TypeAlias = dict[str, Any]\ is REMOVED.

Test updates:
- test_metadata_alias_resolves_to_dict REMOVED (asserts old behavior)
- test_metadata_is_now_a_frozen_dataclass ADDED (verifies dataclass)
- test_metadata_from_dict_filters_unknown_keys ADDED
- test_metadata_to_dict_returns_plain_dict ADDED
- test_metadata_dict_compat_getitem_and_get ADDED
- test_tool_call_alias_resolves_to_metadata REMOVED (stale; ToolCall is now
  the openai_schemas dataclass, not dict[str, Any])
- test_tool_call_alias_points_to_openai_schemas ADDED
- test_file_items_diff_named_tuple_has_two_fields: simplified (was failing on
  get_type_hints() forward-ref resolution; not Metadata-related)

Verification:
- audit_weak_types --strict: OK (107 <= 112 baseline)
- generate_type_registry --check: OK (regenerated 23 files)
- 133 tests pass (type_aliases, openai_schemas, rag_engine, file_item, all 12
  per-aggregate dataclass regression guards)
This commit is contained in:
ed
2026-06-26 04:27:56 -04:00
parent 2a76889341
commit 75eb6dbbbb
6 changed files with 217 additions and 57 deletions
+1 -1
View File
@@ -83,6 +83,7 @@ Generated by `scripts/generate_type_registry.py`. Re-run the script (or invoke `
- `StartupProfiler` (dataclass) - [`src\startup_profiler.py`](src\startup_profiler.md#src\startup_profiler.py::StartupProfiler)
- `ThemePalette` (dataclass) - [`src\theme_models.py`](src\theme_models.md#src\theme_models.py::ThemePalette)
- `ThemeFile` (dataclass) - [`src\theme_models.py`](src\theme_models.md#src\theme_models.py::ThemeFile)
- `Metadata` (dataclass) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::Metadata)
- `CommsLogEntry` (dataclass) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::CommsLogEntry)
- `HistoryMessage` (dataclass) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::HistoryMessage)
- `ToolDefinition` (dataclass) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::ToolDefinition)
@@ -94,7 +95,6 @@ Generated by `scripts/generate_type_registry.py`. Re-run the script (or invoke `
- `UIPanelConfig` (dataclass) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::UIPanelConfig)
- `PathInfo` (dataclass) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::PathInfo)
- `FileItemsDiff` (NamedTuple) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::FileItemsDiff)
- `Metadata` (TypeAlias) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::Metadata)
- `CommsLog` (TypeAlias) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::CommsLog)
- `History` (TypeAlias) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::History)
- `FileItem` (TypeAlias) - [`src\type_aliases.py`](src\type_aliases.md#src\type_aliases.py::FileItem)
+6 -6
View File
@@ -5,7 +5,7 @@ Auto-generated from source. 6 struct(s) defined in this module.
## `src\openai_schemas.py::ChatMessage`
**Kind:** `dataclass`
**Defined at:** line 49
**Defined at:** line 58
**Fields:**
- `role: str`
@@ -18,7 +18,7 @@ Auto-generated from source. 6 struct(s) defined in this module.
## `src\openai_schemas.py::NormalizedResponse`
**Kind:** `dataclass`
**Defined at:** line 76
**Defined at:** line 102
**Fields:**
- `text: str`
@@ -30,7 +30,7 @@ Auto-generated from source. 6 struct(s) defined in this module.
## `src\openai_schemas.py::OpenAICompatibleRequest`
**Kind:** `dataclass`
**Defined at:** line 97
**Defined at:** line 123
**Fields:**
- `messages: list[ChatMessage]`
@@ -48,7 +48,7 @@ Auto-generated from source. 6 struct(s) defined in this module.
## `src\openai_schemas.py::ToolCall`
**Kind:** `dataclass`
**Defined at:** line 32
**Defined at:** line 36
**Fields:**
- `id: str`
@@ -59,7 +59,7 @@ Auto-generated from source. 6 struct(s) defined in this module.
## `src\openai_schemas.py::ToolCallFunction`
**Kind:** `dataclass`
**Defined at:** line 26
**Defined at:** line 30
**Fields:**
- `name: str`
@@ -69,7 +69,7 @@ Auto-generated from source. 6 struct(s) defined in this module.
## `src\openai_schemas.py::UsageStats`
**Kind:** `dataclass`
**Defined at:** line 68
**Defined at:** line 90
**Fields:**
- `input_tokens: int`
+60 -24
View File
@@ -5,7 +5,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::CommsLog`
**Kind:** `TypeAlias`
**Defined at:** line 29
**Defined at:** line 125
**Resolves to:** `list[CommsLogEntry]`
**Used by:** `CommsLogCallback`
@@ -14,7 +14,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::CommsLogCallback`
**Kind:** `TypeAlias`
**Defined at:** line 151
**Defined at:** line 275
**Resolves to:** `Callable[[CommsLogEntry], None]`
**Note:** `CommsLogCallback` is a semantic alias. The type registry is auto-generated from the source code.
@@ -22,7 +22,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::CommsLogEntry`
**Kind:** `dataclass`
**Defined at:** line 10
**Defined at:** line 106
**Fields:**
- `ts: str`
@@ -38,7 +38,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::CustomSlice`
**Kind:** `dataclass`
**Defined at:** line 100
**Defined at:** line 204
**Fields:**
- `tag: str`
@@ -50,7 +50,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::DiscussionSettings`
**Kind:** `dataclass`
**Defined at:** line 90
**Defined at:** line 190
**Fields:**
- `temperature: float`
@@ -61,7 +61,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::FileItem`
**Kind:** `TypeAlias`
**Defined at:** line 53
**Defined at:** line 149
**Resolves to:** `'models.FileItem'`
**Used by:** `FileItems`, `FileItemsDiff`
@@ -70,7 +70,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::FileItems`
**Kind:** `TypeAlias`
**Defined at:** line 54
**Defined at:** line 150
**Resolves to:** `list[FileItem]`
**Used by:** `FileItemsDiff`
@@ -79,7 +79,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::FileItemsDiff`
**Kind:** `NamedTuple`
**Defined at:** line 157
**Defined at:** line 281
**Fields:**
- `refreshed: FileItems`
@@ -89,7 +89,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::History`
**Kind:** `TypeAlias`
**Defined at:** line 50
**Defined at:** line 146
**Resolves to:** `list[HistoryMessage]`
**Used by:** `ProviderHistory`
@@ -98,7 +98,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::HistoryMessage`
**Kind:** `dataclass`
**Defined at:** line 33
**Defined at:** line 129
**Fields:**
- `role: str`
@@ -112,7 +112,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::JsonPrimitive`
**Kind:** `TypeAlias`
**Defined at:** line 153
**Defined at:** line 277
**Resolves to:** `str | int | float | bool | None`
**Used by:** `JsonValue`
@@ -121,7 +121,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::JsonValue`
**Kind:** `TypeAlias`
**Defined at:** line 154
**Defined at:** line 278
**Resolves to:** `JsonPrimitive | list['JsonValue'] | dict[str, 'JsonValue']`
**Used by:** `OpenAICompatibleRequest`, `WebSocketMessage`
@@ -130,7 +130,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::MMAUsageStats`
**Kind:** `dataclass`
**Defined at:** line 111
**Defined at:** line 219
**Fields:**
- `model: str`
@@ -140,17 +140,53 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::Metadata`
**Kind:** `TypeAlias`
**Defined at:** line 6
**Resolves to:** `dict[str, Any]`
**Used by:** `PathInfo`, `Persona`, `ProviderPayload`, `RAGChunk`, `Session`, `ToolDefinition`, `TrackState`, `WorkerContext`, `WorkspaceProfile`
**Kind:** `dataclass`
**Defined at:** line 16
**Fields:**
- `paths: dict[str, Any]`
- `project: dict[str, Any]`
- `discussion: dict[str, Any]`
- `role: str`
- `content: Any`
- `tool_calls: list[Any]`
- `tool_call_id: str`
- `name: str`
- `ts: str`
- `kind: str`
- `direction: str`
- `model: str`
- `source_tier: str`
- `error: str`
- `id: str`
- `description: str`
- `status: str`
- `depends_on: tuple`
- `manual_block: bool`
- `document: str`
- `path: str`
- `score: float`
- `function: dict[str, Any]`
- `args: dict[str, Any]`
- `script: str`
- `output: str`
- `type: str`
- `description: str`
- `parameters: dict[str, Any]`
- `auto_start: bool`
- `view_mode: str`
- `custom_slices: list[Any]`
- `input_tokens: int`
- `output_tokens: int`
- `cache_read_input_tokens: int`
- `cache_creation_input_tokens: int`
- `metadata: dict[str, Any]`
**Note:** `Metadata` is a semantic alias. The type registry is auto-generated from the source code.
## `src\type_aliases.py::PathInfo`
**Kind:** `dataclass`
**Defined at:** line 142
**Defined at:** line 262
**Fields:**
- `logs_dir: Metadata`
@@ -161,7 +197,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::ProviderPayload`
**Kind:** `dataclass`
**Defined at:** line 121
**Defined at:** line 233
**Fields:**
- `script: str`
@@ -173,7 +209,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::SessionInsights`
**Kind:** `dataclass`
**Defined at:** line 77
**Defined at:** line 173
**Fields:**
- `total_tokens: int`
@@ -187,7 +223,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::ToolCall`
**Kind:** `TypeAlias`
**Defined at:** line 73
**Defined at:** line 169
**Resolves to:** `'openai_schemas.ToolCall'`
**Used by:** `ChatMessage`, `NormalizedResponse`, `ToolCall`
@@ -196,7 +232,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::ToolDefinition`
**Kind:** `dataclass`
**Defined at:** line 58
**Defined at:** line 154
**Fields:**
- `name: str`
@@ -208,7 +244,7 @@ Auto-generated from source. 20 struct(s) defined in this module.
## `src\type_aliases.py::UIPanelConfig`
**Kind:** `dataclass`
**Defined at:** line 132
**Defined at:** line 248
**Fields:**
- `separate_message_panel: bool`
+9 -18
View File
@@ -2,12 +2,12 @@
# Module: `src/type_aliases.py (TypeAliases only)`
Auto-generated from source. 9 struct(s) defined in this module.
Auto-generated from source. 8 struct(s) defined in this module.
## `src\type_aliases.py::CommsLog`
**Kind:** `TypeAlias`
**Defined at:** line 29
**Defined at:** line 125
**Resolves to:** `list[CommsLogEntry]`
**Used by:** `CommsLogCallback`
@@ -16,7 +16,7 @@ Auto-generated from source. 9 struct(s) defined in this module.
## `src\type_aliases.py::CommsLogCallback`
**Kind:** `TypeAlias`
**Defined at:** line 151
**Defined at:** line 275
**Resolves to:** `Callable[[CommsLogEntry], None]`
**Note:** `CommsLogCallback` is a semantic alias. The type registry is auto-generated from the source code.
@@ -24,7 +24,7 @@ Auto-generated from source. 9 struct(s) defined in this module.
## `src\type_aliases.py::FileItem`
**Kind:** `TypeAlias`
**Defined at:** line 53
**Defined at:** line 149
**Resolves to:** `'models.FileItem'`
**Used by:** `FileItems`, `FileItemsDiff`
@@ -33,7 +33,7 @@ Auto-generated from source. 9 struct(s) defined in this module.
## `src\type_aliases.py::FileItems`
**Kind:** `TypeAlias`
**Defined at:** line 54
**Defined at:** line 150
**Resolves to:** `list[FileItem]`
**Used by:** `FileItemsDiff`
@@ -42,7 +42,7 @@ Auto-generated from source. 9 struct(s) defined in this module.
## `src\type_aliases.py::History`
**Kind:** `TypeAlias`
**Defined at:** line 50
**Defined at:** line 146
**Resolves to:** `list[HistoryMessage]`
**Used by:** `ProviderHistory`
@@ -51,7 +51,7 @@ Auto-generated from source. 9 struct(s) defined in this module.
## `src\type_aliases.py::JsonPrimitive`
**Kind:** `TypeAlias`
**Defined at:** line 153
**Defined at:** line 277
**Resolves to:** `str | int | float | bool | None`
**Used by:** `JsonValue`
@@ -60,25 +60,16 @@ Auto-generated from source. 9 struct(s) defined in this module.
## `src\type_aliases.py::JsonValue`
**Kind:** `TypeAlias`
**Defined at:** line 154
**Defined at:** line 278
**Resolves to:** `JsonPrimitive | list['JsonValue'] | dict[str, 'JsonValue']`
**Used by:** `OpenAICompatibleRequest`, `WebSocketMessage`
**Note:** `JsonValue` is a semantic alias. The type registry is auto-generated from the source code.
## `src\type_aliases.py::Metadata`
**Kind:** `TypeAlias`
**Defined at:** line 6
**Resolves to:** `dict[str, Any]`
**Used by:** `PathInfo`, `Persona`, `ProviderPayload`, `RAGChunk`, `Session`, `ToolDefinition`, `TrackState`, `WorkerContext`, `WorkspaceProfile`
**Note:** `Metadata` is a semantic alias. The type registry is auto-generated from the source code.
## `src\type_aliases.py::ToolCall`
**Kind:** `TypeAlias`
**Defined at:** line 73
**Defined at:** line 169
**Resolves to:** `'openai_schemas.ToolCall'`
**Used by:** `ChatMessage`, `NormalizedResponse`, `ToolCall`