Skip to content

Typed accessor methods for raw dict keys #90

@bradjin8

Description

@bradjin8

Problem

cppa-cursor-browser has a well-structured models/ layer with 7 frozen @dataclass declarations (Composer, Bubble, Workspace, ExportEntry, CliSessionMeta, WorkspaceLocalComposer, ParseWarning), each with validated from_dict classmethods backed by models/from_dict_validation.py. Type annotations exist on function signatures, [tool.mypy] is configured in pyproject.toml, and CI runs mypy alongside pytest. Despite this typed boundary at the read-from-SQLite edge, the service layer passes data onward as untyped dict[str, Any] through pervasive .get() chains: services/workspace_tabs.py has 79 .get() calls, services/workspace_resolver.py has 31, services/workspace_listing.py has 20, and services/cli_tabs.py has 15 — totalling 149 .get() calls across the service layer alone. API routes add another 39 (api/search.py) and scripts/export.py adds 25. The typed @dataclass models validate data at the read boundary but the validated fields are not carried through the service pipeline — instead, code immediately drops back into raw dict access (e.g., cd.get("fullConversationHeadersOnly"), bubble.get("relevantFiles"), ctx.get("projectLayouts")). When Cursor's weekly schema changes rename a key, the from_dict validator catches it at the model boundary, but the 149+ downstream .get() calls silently return None. The gap is not "no types exist" but "types stop at models/ and don't flow through services/."

Acceptance Criteria

  • Typed accessor methods for top 10 most-accessed raw dict keys in the service layer
  • Accessors log a WARNING when expected key is missing (drift detection)
  • Type annotations that mypy can verify end-to-end from model to service output
  • Existing callers in services/workspace_tabs.py and services/workspace_resolver.py migrated to use typed accessors
  • Tests covering drift detection logging

Implementation Notes

  • Audit the 149 .get() calls in the service layer to identify the top 10 most-accessed keys
  • Pattern: @property methods on the existing model @dataclass classes returning Optional[T] with _logger.warning() on missing keys
  • Brad's PR Extract shared from_dict validation helpers for model classes (#70) #80 (from_dict helpers) and models/from_dict_validation.py provide the validation foundation
  • services/workspace_tabs.py (79 .get() calls, 605 LOC) is the highest-value target

References

  • models/conversation.pyComposer, Bubble, WorkspaceLocalComposer dataclasses with from_dict
  • models/from_dict_validation.py — shared validation helpers
  • services/workspace_tabs.py — 79 .get() calls (primary migration target)
  • services/workspace_resolver.py — 31 .get() calls

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions