generated from coulomb/repo-seed
feat(tasks): add needs_human intervention flag (CUST-WP-0009)
- Migration b4c5d6e7f8a9: adds needs_human (bool) + intervention_note (text) to tasks - API: needs_human filter on GET /tasks/; 422 if flagged without note - 3 MCP tools: flag_for_human, clear_human_flag, list_human_interventions - Dashboard: interventions.md with amber cards and "Mark done" button - Policy router + workstream DoD policy (workstream-dod.md) - Workstream lifecycle docs page + workplan CUST-WP-0010 - CLAUDE.md: add step 4 (run fix-consistency after workplan writes) - consistency_check.py: promote C-11 unlinked tasks from INFO to WARN Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
41
api/routers/policy.py
Normal file
41
api/routers/policy.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
POLICY_DIR = Path(__file__).parent.parent.parent / "policies"
|
||||
_VALID_NAME = re.compile(r"^[a-z0-9][a-z0-9-]{0,63}$")
|
||||
|
||||
router = APIRouter(prefix="/policy", tags=["policy"])
|
||||
|
||||
|
||||
class PolicyRead(BaseModel):
|
||||
name: str
|
||||
content: str
|
||||
|
||||
|
||||
class PolicyUpdate(BaseModel):
|
||||
content: str
|
||||
|
||||
|
||||
def _policy_path(name: str) -> Path:
|
||||
if not _VALID_NAME.match(name):
|
||||
raise HTTPException(status_code=400, detail="Invalid policy name")
|
||||
path = POLICY_DIR / f"{name}.md"
|
||||
if not path.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Policy '{name}' not found")
|
||||
return path
|
||||
|
||||
|
||||
@router.get("/{name}", response_model=PolicyRead)
|
||||
def get_policy(name: str) -> PolicyRead:
|
||||
path = _policy_path(name)
|
||||
return PolicyRead(name=name, content=path.read_text())
|
||||
|
||||
|
||||
@router.put("/{name}", response_model=PolicyRead)
|
||||
def update_policy(name: str, body: PolicyUpdate) -> PolicyRead:
|
||||
path = _policy_path(name)
|
||||
path.write_text(body.content)
|
||||
return PolicyRead(name=name, content=body.content)
|
||||
Reference in New Issue
Block a user