Skip to content

Commit 545886d

Browse files
committed
docs: drop module docstrings and trim class docstrings to one-liners (#30)
Internal cleanup on the typed-models package — file location and class name carry the intent; the multi-paragraph rationales were rehashing the PR description. Function bodies are unchanged. - models/__init__.py: removed 8-line module docstring - models/errors.py: dropped module docstring + SchemaError class docstring trimmed to one line - models/conversation.py: dropped module docstring; Composer, WorkspaceLocalComposer, Bubble docstrings trimmed to one line each - models/cli_session.py: dropped module docstring; CliSessionMeta docstring trimmed - models/workspace.py: dropped module docstring; Workspace docstring trimmed - models/export.py: dropped module docstring; ExportEntry docstring trimmed - tests/test_models.py: dropped module docstring; removed now-unused ``from pathlib import Path`` 204 tests pass.
1 parent d983b9b commit 545886d

7 files changed

Lines changed: 7 additions & 96 deletions

File tree

models/__init__.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
"""Typed domain models for Cursor schema (closes #24).
2-
3-
Cursor's on-disk JSON shapes are not versioned, so silent renames of fields
4-
like ``composerData`` or ``latestRootBlobId`` would otherwise pass through
5-
``dict.get(...)`` with a fallback default and produce empty conversations
6-
with no error raised. The models here add a schema-validation boundary at
7-
database read sites: ``from_dict`` classmethods raise ``SchemaError`` when
8-
critical fields are missing, so drift becomes loud instead of silent.
9-
"""
10-
111
from models.cli_session import CliSessionMeta
122
from models.conversation import Bubble, Composer, WorkspaceLocalComposer
133
from models.errors import SchemaError

models/cli_session.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"""CliSessionMeta — typed model for the Cursor CLI ``meta`` blob."""
2-
31
from __future__ import annotations
42

53
from dataclasses import dataclass, field
@@ -10,16 +8,7 @@
108

119
@dataclass(frozen=True)
1210
class CliSessionMeta:
13-
"""The ``meta`` blob at the head of a Cursor CLI ``store.db`` blob graph.
14-
15-
``latestRootBlobId`` is the entry point for the conversation reconstruction
16-
BFS in ``utils/cli_chat_reader.traverse_blobs``; without it, the entire
17-
conversation is unreachable. ``createdAt`` is documented as part of the
18-
meta-blob schema (see ``utils/cli_chat_reader`` module docstring) and is
19-
captured here, but it is not gated on — only ``latestRootBlobId`` is the
20-
hard requirement, since that is the only field whose absence prevents
21-
conversation reconstruction.
22-
"""
11+
"""CLI session meta blob; latestRootBlobId is the conversation entry point and the only required field."""
2312

2413
latest_root_blob_id: str
2514
created_at: Any = None

models/conversation.py

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"""Composer (conversation) and Bubble (message) typed models."""
2-
31
from __future__ import annotations
42

53
from dataclasses import dataclass, field
@@ -10,19 +8,7 @@
108

119
@dataclass(frozen=True)
1210
class Composer:
13-
"""A Cursor conversation (a.k.a. "composer") row.
14-
15-
Required fields per the schema-validation contract (issue #24):
16-
- ``fullConversationHeadersOnly`` — without this, a composer cannot be
17-
rendered (no message order is recoverable).
18-
- ``createdAt`` — Cursor writes this on every composer (verified
19-
17/17 against a live workspaceStorage). A missing value is the
20-
kind of drift this layer exists to surface.
21-
22-
The composer ID is intentionally passed in as a constructor argument
23-
rather than read from ``raw`` because Cursor stores it in the row key
24-
(``composerData:<id>``) rather than in the JSON value.
25-
"""
11+
"""Cursor conversation row from globalStorage cursorDiskKV; requires fullConversationHeadersOnly + createdAt."""
2612

2713
composer_id: str
2814
full_conversation_headers_only: list[dict[str, Any]]
@@ -72,17 +58,7 @@ def from_dict(cls, raw: dict[str, Any], *, composer_id: str) -> "Composer":
7258

7359
@dataclass(frozen=True)
7460
class WorkspaceLocalComposer:
75-
"""A composer entry from ``composer.composerData`` ItemTable rows.
76-
77-
These are summary records that live in each per-workspace ``state.vscdb``.
78-
They share ``composerId`` and ``lastUpdatedAt`` with the global composer
79-
schema, but they do **not** carry ``fullConversationHeadersOnly`` or
80-
``createdAt`` — those only exist on the global ``cursorDiskKV`` rows that
81-
``Composer.from_dict`` validates. Treating both shapes through the same
82-
model would reject every workspace-local entry, so this slim model
83-
exists to keep schema-drift detection at the boundary without conflating
84-
the two storage paths.
85-
"""
61+
"""Summary composer row from per-workspace state.vscdb ItemTable; only composerId is required."""
8662

8763
composer_id: str
8864
last_updated_at: Any = None
@@ -112,13 +88,7 @@ def from_dict(cls, raw: dict[str, Any]) -> "WorkspaceLocalComposer":
11288

11389
@dataclass(frozen=True)
11490
class Bubble:
115-
"""A single message bubble within a composer.
116-
117-
The bubble ID lives in the row key (``bubbleId:<composer_id>:<bubble_id>``)
118-
rather than the JSON value, so it is passed in explicitly. The raw dict
119-
is preserved to keep downstream rendering code (which still walks the
120-
untyped shape) working without modification.
121-
"""
91+
"""One message in a composer; bubble_id comes from the row key, not the JSON value."""
12292

12393
bubble_id: str
12494
raw: dict[str, Any] = field(default_factory=dict)

models/errors.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
1-
"""Exception types for the typed-model schema-validation layer."""
2-
31
from __future__ import annotations
42

53

64
class SchemaError(ValueError):
7-
"""Raised when a required Cursor schema field is missing or malformed.
8-
9-
Inherits from ``ValueError`` so call sites that already catch generic
10-
deserialisation errors (e.g. ``json.JSONDecodeError`` is a subclass of
11-
``ValueError``) also catch schema drift without needing a separate
12-
``except`` clause. New code should catch ``SchemaError`` explicitly.
13-
"""
5+
"""Raised when a required Cursor schema field is missing or malformed."""
146

157
def __init__(self, model: str, field: str, *, hint: str | None = None) -> None:
168
self.model = model

models/export.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"""ExportEntry — typed model for an export manifest record (JSONL line)."""
2-
31
from __future__ import annotations
42

53
from dataclasses import dataclass, field
@@ -10,13 +8,7 @@
108

119
@dataclass(frozen=True)
1210
class ExportEntry:
13-
"""A single record in the export manifest (one line in ``manifest.jsonl``).
14-
15-
Required fields are the YAML-frontmatter keys that downstream tooling
16-
indexes against: a missing ``log_id`` makes the entry unaddressable, and
17-
a missing ``title`` produces unreadable output. Timestamps are optional —
18-
not every Cursor conversation has both a creation and update time.
19-
"""
11+
"""One line of manifest.jsonl; log_id / title / workspace required, timestamps optional."""
2012

2113
log_id: str
2214
title: str

models/workspace.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"""Workspace — typed model for a single Cursor workspace folder."""
2-
31
from __future__ import annotations
42

53
from dataclasses import dataclass, field
@@ -10,14 +8,7 @@
108

119
@dataclass(frozen=True)
1210
class Workspace:
13-
"""A Cursor workspace entry.
14-
15-
The workspace ID is the directory name on disk (Cursor uses random
16-
short hashes as workspace IDs) and is passed in explicitly. ``folder``
17-
is the absolute path of the project the workspace targets, read from
18-
``workspace.json``; it may legitimately be ``None`` for a CLI-only
19-
workspace, so missing-folder is not a schema error.
20-
"""
11+
"""A Cursor workspace folder; folder is None for CLI-only workspaces (not a schema error)."""
2112

2213
workspace_id: str
2314
folder: str | None = None

tests/test_models.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,8 @@
1-
"""Regression tests for issue #24 — typed models + schema validation.
2-
3-
Three fixture-based tests, per the issue acceptance criteria:
4-
1. known-good Composer schema parses cleanly
5-
2. missing-field Composer schema raises SchemaError
6-
3. CliSessionMeta + ``_extract_blob_refs`` together exercise the binary
7-
blob path (``0x0a 0x20`` marker)
8-
9-
Run:
10-
python -m unittest tests.test_models -v
11-
"""
12-
131
from __future__ import annotations
142

153
import os
164
import sys
175
import unittest
18-
from pathlib import Path
196

207
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
218
if REPO_ROOT not in sys.path:

0 commit comments

Comments
 (0)