--- title: Capability Requests --- ```js import {API, apiFetch, pollDelay, waitForVisible} from "./components/config.js"; const POLL = 30_000; ``` ```js // Live poll for capability requests const reqState = (async function*() { let failures = 0; while (true) { let data = [], ok = false; try { const r = await apiFetch("/capability-requests/"); ok = r.ok; data = ok ? await r.json() : []; } catch {} failures = ok ? 0 : failures + 1; yield {data, ok, ts: new Date()}; await waitForVisible(pollDelay({ok, base: POLL, failures})); } })(); ``` ```js const requests = reqState.data ?? []; const _ok = reqState.ok ?? false; const _ts = reqState.ts; ``` # Capability Requests ```js import {injectTocTop} from "./components/toc-sidebar.js"; import {withDocHelp} from "./components/doc-overlay.js"; const _liveEl = html`
${_ok ? `Live · ${_ts?.toLocaleTimeString()}` : html`API offline`}
`; withDocHelp(_liveEl, "/docs/live-data"); injectTocTop("live-indicator", _liveEl); const _h1 = document.querySelector("#observablehq-main h1"); if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/capabilities"); } ``` ```js // KPI sidebar const open = requests.filter(r => ["requested","routing_disputed","accepted","in_progress","ready_for_review"].includes(r.status)); const completed = requests.filter(r => r.status === "completed"); const avgFulfill = completed.length > 0 ? (completed.reduce((s, r) => s + (new Date(r.completed_at) - new Date(r.created_at)), 0) / completed.length / 86400000).toFixed(1) : "—"; const critical = open.filter(r => r.priority === "critical" || r.priority === "high").length; const kpiEl = html`
Capability Requests
Open${open.length} Avg fulfill${avgFulfill}d High/Critical${critical} Total${requests.length}
`; injectTocTop("cap-req-kpi", kpiEl); ``` ```js // Filters const typeFilter = Inputs.select( ["all", ...new Set(requests.map(r => r.capability_type))], {label: "Type", value: "all"} ); const statFilter = Inputs.select( ["all", "routing_disputed", "requested", "accepted", "in_progress", "ready_for_review", "completed", "rejected", "withdrawn"], {label: "Status", value: "all"} ); const domFilter = Inputs.select( ["all", ...new Set([...requests.map(r => r.requesting_domain_slug), ...requests.map(r => r.fulfilling_domain_slug).filter(Boolean)])], {label: "Domain", value: "all"} ); display(html`
${typeFilter}${statFilter}${domFilter}
`); ``` ```js const tf = typeFilter.value; const sf = statFilter.value; const df = domFilter.value; const filtered = requests.filter(r => (tf === "all" || r.capability_type === tf) && (sf === "all" || r.status === sf) && (df === "all" || r.requesting_domain_slug === df || r.fulfilling_domain_slug === df) ); ``` ## Summary ```js const priorityColors = {critical: "#e53935", high: "orange", medium: "steelblue", low: "#aaa"}; const disputed = requests.filter(r => r.status === "routing_disputed"); // Disputed banner — shown at top when any exist if (disputed.length > 0) { display(html`
⚠ Routing Disputed (${disputed.length})
${disputed.map(r => html`
${r.title} ${r.requesting_domain_slug} → ${r.fulfilling_domain_slug ?? "unassigned"}
Dispute: ${r.dispute_reason ?? "(no reason given)"}
${r.dispute_suggested_domain ? html`
Suggested domain: ${r.dispute_suggested_domain}
` : ""} ${r.disputed_by ? html`
Raised by ${r.disputed_by} · ${new Date(r.disputed_at).toLocaleString()}
` : ""}
`)}
`); } display(html`

Requested

${requests.filter(r => r.status === "requested").length}

In Progress

${requests.filter(r => ["accepted","in_progress"].includes(r.status)).length}

Ready for Review

${requests.filter(r => r.status === "ready_for_review").length}

Completed

${completed.length}

`); ``` ## Status Kanban ```js const statusCols = [ {key: "routing_disputed", label: "⚠ Routing Disputed", color: "#f59e0b"}, {key: "requested", label: "Requested", color: "steelblue"}, {key: "accepted", label: "Accepted", color: "#f0a500"}, {key: "in_progress", label: "In Progress", color: "#2196f3"}, {key: "ready_for_review", label: "Ready for Review", color: "#4caf50"}, {key: "completed", label: "Completed", color: "#2e7d32"}, {key: "rejected", label: "Rejected", color: "#e53935"}, {key: "withdrawn", label: "Withdrawn", color: "#bbb"}, ]; const colMap = {}; for (const r of filtered) { (colMap[r.status] = colMap[r.status] ?? []).push(r); } const activeCols = statusCols.filter(s => colMap[s.key]?.length); if (activeCols.length === 0) { display(html`

No capability requests match the current filters.

`); } else { const ageDays = (r) => ((Date.now() - new Date(r.created_at)) / 86400000).toFixed(0); display(html`
${activeCols.map(s => html`
${s.label} ${colMap[s.key].length}
${colMap[s.key].map(r => html`
${r.capability_type}
${r.priority}
${r.title}
${r.requesting_domain_slug} ${r.fulfilling_domain_slug ? html` → ${r.fulfilling_domain_slug}` : html` → unassigned`}
${ageDays(r)}d old
`)}
`)}
`); } ``` ## All Requests ```js display(Inputs.table(filtered.map(r => ({ Type: r.capability_type, Title: r.title, Priority: r.priority, Status: r.status, Requester: r.requesting_domain_slug, Provider: r.fulfilling_domain_slug ?? "—", Agent: r.requesting_agent, Created: new Date(r.created_at).toLocaleDateString(), })), {maxWidth: 1000})); ``` --- ## Capability Catalog ```js // Live poll for catalog entries const catalogState = (async function*() { let failures = 0; while (true) { let data = [], ok = false; try { const r = await apiFetch("/capability-catalog/?status=all"); ok = r.ok; if (r.ok) data = await r.json(); } catch {} failures = ok ? 0 : failures + 1; yield data; await waitForVisible(pollDelay({ok, base: POLL, failures})); } })(); ``` ```js const catalog = catalogState ?? []; ``` ```js if (catalog.length === 0) { display(html`

No capabilities registered yet. Add ```capability blocks to SCOPE.md files and run make ingest-capabilities-all.

`); } else { // Group by domain const byDomain = {}; for (const c of catalog) { (byDomain[c.domain_slug] = byDomain[c.domain_slug] ?? []).push(c); } const typeColors = { infrastructure: "#e65100", api: "#1565c0", data: "#2e7d32", security: "#c62828", documentation: "#6a1b9a", other: "#888" }; display(html`
${Object.entries(byDomain).sort((a, b) => a[0].localeCompare(b[0])).map(([domain, caps]) => html`
${domain} ${caps.length}
${caps.map(c => html`
${c.capability_type}
${c.title}
${c.description ? html`
${c.description}
` : ""} ${c.keywords?.length ? html`
${c.keywords.map(k => html`${k}`)}
` : ""}
`)}
`)}
`); } ```