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

feat(KR-9): swap relationlink-create defer for kora__create_relationlink MCP call — closes D-kr3-st2#17

Merged
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR9-relationlink-create-mcp-swap
May 20, 2026
Merged

feat(KR-9): swap relationlink-create defer for kora__create_relationlink MCP call — closes D-kr3-st2#17
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR9-relationlink-create-mcp-swap

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

KR-9 swaps the deferred relationlink-write surface for a real kora__create_relationlink MCP call via the KR-7a-wired IsoKronMCPClient. Closes D-kr3-st2-no-relationlink-write-mcp-tool — the 4th and final mechanical KR-N closure swap.

K-10 + 0083 (IsoKron PM #32) resolved all three pre-KR-9 substrate-side blockers:

  • actor_kind CHECK extended to include 'kora' (0083 prod-applied)
  • public.kora_create_relationlink SECDEF wraps the write
  • kora.relationlink.created is the 300th literal in event_log_event_type_check
  • kora__create_relationlink Sea MCP tool registered

Production-test posture (same as KR-7 / KR-7b / KR-8)

K-10's handler is a notImplementedHandler stub on substrate main; substrate-team task NousResearch#395 un-stubs + bridges Layer-A wsk_* auth → Layer-B actor_kind='kora'. KR-9 code shape is sound; mock tests verify correctness; production deploys wait on dispatch tier.

What landed

File Change
plugins/memory/isokron/relationlink.py create_relationlink body swap: invokes kora__create_relationlink with {workspace_id, from/to entity_id+kind, link_type, evidence_block_ids[], (rationale_block_id?)}. New rationale_block_id + evidence_block_ids params match K-10's input schema. Legacy rationale param preserved one-release for back-compat. Defensive: None client → ValueError; bad shape → RuntimeError. RelationLinkWriteNotAvailableError tagged [kora.isokron.deprecated] for one-release runway.
plugins/memory/isokron/tools/iso_link.py _handle_iso_link_create drops deferred-envelope path. Success → {"ok": True, "link_id": <substrate-uuid>}. Substrate failure → {"ok": False, "substrate_error": True, "tool_name", "message"} — same shape as KR-8's iso_node handlers.
BUILD_DEVIATIONS.md D-kr3-st2 moved Open → Closed with Rule-5 spec-quote, blockers-resolved note, production-test posture, deprecation-runway note.
plugins/memory/isokron/README.md "Deferred-surface summary" table replaced with "All BUILD_DEVIATIONS closed code-side as of KR-9" note (parallel-merged with KR-7b + KR-8). Individual "iso_link_create writes blocked" pitfall rewritten as "RelationLink writes route via kora__create_relationlink (KR-9)".
tests/plugins/memory/test_iso_link_tools.py 7 new + 2 flipped tests (see below).

Test plan

7 new + 2 flipped tests, all passing:

create_relationlink (low-level helper):

  • Happy path: invokes kora__create_relationlink with spec-pinned arg shape; returns substrate link_id.
  • Propagates IsoKronMCPInvocationError from substrate (active-edge uniqueness violation tested).
  • Rejects None mcp_client with ValueError.
  • Rejects unexpected response shape with RuntimeError.
  • Optional rationale_block_id + evidence_block_ids pass-through correctly.
  • Deprecation runway: RelationLinkWriteNotAvailableError still importable; carries [kora.isokron.deprecated] tag.

iso_link_create handler (high-level tool):

  • Returns {"ok": True, "link_id": <uuid>} on success; MCP invoke verified.
  • Surfaces substrate error as {"ok": False, "substrate_error": True, "tool_name", "message"}.

_FakeMcpClient routes by tool_name; _FakeProviderConnection gains get_mcp_client().

Gates

  • ty check7,337 diagnostics, zero-delta vs KR-7 baseline.
  • pytest tests/plugins/memory/357/357 passing.
  • Full suite via xdist (-n auto): 24,629 passed / 181 failed / 12 errors / 129 skipped. Same tests/tools/* xdist isolation noise (kanban_tools test_complete_* errors aren't reproducible in isolation; documented across prior PRs). None touch plugins/memory/isokron/.

Parallel-mergeability

KR-7b + KR-8 + KR-9 modify disjoint files:

  • KR-7b: capability_matrix_mirror.py + provider.initialize
  • KR-8: scratchpad.py + provider sync_turn/on_memory_write/_attempt_scratchpad_write
  • KR-9: relationlink.py + tools/iso_link.py

Each PR narrows its E2E assertions to its own surface so test-fixture counts don't fight. PM handles README.md + BUILD_DEVIATIONS.md final reconciliation on merge order.

Rule-6 / BUILD_DEVIATIONS / Open asks

Closed: D-kr3-st2-no-relationlink-write-mcp-tool (KR-9). 4th of 4 substrate-MCP-tool deferrals closed.

After KR-9 + KR-7b + KR-8 merge, all 4 BUILD_DEVIATIONS are closed code-side.

Standing-by state becomes dispatch-tier-gated:

Per the K-13 heads-up: when CC#1 lands capability-matrix tightening, my capability_matrix_mirror.py fallback dict will need a 2-line update (add cap_emit_chain_event + cap_write_relationlink). Parity test catches it at CI; small follow-on PR. Production picks up the new caps automatically at next provider initialize (KR-7b's MCP fetch is authoritative).

🤖 Generated with Claude Code

…ink MCP call — closes D-kr3-st2

Fourth + final mechanical follow-on swap unlocked by K-10 + 0083
(IsoKron PM #32). Same pattern as KR-7 (chain-emit) and KR-8
(scratchpad-write): create_relationlink body replaces `raise
RelationLinkWriteNotAvailableError()` with
`await mcp_client.invoke('kora__create_relationlink', {...})`,
returning the substrate-assigned link_id. ~30 LOC across
relationlink.py + tools/iso_link.py + tests + docs.

All three KR-3 ST2 substrate blockers are now resolved substrate-side:
* actor_kind CHECK extended to include 'kora' via 0083 (prod-applied)
* public.kora_create_relationlink SECDEF function exists
* kora.relationlink.created event literal in event_log_event_type_check
  (300th literal in the set post-0083)
* kora__create_relationlink Sea MCP tool registered

Production-test posture per IsoKron PM #27:
* K-10's kora__create_relationlink handler is a notImplementedHandler
  stub on substrate main; substrate-team's dispatch tier (task NousResearch#395)
  un-stubs + bridges Layer-A wsk_* auth → Layer-B actor_kind='kora'.
* KR-9 code shape is sound; mock tests verify correctness.
* Production deploys wait on dispatch tier landing — identical
  posture to KR-7 / KR-7b / KR-8.

Verify-at-first-live-emit per spec § 3:
* event_log row with event_type = 'kora.relationlink.created'
* event_log.actor_id = 0076-seeded canonical Kora actor (NOT
  token-UUIDv5)
* relationlink row with chain_event_id matching the emitted event +
  created_by_actor_kind = 'kora'

relationlink.py:
* create_relationlink body: live call to mcp_client.invoke. K-10
  contract output: {'link_id': '<uuid>', 'chain_event_id': '<uuid>'}
  — projected to a plain str link_id return.
* mcp_client param now required (was Optional with deferred-error
  default).
* New rationale_block_id + evidence_block_ids params match K-10's
  input schema. Legacy `rationale` parameter preserved for one-
  release back-compat (silently dropped — superseded by
  rationale_block_id).
* Defensive: None mcp_client → ValueError; unexpected response shape
  → RuntimeError (mirrors KR-7/KR-8 pattern).
* RelationLinkWriteNotAvailableError class kept exported tagged
  [kora.isokron.deprecated] for one release. Original three-blocker
  message preserved inside the message body for grep stability.

tools/iso_link.py:_handle_iso_link_create:
* Dropped the deferred-envelope path. Success →
  {"ok": True, "link_id": <substrate-uuid>}. Substrate failure →
  {"ok": False, "substrate_error": True, "tool_name", "message"} —
  same structured signal shape as KR-8's iso_node_create.
* Fetches IsoKronMCPClient via get_mcp_client(); MCP-client-
  unavailable returns {"ok": False, "error": ...} envelope.
* Removed unused RelationLinkWriteNotAvailableError import.

Tests (7 new + 2 updated):
* test_iso_link_tools.py:
  - test_create_relationlink_raises_deferred_write_error →
    test_create_relationlink_invokes_kora__create_relationlink:
    happy path asserts spec-pinned arg shape (workspace_id,
    from/to entity_id + kind, link_type, evidence_block_ids=[]).
  - New test_create_relationlink_propagates_mcp_invocation_error
    (substrate active-edge uniqueness violation surfaces).
  - New test_create_relationlink_rejects_none_mcp_client.
  - New test_create_relationlink_rejects_unexpected_response_shape.
  - New test_create_relationlink_passes_rationale_block_id_when_present
    (optional args pass-through).
  - New test_relationlink_write_not_available_error_still_importable_post_kr9
    (deprecation runway).
  - test_iso_link_create_handler_returns_deferred_envelope →
    _returns_ok_envelope_with_substrate_link_id: success-envelope
    + verifies spec-pinned tool name in invoke recording.
  - New test_iso_link_create_handler_surfaces_substrate_error_envelope:
    IsoKronMCPInvocationError flips to structured envelope.
  - _FakeMcpClient routes by tool_name (returns link-N for
    kora__create_relationlink). _FakeProviderConnection gains
    get_mcp_client().

BUILD_DEVIATIONS:
* D-kr3-st2-no-relationlink-write-mcp-tool moved Open → Closed with
  Rule-5 spec-quote, call-site refactor inventory, production-test
  posture, all-three-blockers-resolved-substrate-side note,
  deprecation-runway note, verify-at-first-live-emit step.

README "Operator pitfalls":
* "Deferred-surface summary" table replaced with
  "All BUILD_DEVIATIONS closed code-side as of KR-9 (parallel-merged
  with KR-7b + KR-8)" note. All 5 deferral closures listed under
  Recently closed.
* Individual "iso_link_create writes are blocked" pitfall rewritten
  as "RelationLink writes route via kora__create_relationlink (KR-9)"
  with success/failure envelope shapes + operator grep pointer.

Parallel-mergeability note: KR-7b + KR-8 + KR-9 modify disjoint files
(KR-7b: capability_matrix_mirror.py + provider.initialize; KR-8:
scratchpad.py + provider sync_turn/on_memory_write; KR-9:
relationlink.py + tools/iso_link.py). Merge interleaves; each PR
narrows its E2E assertions to its own surface so test fixture
counts don't fight. PM handles README + BUILD_DEVIATIONS final
reconciliation on merge order.

Local gates:
* ty check — 7,337 diagnostics, zero-delta vs KR-7 baseline.
* pytest tests/plugins/memory/ — 357/357 passing.
* Full suite via xdist (-n auto): 24,629 / 181 failed / 12 errors /
  129 skipped. Same tests/tools/* xdist isolation noise as documented
  across prior PRs; none touch isokron.

After KR-9 + KR-7b + KR-8 merge, all four BUILD_DEVIATIONS are
closed code-side. Standing-by state becomes dispatch-tier-gated
(waiting on substrate-team task NousResearch#395 + service-token mint for
production deploys).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rafe-walker rafe-walker force-pushed the feat/kora-KR9-relationlink-create-mcp-swap branch from dddab4b to 5a6fe93 Compare May 20, 2026 22:17
@rafe-walker rafe-walker reopened this May 20, 2026
@rafe-walker rafe-walker merged commit 15f47a2 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