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

feat(KR-7b): swap C2 capability mirror for kora__read_kora_capability_row MCP fetch — closes D-kr2-st2 - #15

Merged
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR7b-capability-row-mcp-swap
May 20, 2026
Merged

feat(KR-7b): swap C2 capability mirror for kora__read_kora_capability_row MCP fetch — closes D-kr2-st2#15
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR7b-capability-row-mcp-swap

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

KR-7b swaps the hand-mirrored C2 capability dict for an authoritative MCP fetch via kora__read_kora_capability_row at provider initialize. Closes D-kr2-st2-capability-matrix-mirror.

CC#3 elected Option A (use the KR-7a-wired IsoKronMCPClient) over Option B (parallel httpx fetch path) since KR-7a is shipped — one canonical MCP-call pattern across all closure swaps. The hand-mirrored 49-entry dict stays as a dev/test fallback (parity test still guards drift); production fetches authoritatively at start.

Production-test posture (same as KR-7)

K-7's kora__read_kora_capability_row handler is a notImplementedHandler stub on substrate main; substrate-team's dispatch tier (queued, task NousResearch#395) un-stubs the handler. KR-7b's code shape is sound; mock tests verify the populate machinery; production deploys wait on the dispatch tier landing. On fetch failure the hand-mirrored fallback stays in place + a [kora.capability_matrix.fallback] WARNING is logged — dev/test ergonomics survive substrate downtime; sessions still run. Operators grep [kora.capability_matrix.fallback] in production logs to confirm fetch health.

What landed

File Change
plugins/memory/isokron/capability_matrix_mirror.py New populate_capability_matrix_from_mcp(mcp_client) coroutine — invokes kora__read_kora_capability_row (no args), validates {capability_matrix: dict[str, bool]} shape (defensive checks on both keys and values), mutates ACTOR_CAPABILITY_MATRIX_KORA_COLUMN in-place via clear() + update(). Returns the entry count. New CAPABILITY_MATRIX_MCP_TOOL constant. Module docstring rewritten: hand-mirrored data is now the dev/test fallback (no longer "C2 interim").
plugins/memory/isokron/provider.py initialize() now calls new _refresh_capability_matrix_from_mcp() after starting the connection. Two log paths: INFO [kora.capability_matrix] on success; WARNING [kora.capability_matrix.fallback] on MCP-fetch or transport failure (fallback intact).
tests/plugins/memory/test_capability_matrix_mcp_fetch.py new — 11 tests covering populate (happy + 6 defensive error paths) + provider.initialize (INFO success, two WARNING fallback variants). Autouse fixture snapshots + restores the module-level dict for xdist isolation.
tests/plugins/memory/test_provider_end_to_end.py _FakeMcpClient.invoke routes by tool name — returns a canonical 3-entry capability_matrix for kora__read_kora_capability_row; mock event_id for kora__append_event. E2E asserts the initialize-time fetch fired and replaced the dict. New restore_capability_matrix fixture.
BUILD_DEVIATIONS.md D-kr2-st2 moved Open → Closed with KR-7b's Option-A rationale, production-test posture, hand-mirrored fallback retention note.
plugins/memory/isokron/README.md Deferred-surface table trimmed 3 → 2 rows. D-kr2-st2 moves to Recently-closed. Individual pitfall rewritten as "MCP-fetched at provider initialize" with fallback semantics.

Why hand-mirrored fallback stays

The 49-entry C2 dict at module import is now framed as the dev/test fallback rather than "C2 interim":

  • Production: MCP fetch succeeds at initialize() → dict replaced with authoritative substrate data. K-13's upcoming additions (cap_emit_chain_event, cap_write_relationlink) flow through automatically at next provider start — no Python-side code change.
  • Dev/test: tests run without a live substrate. Fallback provides 49-entry coverage so actor_has_capability lookups still resolve. K-13 will still require a 2-line bump to the fallback for dev parity, but production picks it up automatically (the parity test against TS source catches the bump-needed signal at CI).
  • Production with substrate downtime: fallback stays + [kora.capability_matrix.fallback] WARNING fires. Sessions keep running on (potentially stale) dev data rather than failing closed. Operators grep the tag to confirm fetch health.

Test plan

11 new tests in test_capability_matrix_mcp_fetch.py, all passing:

populate_capability_matrix_from_mcp (7):

  • Invokes kora__read_kora_capability_row with empty args
  • Replaces the module dict in-place; identity preserved (forward-stability for capability_check consumers)
  • Raises ValueError on None mcp_client
  • Raises RuntimeError on missing capability_matrix key
  • Raises RuntimeError on non-dict response
  • Raises RuntimeError on non-bool capability value (defensive vs substrate regression)
  • Raises RuntimeError on non-str capability key
  • Propagates underlying MCP-side exceptions unchanged

provider.initialize (3):

  • Success: INFO [kora.capability_matrix] populated from kora__read_kora_capability_row — N entries + dict replaced
  • Substrate-down: WARNING [kora.capability_matrix.fallback] MCP fetch ... failed (...); using hand-mirrored fallback + fallback intact
  • Transport-unavailable: WARNING [kora.capability_matrix.fallback] could not reach MCP client (...)

E2E updated (test_provider_end_to_end.py): _FakeMcpClient.invoke routes by tool name. Asserts the initialize-time fetch fired with the spec-pinned tool name + empty args, dict was replaced with the canonical test matrix, and the 2 append_event emits still fired separately.

Gates

  • ty check7,337 diagnostics, zero-delta vs KR-7 baseline. All targeted-file diagnostics resolved.
  • pytest tests/plugins/memory/362/362 passing (11 new KR-7b + 351 pre-KR-7b).
  • Full suite via xdist (-n auto): 24,652 passed / 175 failed / 129 skipped. Δ vs KR-7 (24,561 / 203 / 52err / 129): +91 passed, −28 failed, −52 errors. Same tests/tools/* + tests/tui_gateway/* xdist isolation noise; none touch plugins/memory/isokron/.

Rule-6 / BUILD_DEVIATIONS / Open asks

Closed: D-kr2-st2-capability-matrix-mirror (KR-7b).

2 deferrals remain open — both unblocked at substrate; PM has dispatched the matching closure swaps:

Deviation Closes when
D-kr2-st3-no-scratchpad-write-mcp-tool KR-8 (K-8 merged bd165eb2; PM dispatched)
D-kr3-st2-no-relationlink-write-mcp-tool KR-9 (K-10 + 0083 in prod; PM dispatched)

Both swaps follow the KR-7 template — same mechanical pattern, same production-test posture. Shipping KR-8 next per PM-suggested order, then KR-9. After all 4 closures merge, the standing-by state becomes dispatch-tier-gated (substrate-team task NousResearch#395 + service-token mint for production).

🤖 Generated with Claude Code

…_row MCP fetch — closes D-kr2-st2

Mechanical follow-on swap unlocked by K-7 (substrate `ee730853`) and
KR-7a's MCP client transport. CC#3 elected Option A (use the unified
IsoKronMCPClient) over Option B (parallel httpx fetch) since KR-7a is
shipped — one canonical MCP-call pattern across all closure swaps.

Pattern: provider.initialize() now refreshes the capability matrix
from the substrate before returning. On fetch failure (substrate
unreachable / transport down / bad response), the hand-mirrored
49-entry fallback stays in place + a WARNING is logged so dev/test
ergonomics survive substrate downtime. Operators grep
[kora.capability_matrix.fallback] in production logs to confirm the
fetch is succeeding.

capability_matrix_mirror.py:
* New populate_capability_matrix_from_mcp(mcp_client) coroutine:
  - Invokes kora__read_kora_capability_row (no args; K-7 contract:
    static-config tool, no actor identity needed).
  - Validates the response shape: {capability_matrix: dict[str, bool]}
    with defensive checks on both key and value types (Zod-strict on
    the TS side, but a regression would silently break
    actor_has_capability lookups — fail loudly here).
  - Mutates ACTOR_CAPABILITY_MATRIX_KORA_COLUMN in place via
    clear() + update(). Identity preserved so capability_check.py's
    by-reference import sees fresh data without re-importing.
  - Returns the count of entries written (for logging visibility).
  - Raises on None mcp_client (defensive) or bad response shape;
    caller decides fail-closed vs fallback.
* New CAPABILITY_MATRIX_MCP_TOOL = "kora__read_kora_capability_row"
  constant — referenced by the populate function + tests.
* Module docstring rewritten: hand-mirrored data is now framed as
  dev/test fallback (not "C2 interim"). Forward stability noted
  for K-13's upcoming additions (substrate ships → fetch picks up;
  fallback dict gets the 2-line update at next parity-test failure).

provider.initialize():
* New _refresh_capability_matrix_from_mcp() method called after the
  connection starts. Two log paths:
  - Happy: [kora.capability_matrix] populated from kora__read_kora_
    capability_row — N entries (INFO from mirror module).
  - Substrate fetch failed: [kora.capability_matrix.fallback] MCP
    fetch ... failed (...); using hand-mirrored fallback (WARNING).
  - MCP client unavailable (transport not started): [kora.capability_
    matrix.fallback] could not reach MCP client ... (WARNING).
* Same production-test posture as KR-7's chain-emit closure: code
  shape ships green; substrate-team dispatch tier un-stubs the K-7
  handler; until then production falls back to hand-mirrored data
  + WARNINGs are operator-visible.

Tests:
* test_capability_matrix_mcp_fetch.py — 11 new tests:
  - populate invokes the canonical tool with empty args
  - populate replaces the dict in-place (identity preserved across
    re-imports — forward-stability check for capability_check.py
    consumers)
  - Defensive errors: None mcp_client / missing capability_matrix
    key / non-dict response / non-bool value / non-str key / under-
    lying invocation error propagation
  - provider.initialize success-path logs [kora.capability_matrix]
    INFO + dict replaced
  - provider.initialize substrate-down logs [kora.capability_matrix.
    fallback] WARNING + fallback intact
  - provider.initialize transport-unavailable logs the distinct
    "could not reach MCP" fallback variant
  - autouse fixture snapshots + restores the module-level dict so
    parallel xdist workers and serial tests stay clean

* test_provider_end_to_end.py updated:
  - _FakeMcpClient.invoke now routes by tool_name (returns a
    canonical 3-entry capability_matrix for kora__read_kora_capability
    _row; mock event_ids for kora__append_event).
  - Test asserts the initialize-time fetch fired + replaced the dict
    with the test matrix; separately asserts the 2 append_event
    emits via the new append_event_calls attribute on the fake.
  - New restore_capability_matrix fixture snapshots + restores the
    module-level dict.

BUILD_DEVIATIONS:
* D-kr2-st2-capability-matrix-mirror moved Open → Closed with Rule-5
  spec-quote, KR-7b's Option-A rationale, production-test posture,
  hand-mirrored fallback retention note.
* 2 deferrals remain open (D-kr2-st3 / D-kr3-st2).

README "Operator pitfalls":
* Deferred-surface table trimmed 3 → 2 rows; D-kr2-st2 moves to
  Recently-closed.
* Individual "Capability matrix is currently a Python mirror" pitfall
  rewritten as "Capability matrix is now MCP-fetched at provider
  initialize (KR-7b)" with the fallback semantics + operator grep
  pointer.

Local gates:
* ty check — 7,337 diagnostics, zero-delta vs KR-7 baseline.
* pytest tests/plugins/memory/ — 362/362 passing (11 new KR-7b +
  351 pre-KR-7b).
* Full suite via xdist (-n auto): 24,652 / 175 failed / 129 skipped.
  Δ vs KR-7 (24,561/203/52err/129): +91 passed, -28 failed, -52
  errors. Same tests/tools/* + tests/tui_gateway/* xdist isolation
  noise as documented across prior PRs; none touch isokron.

2 deferrals still open pending CC#1 substrate buckets:
* D-kr2-st3-no-scratchpad-write-mcp-tool ← KR-8 (K-8 merged; PM dispatched)
* D-kr3-st2-no-relationlink-write-mcp-tool ← KR-9 (K-10 merged; PM dispatched)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rafe-walker
rafe-walker merged commit 0c57dbf into main May 20, 2026
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