state-hub/api/schemas/state.py

83 lines
2.1 KiB
Python
Raw Normal View History

Implement State Hub v0.2: dependency graph, next-steps suggestions, design boundary S0 — Design boundary formalised across all integration surfaces: - TOOLS.md restructured with Design Boundary section, Sanctioned Write Tools, and Bootstrap-Only Tools (create_workstream, create_task) with explicit note - project_claude_md.template and railiance CLAUDE.md updated with boundary note and get_next_steps() in session start protocol - Global ~/.claude/CLAUDE.md updated accordingly S1 — Workstream dependency graph: - WorkstreamDependency model (directed edge, CASCADE on delete, unique pair constraint) - Alembic migration 0b547c153153; script.py.mako added (was missing) - REST API: POST/GET /workstreams/{id}/dependencies/, DELETE …/{dep_id} (hard delete) - StateSummary open_workstreams enriched with depends_on/blocks lists - MCP tools: create_dependency(), list_dependencies() - Dashboard workstreams page: Dependencies section with relationship cards - Seeded: custodian-agent-runtime → llm-shared-library + phase-0-operational-baseline S2 — Suggesting Next Steps (sanctioned write use case #2): - GET /state/next_steps derives suggestions from recently resolved decisions (→ first open task in same workstream) and cleared dependencies (→ first todo task in now-unblocked workstream) - StateSummary.next_steps included on every summary call - MCP tool: get_next_steps() - Dashboard: "What's next?" card grid above Registered Projects Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 23:33:14 +01:00
import uuid
from datetime import datetime
from pydantic import BaseModel
from api.schemas.decision import DecisionRead
feat(state-hub): implement v0.5 — dynamic domains & multi-repo Replaces the hardcoded 6-domain PostgreSQL ENUM with a first-class `domains` DB table, and adds a `managed_repos` table for multi-repo support per domain. P1 — Domain as a DB entity: - Migration b1c2d3e4f5a6: creates `domains` table, migrates topics.domain ENUM column to domain_id FK, drops the domain ENUM type - Domain ORM model (api/models/domain.py) + Pydantic schemas - Domain API router: GET/POST /domains/, GET/PATCH /domains/{slug}/, rename and archive endpoints with EP/TD cascade on rename - Topic model updated: domain_id FK + @property domain_slug for backwards-compatible JSON serialization (field renamed domain → domain_slug) - TopicCreate/TopicRead updated; seed.py rewritten to use FK lookup P2 — Multi-repo support: - ManagedRepo ORM model (api/models/managed_repo.py) + schemas - Repo API router: GET/POST /repos/, GET/PATCH /repos/{slug}/, archive - Makefile: add-domain, rename-domain, add-repo, list-repos targets - register_project.sh: verify domain via /domains/ API + POST /repos/ P3 — MCP tools & live validation: - 6 new MCP tools: list_domains, create_domain, rename_domain, archive_domain, list_domain_repos, register_repo - EP/TD routers: replace hardcoded VALID_DOMAINS set with per-request DB lookup — returns 422 with list of valid slugs on unknown domain - State summary: adds domains: list[DomainSummary] (slug, name, repo_count, active_workstream_count, ep_count, td_count) - TOOLS.md updated with domain management section P4 — Dashboard: - New domains.md page with KPI row + domain cards + repo lists - domains.json.py + repos.json.py data loaders - Domains page added to observablehq.config.js nav - workstreams.md, extensions.md, techdept.md: domain_slug fix + dynamic domain list loaded from /domains/ API (no longer hardcoded) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 15:20:15 +01:00
from api.schemas.domain import DomainSummary
from api.schemas.progress_event import ProgressEventRead
from api.schemas.task import TaskRead
from api.schemas.topic import TopicWithWorkstreams
Implement State Hub v0.2: dependency graph, next-steps suggestions, design boundary S0 — Design boundary formalised across all integration surfaces: - TOOLS.md restructured with Design Boundary section, Sanctioned Write Tools, and Bootstrap-Only Tools (create_workstream, create_task) with explicit note - project_claude_md.template and railiance CLAUDE.md updated with boundary note and get_next_steps() in session start protocol - Global ~/.claude/CLAUDE.md updated accordingly S1 — Workstream dependency graph: - WorkstreamDependency model (directed edge, CASCADE on delete, unique pair constraint) - Alembic migration 0b547c153153; script.py.mako added (was missing) - REST API: POST/GET /workstreams/{id}/dependencies/, DELETE …/{dep_id} (hard delete) - StateSummary open_workstreams enriched with depends_on/blocks lists - MCP tools: create_dependency(), list_dependencies() - Dashboard workstreams page: Dependencies section with relationship cards - Seeded: custodian-agent-runtime → llm-shared-library + phase-0-operational-baseline S2 — Suggesting Next Steps (sanctioned write use case #2): - GET /state/next_steps derives suggestions from recently resolved decisions (→ first open task in same workstream) and cleared dependencies (→ first todo task in now-unblocked workstream) - StateSummary.next_steps included on every summary call - MCP tool: get_next_steps() - Dashboard: "What's next?" card grid above Registered Projects Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 23:33:14 +01:00
from api.schemas.workstream import WorkstreamWithDeps
class TopicTotals(BaseModel):
active: int = 0
paused: int = 0
archived: int = 0
total: int = 0
class WorkstreamTotals(BaseModel):
active: int = 0
blocked: int = 0
completed: int = 0
archived: int = 0
total: int = 0
class TaskTotals(BaseModel):
todo: int = 0
in_progress: int = 0
blocked: int = 0
done: int = 0
cancelled: int = 0
total: int = 0
class DecisionTotals(BaseModel):
open: int = 0
resolved: int = 0
escalated: int = 0
superseded: int = 0
total: int = 0
class Totals(BaseModel):
topics: TopicTotals
workstreams: WorkstreamTotals
tasks: TaskTotals
decisions: DecisionTotals
Implement State Hub v0.2: dependency graph, next-steps suggestions, design boundary S0 — Design boundary formalised across all integration surfaces: - TOOLS.md restructured with Design Boundary section, Sanctioned Write Tools, and Bootstrap-Only Tools (create_workstream, create_task) with explicit note - project_claude_md.template and railiance CLAUDE.md updated with boundary note and get_next_steps() in session start protocol - Global ~/.claude/CLAUDE.md updated accordingly S1 — Workstream dependency graph: - WorkstreamDependency model (directed edge, CASCADE on delete, unique pair constraint) - Alembic migration 0b547c153153; script.py.mako added (was missing) - REST API: POST/GET /workstreams/{id}/dependencies/, DELETE …/{dep_id} (hard delete) - StateSummary open_workstreams enriched with depends_on/blocks lists - MCP tools: create_dependency(), list_dependencies() - Dashboard workstreams page: Dependencies section with relationship cards - Seeded: custodian-agent-runtime → llm-shared-library + phase-0-operational-baseline S2 — Suggesting Next Steps (sanctioned write use case #2): - GET /state/next_steps derives suggestions from recently resolved decisions (→ first open task in same workstream) and cleared dependencies (→ first todo task in now-unblocked workstream) - StateSummary.next_steps included on every summary call - MCP tool: get_next_steps() - Dashboard: "What's next?" card grid above Registered Projects Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 23:33:14 +01:00
class NextStep(BaseModel):
"""A derived suggestion pointing to where work should happen next.
Suggestions are never persisted they are computed on demand from
current hub state: recently resolved decisions, newly unblocked tasks,
cleared dependencies.
"""
type: str # unblocked_task | resolved_decision | dependency_cleared
domain: str | None = None
workstream_id: uuid.UUID | None = None
workstream_title: str | None = None
workstream_slug: str | None = None
task_id: uuid.UUID | None = None
task_title: str | None = None
message: str # plain-language explanation
class StateSummary(BaseModel):
generated_at: datetime
totals: Totals
topics: list[TopicWithWorkstreams]
blocking_decisions: list[DecisionRead]
blocked_tasks: list[TaskRead]
recent_progress: list[ProgressEventRead]
Implement State Hub v0.2: dependency graph, next-steps suggestions, design boundary S0 — Design boundary formalised across all integration surfaces: - TOOLS.md restructured with Design Boundary section, Sanctioned Write Tools, and Bootstrap-Only Tools (create_workstream, create_task) with explicit note - project_claude_md.template and railiance CLAUDE.md updated with boundary note and get_next_steps() in session start protocol - Global ~/.claude/CLAUDE.md updated accordingly S1 — Workstream dependency graph: - WorkstreamDependency model (directed edge, CASCADE on delete, unique pair constraint) - Alembic migration 0b547c153153; script.py.mako added (was missing) - REST API: POST/GET /workstreams/{id}/dependencies/, DELETE …/{dep_id} (hard delete) - StateSummary open_workstreams enriched with depends_on/blocks lists - MCP tools: create_dependency(), list_dependencies() - Dashboard workstreams page: Dependencies section with relationship cards - Seeded: custodian-agent-runtime → llm-shared-library + phase-0-operational-baseline S2 — Suggesting Next Steps (sanctioned write use case #2): - GET /state/next_steps derives suggestions from recently resolved decisions (→ first open task in same workstream) and cleared dependencies (→ first todo task in now-unblocked workstream) - StateSummary.next_steps included on every summary call - MCP tool: get_next_steps() - Dashboard: "What's next?" card grid above Registered Projects Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 23:33:14 +01:00
open_workstreams: list[WorkstreamWithDeps]
next_steps: list[NextStep] = []
feat(state-hub): implement v0.5 — dynamic domains & multi-repo Replaces the hardcoded 6-domain PostgreSQL ENUM with a first-class `domains` DB table, and adds a `managed_repos` table for multi-repo support per domain. P1 — Domain as a DB entity: - Migration b1c2d3e4f5a6: creates `domains` table, migrates topics.domain ENUM column to domain_id FK, drops the domain ENUM type - Domain ORM model (api/models/domain.py) + Pydantic schemas - Domain API router: GET/POST /domains/, GET/PATCH /domains/{slug}/, rename and archive endpoints with EP/TD cascade on rename - Topic model updated: domain_id FK + @property domain_slug for backwards-compatible JSON serialization (field renamed domain → domain_slug) - TopicCreate/TopicRead updated; seed.py rewritten to use FK lookup P2 — Multi-repo support: - ManagedRepo ORM model (api/models/managed_repo.py) + schemas - Repo API router: GET/POST /repos/, GET/PATCH /repos/{slug}/, archive - Makefile: add-domain, rename-domain, add-repo, list-repos targets - register_project.sh: verify domain via /domains/ API + POST /repos/ P3 — MCP tools & live validation: - 6 new MCP tools: list_domains, create_domain, rename_domain, archive_domain, list_domain_repos, register_repo - EP/TD routers: replace hardcoded VALID_DOMAINS set with per-request DB lookup — returns 422 with list of valid slugs on unknown domain - State summary: adds domains: list[DomainSummary] (slug, name, repo_count, active_workstream_count, ep_count, td_count) - TOOLS.md updated with domain management section P4 — Dashboard: - New domains.md page with KPI row + domain cards + repo lists - domains.json.py + repos.json.py data loaders - Domains page added to observablehq.config.js nav - workstreams.md, extensions.md, techdept.md: domain_slug fix + dynamic domain list loaded from /domains/ API (no longer hardcoded) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 15:20:15 +01:00
domains: list[DomainSummary] = []
contribution_counts: dict[str, int] = {}
licence_risk_count: int = 0
open_capability_requests: int = 0