state-hub/api/routers/workstream_dependencies.py

183 lines
6.3 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 fastapi import APIRouter, Depends, HTTPException, Request, Response, status
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 sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from api.database import get_session
from api.models.task import Task
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.models.workstream import Workstream
from api.models.workstream_dependency import WorkstreamDependency
from api.schemas.workstream_dependency import WorkstreamDependencyCreate, WorkstreamDependencyRead
from api.routers.workstreams import _legacy_key, _meter_legacy_route
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
router = APIRouter(prefix="/workstreams", tags=["dependencies"])
workplan_router = APIRouter(prefix="/workplans", tags=["dependencies"])
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
async def _create_dependency(
*,
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
workstream_id: uuid.UUID,
body: WorkstreamDependencyCreate,
session: AsyncSession,
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
) -> WorkstreamDependency:
if await session.get(Workstream, workstream_id) is None:
raise HTTPException(status_code=404, detail="from workplan not found")
has_workstream_target = body.to_workstream_id is not None
has_task_target = body.to_task_id is not None
if has_workstream_target == has_task_target:
raise HTTPException(status_code=422, detail="provide exactly one dependency target")
if body.to_workstream_id and await session.get(Workstream, body.to_workstream_id) is None:
raise HTTPException(status_code=404, detail="target workplan not found")
if body.to_task_id and await session.get(Task, body.to_task_id) is None:
raise HTTPException(status_code=404, detail="target task not found")
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
if workstream_id == body.to_workstream_id:
raise HTTPException(status_code=422, detail="a workplan cannot depend on itself")
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
dep = WorkstreamDependency(
from_workstream_id=workstream_id,
to_workstream_id=body.to_workstream_id,
to_task_id=body.to_task_id,
relationship_type=body.relationship_type,
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
description=body.description,
)
session.add(dep)
await session.commit()
await session.refresh(dep)
return dep
async def _list_dependencies(
*,
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
workstream_id: uuid.UUID,
session: AsyncSession,
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
) -> list[WorkstreamDependency]:
if await session.get(Workstream, workstream_id) is None:
raise HTTPException(status_code=404, detail="workplan not found")
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
rows = await session.execute(
select(WorkstreamDependency).where(
(WorkstreamDependency.from_workstream_id == workstream_id)
| (WorkstreamDependency.to_workstream_id == workstream_id)
)
)
return list(rows.scalars().all())
async def _delete_dependency(
*,
workstream_id: uuid.UUID,
dep_id: uuid.UUID,
session: AsyncSession,
) -> None:
dep = await session.get(WorkstreamDependency, dep_id)
if dep is None:
raise HTTPException(status_code=404, detail="dependency not found")
if dep.from_workstream_id != workstream_id:
raise HTTPException(status_code=403, detail="dependency does not belong to this workplan")
await session.delete(dep)
await session.commit()
@router.post(
"/{workstream_id}/dependencies/",
response_model=WorkstreamDependencyRead,
status_code=status.HTTP_201_CREATED,
)
async def create_dependency(
request: Request,
response: Response,
workstream_id: uuid.UUID,
body: WorkstreamDependencyCreate,
session: AsyncSession = Depends(get_session),
) -> WorkstreamDependency:
"""Record that workstream_id depends on another workstream or a task."""
await _meter_legacy_route(
session=session,
request=request,
response=response,
interface_key=_legacy_key("POST", "/workstreams/{workstream_id}/dependencies/"),
replacement_ref="/workplans/{workplan_id}/dependencies/",
)
return await _create_dependency(workstream_id=workstream_id, body=body, session=session)
@workplan_router.post(
"/{workplan_id}/dependencies/",
response_model=WorkstreamDependencyRead,
status_code=status.HTTP_201_CREATED,
)
async def create_workplan_dependency(
workplan_id: uuid.UUID,
body: WorkstreamDependencyCreate,
session: AsyncSession = Depends(get_session),
) -> WorkstreamDependency:
return await _create_dependency(workstream_id=workplan_id, body=body, session=session)
@router.get(
"/{workstream_id}/dependencies/",
response_model=list[WorkstreamDependencyRead],
)
async def list_dependencies(
request: Request,
response: Response,
workstream_id: uuid.UUID,
session: AsyncSession = Depends(get_session),
) -> list[WorkstreamDependency]:
"""Return all dependency edges touching this workstream (both directions)."""
await _meter_legacy_route(
session=session,
request=request,
response=response,
interface_key=_legacy_key("GET", "/workstreams/{workstream_id}/dependencies/"),
replacement_ref="/workplans/{workplan_id}/dependencies/",
)
return await _list_dependencies(workstream_id=workstream_id, session=session)
@workplan_router.get(
"/{workplan_id}/dependencies/",
response_model=list[WorkstreamDependencyRead],
)
async def list_workplan_dependencies(
workplan_id: uuid.UUID,
session: AsyncSession = Depends(get_session),
) -> list[WorkstreamDependency]:
return await _list_dependencies(workstream_id=workplan_id, session=session)
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
@router.delete(
"/{workstream_id}/dependencies/{dep_id}",
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_dependency(
request: Request,
response: Response,
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
workstream_id: uuid.UUID,
dep_id: uuid.UUID,
session: AsyncSession = Depends(get_session),
) -> None:
"""Hard-delete a dependency edge. Removing a constraint is safe — no information is lost."""
await _meter_legacy_route(
session=session,
request=request,
response=response,
interface_key=_legacy_key("DELETE", "/workstreams/{workstream_id}/dependencies/{dep_id}"),
replacement_ref="/workplans/{workplan_id}/dependencies/{dep_id}",
)
await _delete_dependency(workstream_id=workstream_id, dep_id=dep_id, session=session)
@workplan_router.delete(
"/{workplan_id}/dependencies/{dep_id}",
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_workplan_dependency(
workplan_id: uuid.UUID,
dep_id: uuid.UUID,
session: AsyncSession = Depends(get_session),
) -> None:
await _delete_dependency(workstream_id=workplan_id, dep_id=dep_id, session=session)