Skip to content

cppa-cursor-browser: cleanup workspace_tabs and cursor_md_exporter hygiene debt #136

Description

@clean6378-max-it

Calendar Day

Backlog follow-up (discovered July 16, 2026 during refactor/trim-model-exports review)

Planned Effort

3–5 story points (Medium) — not on Week 29 sprint; file separately from Thursday PR 2

Problem

Code cleanup review of refactor/trim-model-exports found 12 pre-existing issues in unchanged portions of services/workspace_tabs.py, utils/cursor_md_exporter.py, and utils/display_bubble.py. None were introduced by the export trim (removing BubbleRole / BubbleMetadata from models/__all__). They are valid repair targets but out of scope for PR 2.

Goal

One follow-up PR reducing duplication, narrowing exception handling, and fixing small performance/hygiene issues in the tabs and markdown-export paths. No behavior change unless a bug is found while refactoring.

Scope

Medium priority

  1. services/workspace_tabs.py_assemble_tab_from_composer_data (~241 lines): extract sequential phases (bubble build, sort/annotate, metadata aggregation, tab dict construction).
  2. services/workspace_tabs.py — duplicate composer-row loop in _build_workspace_tab_summaries_uncached and assemble_workspace_tabs; extract shared iteration/guard/exception skeleton with a callback or generator.
  3. services/workspace_tabs.pyexcept Exception at L517 and L774; narrow to KeyError, TypeError, ValueError, json.JSONDecodeError (and similar realistic parse failures).
  4. utils/cursor_md_exporter.pycursor_ide_chat_to_markdown (~273 lines): extract phases (bubbles, aggregates, activity scan, frontmatter, body).
  5. utils/cursor_md_exporter.py — duplicate tool-call markdown rendering in cursor_cli_session_to_markdown and cursor_ide_chat_to_markdown; extract _render_tool_call_md(tc) -> str.

Low priority

  1. services/workspace_tabs.py — repeated error literals ("Conversation not found" ×4, "Global storage not found" ×3); extract named constants.
  2. services/workspace_tabs.pycontext_text += in nested loops (L170–209); accumulate list and join once.
  3. services/workspace_tabs.py — restating comments at L683 and L782; delete.
  4. utils/cursor_md_exporter.pybody += in per-bubble loops (CLI and IDE paths); use list + join (match fm_lines pattern).
  5. utils/cursor_md_exporter.pyexcept Exception at L93 when reading CLI session metadata; narrow to sqlite3.Error, json.JSONDecodeError, IndexError, TypeError.
  6. utils/display_bubble.pycast(BubbleMetadata, …) at L129 and L160; type build_storage_bubble_metadata as BubbleMetadata | None to drop casts (also affects workspace_tabs.py).

Out of scope

  • Further models/__init__.py export trimming (Thursday PR 2 scope).
  • RuleTokens threading, release tag, or other Week 29 items.

Acceptance Criteria

  • _assemble_tab_from_composer_data split into named phase helpers (or equivalent structure with no 200+ line body).
  • Shared composer-row loop extracted; both call sites use it.
  • Broad except Exception narrowed in scoped locations (or documented if intentionally broad).
  • Tool-call markdown rendering deduplicated between CLI and IDE export paths.
  • String concatenation in hot loops replaced with list + join where touched.
  • mypy --strict + full pytest -q green; no user-visible export/tab behavior change.

Verification

cd C:\Users\Jasen\CppAliance\cppa-cursor-browser
.\.venv\Scripts\Activate.ps1
mypy --strict services/workspace_tabs.py utils/cursor_md_exporter.py utils/display_bubble.py
pytest -q tests/test_workspace_tabs.py tests/test_export_engine.py
pytest -q -k "export or tab"
pytest -q

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Fields

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