feat(classification-spine): implement STATE-WP-0065 repo-anchored model

Replace the ad-hoc coordination-domain spine with the Repo Classification
Standard: 14 market domains, classification columns on managed_repos, and
workplans anchored by repo_id (topic_id optional).

- Add Alembic migration d8e9f0a1b2c3 with data backfill and workstream→workplan rename
- Add api/classification.py validation and register-from-classification tooling
- Expose workplan-first REST/MCP surface with legacy workstream aliases
- Add C-24 consistency rule and legacy domain frontmatter mapping
- Update dashboard repos page with category/capability/stake filters
- Update orientation docs; mark STATE-WP-0065 finished
This commit is contained in:
2026-06-22 13:52:13 +02:00
parent 279be4ffbd
commit 0949d4c0d8
84 changed files with 4494 additions and 1111 deletions

View File

@@ -2,7 +2,7 @@ from __future__ import annotations
from typing import Any
from api.workplan_status import normalize_workstream_status
from api.workplan_status import normalize_workplan_status
EXECUTION_STATES = {
@@ -57,7 +57,7 @@ PRIORITY_RANK = {
"low": 3,
}
CLOSED_WORKSTREAM_STATUSES = {"finished", "archived"}
CLOSED_WORKPLAN_STATUSES = {"finished", "archived"}
def execution_state_for_launch(launch_mode: str, immediate_pickup: bool = False) -> str:
@@ -71,19 +71,24 @@ def execution_state_for_launch(launch_mode: str, immediate_pickup: bool = False)
return "queued"
def workstream_blockers(
workstream_id: Any,
def workplan_blockers(
workplan_id: Any,
dependency_targets: dict[Any, list[Any]],
workstream_status: dict[Any, str],
workplan_status: dict[Any, str],
workstream_id: Any = None,
) -> list[Any]:
scope_id = workplan_id if workplan_id is not None else workstream_id
blockers = []
for target_id in dependency_targets.get(workstream_id, []):
target_status = normalize_workstream_status(workstream_status.get(target_id))
if target_status not in CLOSED_WORKSTREAM_STATUSES:
for target_id in dependency_targets.get(scope_id, []):
target_status = normalize_workplan_status(workplan_status.get(target_id))
if target_status not in CLOSED_WORKPLAN_STATUSES:
blockers.append(target_id)
return blockers
workstream_blockers = workplan_blockers
def queue_sort_key(workstream: Any, *, eligible: bool) -> list[int | str]:
priority = str(getattr(workstream, "planning_priority", "") or "").strip().lower()
execution_state = str(getattr(workstream, "execution_state", "") or "manual").strip().lower()