--- id: CUST-WP-0022 type: workplan title: Capability Request System domain: custodian status: done owner: custodian topic_slug: the-custodian created: "2026-03-19" updated: "2026-03-19" state_hub_workstream_id: "7cc173c6-f63e-43b0-af8e-04df7f95b96c" --- # CUST-WP-0022 — Capability Request System ## Purpose Enable cross-domain capability requests without requiring the requester to know which domain is responsible. A net-kingdom dev-worker can say "I need a privacy idea instance on the cluster" and the system routes it to railiance, manages the fulfillment lifecycle, and auto-notifies when work is ready for review. ## Scope - `capability_catalog` table — domains register capabilities they can provide - `capability_requests` table — lifecycle from requested → completed with auto-routing - Soft routing via keyword matching; broadcast fallback when ambiguous - Auto-notifications via AgentMessage on every lifecycle transition - Auto-unblock of blocking tasks on completion - 7 MCP tools, 1 dashboard page, StateSummary integration ## Files Changed | File | Change | |------|--------| | `migrations/versions/i6d7e8f9a0b1_capability_requests.py` | New migration | | `api/models/capability_catalog.py` | New model | | `api/models/capability_request.py` | New model | | `api/models/__init__.py` | Export new models | | `api/schemas/capability_request.py` | New schemas (Catalog + Request CRUD) | | `api/routers/capability_requests.py` | New router (lifecycle guard, routing, auto-notify) | | `api/main.py` | Mount new router | | `api/schemas/state.py` | Added `open_capability_requests` to StateSummary | | `api/routers/state.py` | Count open requests in summary builder | | `mcp_server/server.py` | 7 new MCP tools | | `dashboard/src/capability-requests.md` | New dashboard page (Kanban + KPIs) | | `dashboard/observablehq.config.js` | Nav entry | | `tests/test_capability_requests.py` | 14 test cases | | `scripts/ingest_capabilities.py` | Ingest `capability` blocks from SCOPE.md → catalog API | | `scripts/project_rules/scope.template` | Added `## Provided Capabilities` section | | `SCOPE.md` (repo root) | Added 3 capability blocks for custodian domain | | `dashboard/src/docs/capabilities.md` | Reference doc for capabilities | | `dashboard/src/docs/scope.md` | Reference doc for SCOPE.md | ## Tasks ### T01: Write TDD test suite ```task id: CUST-WP-0022-T01 status: done priority: high state_hub_task_id: "34f40ede-3396-4ef2-ae5a-9af4edbfc17d" ``` ### T02: Alembic migration ```task id: CUST-WP-0022-T02 status: done priority: high state_hub_task_id: "094fd9de-e4fa-4b9f-bc70-31f049907fa9" ``` ### T03: SQLAlchemy models ```task id: CUST-WP-0022-T03 status: done priority: high state_hub_task_id: "5fadabfb-100e-493e-a950-2b5c3d286c6b" ``` ### T04: Pydantic schemas ```task id: CUST-WP-0022-T04 status: done priority: high state_hub_task_id: "1efabfde-e9de-41d9-a864-2eb1e9e2dae6" ``` ### T05: Router with lifecycle + routing + auto-notify ```task id: CUST-WP-0022-T05 status: done priority: high state_hub_task_id: "57f754b6-022c-4829-adb5-45629567d575" ``` ### T06: Run tests, iterate until green ```task id: CUST-WP-0022-T06 status: done priority: high state_hub_task_id: "41ef3722-ffbe-41bb-9ef4-8485db37bb0a" ``` ### T07: MCP tools ```task id: CUST-WP-0022-T07 status: done priority: medium state_hub_task_id: "12f28272-2767-4d8e-80a0-a28bb172d6af" ``` ### T08: Dashboard page ```task id: CUST-WP-0022-T08 status: done priority: medium state_hub_task_id: "d6596ac4-53ac-4b44-bdd2-635b5c109372" ``` ### T09: StateSummary integration ```task id: CUST-WP-0022-T09 status: done priority: medium state_hub_task_id: "964e7f8b-e9f6-41f9-9eb1-ba35e48adf55" ``` ### T10: Seed catalog entries (file-first via SCOPE.md) ```task id: CUST-WP-0022-T10 status: done priority: low state_hub_task_id: "2c747cde-bc00-4fd9-a3cd-625709ac6d6d" ``` ## Design Notes - **Routing algorithm**: Exact match on capability_type in catalog. If 1 result → auto-assign. If multiple → keyword-score description against entry keywords, pick unambiguous winner. If 0 or tied → fulfilling_domain_id=NULL, broadcast AgentMessage. - **Lifecycle transitions** guarded by `_VALID_TRANSITIONS` dict (same pattern as contributions). - **Auto-unblock**: On `completed`, if `blocking_task_id` set and task status is `blocked`, patches it to `todo` and clears `blocking_reason`. - **Status uses String(20)** not SA Enum — avoids ALTER TYPE pain in future migrations. - **Third sanctioned write use case** — alongside resolve_decision and get_next_steps.