Consolidates all open technical debt into three workplans: - CUST-WP-0018: API hardening & code quality (TD-006–019 medium/high items) - CUST-WP-0019: Dashboard UX polish (Repos nav restructure, config.js cleanup, todo filter fix for new suggestion workflow statuses) - CUST-WP-0020: pytest test suite with real DB (TD-014) Also fixes todo.md Suggestions filter: was checking status===open but new suggestions enter with status=submitted; now excludes terminal statuses only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.2 KiB
id, type, title, domain, status, owner, topic_slug, created, updated
| id | type | title | domain | status | owner | topic_slug | created | updated |
|---|---|---|---|---|---|---|---|---|
| CUST-WP-0018 | workplan | State Hub — API Hardening & Code Quality | custodian | active | custodian | custodian | 2026-03-18 | 2026-03-18 |
State Hub — API Hardening & Code Quality
Summary
Resolve all open medium/high technical debt items in the API and MCP server. These are small, targeted fixes: datetime correctness, missing filter params, MCP error handling, and a bundle of low-severity cleanup items. No schema migrations required.
Resolves
TD-CUST-006, TD-CUST-007, TD-CUST-008, TD-CUST-009, TD-CUST-010, TD-CUST-011, TD-CUST-012, TD-CUST-013, TD-CUST-015, TD-CUST-016, TD-CUST-017, TD-CUST-018, TD-CUST-019
TD-CUST-005 (N+1 selectin) deferred — not pressing at current scale.
Tasks
T01 — Fix deprecated datetime.utcnow() in MCP server
id: CUST-WP-0018-T01
status: todo
priority: high
Replace datetime.utcnow() with datetime.now(tz=timezone.utc) throughout
state-hub/mcp_server/server.py. Resolves TD-CUST-006 and TD-CUST-013
(mixed naive/aware datetime handling). One-line change with broad correctness
impact.
Location: state-hub/mcp_server/server.py:343 (and any other occurrences)
T02 — MCP HTTP helpers: catch exceptions and return user-friendly errors
id: CUST-WP-0018-T02
status: todo
priority: high
Wrap _get(), _post(), _patch(), _delete() in a try/except that
catches httpx.HTTPError and Exception, returning a structured error dict
instead of letting the MCP tool crash with a stack trace. Resolves TD-CUST-015.
Location: state-hub/mcp_server/server.py:34–69
Pattern:
try:
r = await client.get(url, ...)
r.raise_for_status()
return r.json()
except httpx.HTTPStatusError as e:
return {"error": f"API {e.response.status_code}: {e.response.text[:200]}"}
except Exception as e:
return {"error": f"Request failed: {e}"}
T03 — Decision write_log: warn when project path not found
id: CUST-WP-0018-T03
status: todo
priority: medium
_write_project_log() in decisions.py silently returns when the project
path directory does not exist. Add a log warning so the caller knows the write
was skipped. Resolves TD-CUST-012.
Location: state-hub/api/routers/decisions.py:147–196
T04 — Add priority and due_date filters to task list endpoint
id: CUST-WP-0018-T04
status: todo
priority: medium
Add priority: str | None and due_date_before: date | None query params to
list_tasks(). Resolves TD-CUST-007.
Location: state-hub/api/routers/tasks.py:14–30
T05 — Add owner and slug filters to workstream list endpoint
id: CUST-WP-0018-T05
status: todo
priority: medium
Add owner: str | None and slug: str | None query params to
list_workstreams(). Resolves TD-CUST-008.
Location: state-hub/api/routers/workstreams.py:14–27
T06 — Add offset pagination to progress event list endpoint
id: CUST-WP-0018-T06
status: todo
priority: medium
Add offset: int = 0 query param to list_progress() alongside existing
limit. Resolves TD-CUST-010.
Location: state-hub/api/routers/progress.py:15–38
T07 — Low-severity cleanup bundle
id: CUST-WP-0018-T07
status: todo
priority: low
Bundle of small fixes (each a few lines):
- TD-CUST-009: Document
decision_typefilter in OpenAPI schema forlist_decisions()consistently with other filter params. - TD-CUST-011: Make
seed.pyupsert-based — update existing rows when field values change (useON CONFLICT ... DO UPDATE). - TD-CUST-016: Normalise filter bar CSS class names across dashboard pages
(
filter-searchvsfilter-owner→ usefilter-text-inputeverywhere). - TD-CUST-017: Read CORS origins from
CORS_ORIGINSenv var (comma-separated), defaulting tolocalhost:3000; remove hard-coded list frommain.py. - TD-CUST-018: Add a
ProgressEventCreate.detailvalidator that at minimum rejects non-dict values (dict-or-None is sufficient). - TD-CUST-019: Add comment explaining the 30.5 avg-days-per-month constant
in
decisions.md:99.
Locations: Various — see TD item descriptions for exact file:line refs.