Skip to content
This repository was archived by the owner on May 26, 2026. It is now read-only.

feat(KR-P2-CAP-PANEL): capabilities inspector — live read from tool_capability_map + actor_has_capability#52

Merged
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR-P2-CAP-PANEL
May 21, 2026
Merged

feat(KR-P2-CAP-PANEL): capabilities inspector — live read from tool_capability_map + actor_has_capability#52
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR-P2-CAP-PANEL

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

Operator-side view of "what Kora is permitted to invoke right now". First real-data panel in the CC#2 admin series — no `stub` flag because both dependencies (KR-P2-A's `TOOL_CAPABILITY_MAP` and the `actor_has_capability` helper) are already on main.

This is the operator-side view of the D-krp2a-st1-infra-tier-caps-missing-from-c2-mirror deviation: infra-tier cap_* names are not yet in the C2 mirror, so `actor_has_capability` raises `KeyError` on them — the endpoint catches that and surfaces an `unmapped_in_c2_mirror` verdict so the operator sees the documented fail-CLOSED state instead of a swallowed error.

Endpoint (kora_cli/web_server.py)

`GET /api/capabilities` — read-only. Returns:

field semantics
`groups[]` one entry per unique cap_* (17 today), each `{cap_name, verdict, tools[]}`; sorted alphabetical by cap_name; tools[] sorted within
`substrate_tier[]` the 4 `kora__*` tools the pre-screen short-circuits (PASS); the substrate dispatch is the authoritative gate
`total_tools` `len(TOOL_CAPABILITY_MAP) + 4` (64 + 4 = 68 today)
`total_caps` unique cap_* count (17 today)
`unmapped_count` groups currently INCONCLUSIVE (17 today, will drop as KR-P2-N extends the mirror)

Verdict resolution: `actor_has_capability(cap)` → `granted`/`denied`; `KeyError` → `unmapped_in_c2_mirror`; unexpected exception → `error` (with server-log).

Frontend (web/)

  • `pages/CapabilitiesPage.tsx`
    • Summary banner — `{total_tools} tools across {total_caps} cap_* groups` + per-verdict counts + "D-krp2a-st1" attribution when `unmapped_count > 0`
    • Substrate-enforced card — 4 `kora__*` tools with green "always PASS" badge + the substrate-side-is-authoritative explainer
    • Capability groups — one card per cap_* (sorted alphabetical), verdict pill with tone, per-verdict border colour, tool chips. Unmapped groups get an inline explainer: "Closes when substrate-team KR-P2-N ships."
  • `lib/api.ts` — `CapVerdict` type alias + `CapabilityGroup` / `CapabilitiesResponse` interfaces + `getCapabilities` client
  • `App.tsx` — `/capabilities` route + nav entry (ShieldCheck icon) between `/cost-state` and `/kora-control`

Current main state at landing

Live call against `origin/main` HEAD `036fc7b` returns:

```
total_tools: 68
total_caps: 17
unmapped_count: 17
groups by verdict: { unmapped_in_c2_mirror: 17 }
```

Every cap_* group is currently unmapped — meaning every non-substrate tool path is fail-CLOSED until KR-P2-N closes the mirror gap. The panel makes that visible at a glance rather than letting it hide as silent denial.

Test plan

  • `tests/kora_cli/test_web_server_capabilities.py` — 12/12 green, covers all 10 §5 scenarios + 2 extra guards (tools sorted within each group; `substrate_tier` disjoint from `TOOL_CAPABILITY_MAP`)
  • `test_web_server_{cost_state,boot_status,kora_control,sea_tickets,cron_profiles,host_header,mcp,gateway_identity}.py` — 78/78 still green (90 total)
  • `npx tsc -b` on `web/` — clean
  • `npx vite build` on `web/` — clean
  • Manual smoke: navigate to `/capabilities`, verify summary banner shows the 17/17 unmapped count + D-krp2a-st1 attribution, verify substrate-tier card shows the 4 `kora__*` tools in green, verify all 17 group cards render amber with the "Closes when KR-P2-N ships" inline explainer

Dependency notes

  • KR-P2-A (already on main) shipped `TOOL_CAPABILITY_MAP` + `actor_has_capability` — this PR reads both directly, no shim.
  • D-krp2a-st1-infra-tier-caps-missing-from-c2-mirror — documented deviation; this panel is the operator-facing surface for it.
  • KR-P2-N (substrate-team's lane, future) extends the C2 mirror to cover infra-tier caps; when it ships the `unmapped_count` drops and the test (`assert >= 0`, not exact) keeps passing without change.

🤖 Generated with Claude Code

…apability_map + actor_has_capability

Operator-side view of "what Kora is permitted to invoke right now". First
real-data panel in the CC#2 admin series (predecessors #26 OPS, #31 SEA,
#37 CONTROL, #45 BOOT, #49 COST were all stub-then-real). No stub flag —
the dependencies (KR-P2-A's TOOL_CAPABILITY_MAP + actor_has_capability)
are already on main.

Backend (kora_cli/web_server.py):
  GET /api/capabilities — reads the 64-entry TOOL_CAPABILITY_MAP and
  resolves each unique cap_* (17 of them) via actor_has_capability,
  catching KeyError → "unmapped_in_c2_mirror" verdict (the documented
  fail-CLOSED state per D-krp2a-st1-infra-tier-caps-missing-from-c2-mirror).
  Returns: groups[] sorted alphabetical by cap_name with tools[] sorted
  within, substrate_tier[] (the 4 kora__* tools the pre-screen
  short-circuits with PASS), and 3 summary counts. Read-only by design;
  cap policy changes are substrate-team's lane.

Frontend:
  - CapabilitiesPage.tsx —
    * Summary banner: "{total_tools} tools across {total_caps} cap_*
      groups" + per-verdict counts + "D-krp2a-st1" attribution when
      anything is unmapped.
    * Substrate-enforced card: 4 kora__* tools with green "always PASS"
      badge and the substrate-side-is-authoritative explainer.
    * One card per cap_* group with verdict pill, per-verdict-tone
      border, tool chips, and an inline explainer for unmapped groups
      ("Closes when substrate-team KR-P2-N ships").
  - api.ts — CapVerdict type alias + 2 interfaces (CapabilityGroup,
    CapabilitiesResponse) + getCapabilities client.
  - App.tsx — /capabilities route + nav entry (ShieldCheck icon)
    between /cost-state and /kora-control per spec §3.

Tests: tests/kora_cli/test_web_server_capabilities.py — 12 tests
covering all 10 §5 scenarios + 2 extra guards (tools sorted within
each group, substrate_tier disjoint from TOOL_CAPABILITY_MAP).
90/90 across the full web_server admin-panel suite pass. tsc -b +
vite build clean.

Current main state at landing: all 17 cap_* groups surface as
unmapped_in_c2_mirror (D-krp2a-st1 default). Panel renders 17 amber
group cards + 4 always-PASS substrate-tier tools — operationally
this gives Joshua immediate visibility into "everything except the
4 kora__* tools is fail-CLOSED until KR-P2-N closes the mirror gap."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant