generated from coulomb/repo-seed
feat(state-hub): add Extension Points and Technical Debt tracking
New entity types (DB tables, API routers, Pydantic schemas, Alembic migration a3f1c2d4e5b6): - extension_points: ep_id, domain, title, ep_type, status, priority, location, description, topic_id, workstream_id - technical_debt: td_id, domain, title, debt_type, severity, status, location, description, topic_id, workstream_id MCP server: 6 new tools — register_extension_point, list_extension_points, update_ep_status, register_technical_debt, list_technical_debt, update_td_status (each write emits a progress_event) Dashboard: two new pages (extensions.md, techdept.md) with KPI sidebar, charts, urgent-items section, and filterable card lists. Both added to nav in observablehq.config.js. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -468,6 +468,167 @@ def list_dependencies(workstream_id: str) -> str:
|
||||
return json.dumps({"depends_on": depends_on, "blocks": blocks}, indent=2)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Extension points & technical debt
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@mcp.tool()
|
||||
def register_extension_point(
|
||||
domain: str,
|
||||
title: str,
|
||||
ep_type: str,
|
||||
description: str | None = None,
|
||||
location: str | None = None,
|
||||
priority: str = "medium",
|
||||
ep_id: str | None = None,
|
||||
topic_id: str | None = None,
|
||||
workstream_id: str | None = None,
|
||||
) -> str:
|
||||
"""Register a discovered extension point — optional future functionality not yet committed.
|
||||
|
||||
Extension points capture design forks: things the system *could* do that
|
||||
have been noticed and parked for deliberate later consideration.
|
||||
|
||||
Args:
|
||||
domain: one of custodian | railiance | markitect | coulomb_social | personhood | foerster_capabilities
|
||||
title: short description of the extension
|
||||
ep_type: api | schema | mcp | dashboard | architecture | integration | other
|
||||
description: longer explanation of what the extension would add
|
||||
location: file:line or module where the extension point was noticed
|
||||
priority: low | medium | high | critical
|
||||
ep_id: optional human-readable ID, e.g. EP-CUST-001 (auto-assigned if omitted)
|
||||
topic_id: UUID of related topic
|
||||
workstream_id: UUID of related workstream
|
||||
"""
|
||||
ep = _post("/extension-points", {
|
||||
"domain": domain, "title": title, "ep_type": ep_type,
|
||||
"description": description, "location": location,
|
||||
"priority": priority, "ep_id": ep_id,
|
||||
"topic_id": topic_id, "workstream_id": workstream_id,
|
||||
})
|
||||
_post("/progress", {
|
||||
"summary": f"Extension point registered: [{ep.get('ep_id') or ep['id'][:8]}] {title} ({ep_type}, {domain})",
|
||||
"event_type": "extension_point",
|
||||
"detail": {"id": ep["id"], "ep_id": ep.get("ep_id"), "ep_type": ep_type, "domain": domain},
|
||||
})
|
||||
return json.dumps(ep, indent=2)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def list_extension_points(
|
||||
domain: str | None = None,
|
||||
status: str | None = None,
|
||||
ep_type: str | None = None,
|
||||
) -> str:
|
||||
"""List extension points, optionally filtered.
|
||||
|
||||
Args:
|
||||
domain: filter by domain
|
||||
status: open | in_progress | addressed | deferred | wont_fix
|
||||
ep_type: api | schema | mcp | dashboard | architecture | integration | other
|
||||
"""
|
||||
return json.dumps(_get("/extension-points", {
|
||||
"domain": domain, "status": status, "ep_type": ep_type,
|
||||
}), indent=2)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def update_ep_status(ep_uuid: str, status: str) -> str:
|
||||
"""Update the status of an extension point.
|
||||
|
||||
Args:
|
||||
ep_uuid: UUID of the extension point
|
||||
status: open | in_progress | addressed | deferred | wont_fix
|
||||
"""
|
||||
ep = _patch(f"/extension-points/{ep_uuid}", {"status": status})
|
||||
_post("/progress", {
|
||||
"summary": f"Extension point status → {status}: {ep['title']}",
|
||||
"event_type": "extension_point",
|
||||
"detail": {"id": ep_uuid, "status": status},
|
||||
})
|
||||
return json.dumps(ep, indent=2)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def register_technical_debt(
|
||||
domain: str,
|
||||
title: str,
|
||||
debt_type: str,
|
||||
description: str | None = None,
|
||||
location: str | None = None,
|
||||
severity: str = "medium",
|
||||
td_id: str | None = None,
|
||||
topic_id: str | None = None,
|
||||
workstream_id: str | None = None,
|
||||
) -> str:
|
||||
"""Register a technical debt item — a known quality compromise to address later.
|
||||
|
||||
Technical debt captures intentional or discovered shortcuts, design
|
||||
weaknesses, missing tests, and similar issues that reduce codebase health.
|
||||
|
||||
Args:
|
||||
domain: one of custodian | railiance | markitect | coulomb_social | personhood | foerster_capabilities
|
||||
title: short description of the debt
|
||||
debt_type: design | implementation | test | docs | dependencies | performance | security | other
|
||||
description: what the issue is and what the correct fix would be
|
||||
location: file:line or module where the debt lives
|
||||
severity: low | medium | high | critical
|
||||
td_id: optional human-readable ID, e.g. TD-CUST-001
|
||||
topic_id: UUID of related topic
|
||||
workstream_id: UUID of related workstream
|
||||
"""
|
||||
td = _post("/technical-debt", {
|
||||
"domain": domain, "title": title, "debt_type": debt_type,
|
||||
"description": description, "location": location,
|
||||
"severity": severity, "td_id": td_id,
|
||||
"topic_id": topic_id, "workstream_id": workstream_id,
|
||||
})
|
||||
_post("/progress", {
|
||||
"summary": f"Technical debt registered: [{td.get('td_id') or td['id'][:8]}] {title} ({debt_type}, {severity}, {domain})",
|
||||
"event_type": "technical_debt",
|
||||
"detail": {"id": td["id"], "td_id": td.get("td_id"), "debt_type": debt_type, "severity": severity, "domain": domain},
|
||||
})
|
||||
return json.dumps(td, indent=2)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def list_technical_debt(
|
||||
domain: str | None = None,
|
||||
status: str | None = None,
|
||||
debt_type: str | None = None,
|
||||
severity: str | None = None,
|
||||
) -> str:
|
||||
"""List technical debt items, optionally filtered.
|
||||
|
||||
Args:
|
||||
domain: filter by domain
|
||||
status: open | in_progress | resolved | deferred | wont_fix
|
||||
debt_type: design | implementation | test | docs | dependencies | performance | security | other
|
||||
severity: low | medium | high | critical
|
||||
"""
|
||||
return json.dumps(_get("/technical-debt", {
|
||||
"domain": domain, "status": status,
|
||||
"debt_type": debt_type, "severity": severity,
|
||||
}), indent=2)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def update_td_status(td_uuid: str, status: str) -> str:
|
||||
"""Update the status of a technical debt item.
|
||||
|
||||
Args:
|
||||
td_uuid: UUID of the technical debt item
|
||||
status: open | in_progress | resolved | deferred | wont_fix
|
||||
"""
|
||||
td = _patch(f"/technical-debt/{td_uuid}", {"status": status})
|
||||
_post("/progress", {
|
||||
"summary": f"Technical debt status → {status}: {td['title']}",
|
||||
"event_type": "technical_debt",
|
||||
"detail": {"id": td_uuid, "status": status},
|
||||
})
|
||||
return json.dumps(td, indent=2)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Entry point
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user