Repository: cppa-cursor-browser
Assignee: Brad @bradjin8
Points: 3
Severity: Medium
Problem
Five model classes (Workspace, Composer, WorkspaceLocalComposer, Bubble, CliSessionMeta) each implement a from_dict class method with identical structure: check isinstance(raw, dict), validate required fields, check types, raise SchemaError on failure. The pattern is identical in shape but implemented independently in each file. This becomes structural when combined with the silent failure chain: each from_dict site is wrapped in its own try/except block at the call site, and the handling strategy varies by caller. A fix to exception handling must be applied at every call site independently, creating fresh opportunities for logged-vs-silent inconsistency.
Acceptance Criteria
Implementation Notes
The cleanest approach is a @validated_from_dict decorator or a base class with a generic from_dict that accepts a field specification. For example, each model defines _REQUIRED_FIELDS = {"id": str, "title": str} and the shared from_dict validates against this spec before delegating to the model-specific constructor. Alternatively, a validate_raw(raw, required_fields, model_name) utility function can be called at the top of each from_dict, reducing but not eliminating the boilerplate. The frozen dataclass pattern already used in the models is compatible with either approach. The ExportEntry model in models/export.py follows the same pattern — include it.
References
- Eval finding: Test 5 (Boilerplate Minimality) — part of the "Distributed Constructor Problem" compound (T5+T7+T11)
- Related files:
models/workspace.py, models/conversation.py, models/cli_session.py, models/export.py, models/bubble.py (or equivalent)
Repository: cppa-cursor-browser
Assignee: Brad @bradjin8
Points: 3
Severity: Medium
Problem
Five model classes (
Workspace,Composer,WorkspaceLocalComposer,Bubble,CliSessionMeta) each implement afrom_dictclass method with identical structure: checkisinstance(raw, dict), validate required fields, check types, raiseSchemaErroron failure. The pattern is identical in shape but implemented independently in each file. This becomes structural when combined with the silent failure chain: eachfrom_dictsite is wrapped in its owntry/exceptblock at the call site, and the handling strategy varies by caller. A fix to exception handling must be applied at every call site independently, creating fresh opportunities for logged-vs-silent inconsistency.Acceptance Criteria
from_dictvalidation pattern (isinstance check, required field validation, type checking, SchemaError raising)SchemaErrormessages retain the same level of detail (field name, expected type, actual type)Implementation Notes
The cleanest approach is a
@validated_from_dictdecorator or a base class with a genericfrom_dictthat accepts a field specification. For example, each model defines_REQUIRED_FIELDS = {"id": str, "title": str}and the sharedfrom_dictvalidates against this spec before delegating to the model-specific constructor. Alternatively, avalidate_raw(raw, required_fields, model_name)utility function can be called at the top of eachfrom_dict, reducing but not eliminating the boilerplate. The frozen dataclass pattern already used in the models is compatible with either approach. TheExportEntrymodel inmodels/export.pyfollows the same pattern — include it.References
models/workspace.py,models/conversation.py,models/cli_session.py,models/export.py,models/bubble.py(or equivalent)