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

feat(KR-2 ST2): IsoKron read paths — Role Charter + capability matrix + policy registry#6

Merged
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR2-reads
May 20, 2026
Merged

feat(KR-2 ST2): IsoKron read paths — Role Charter + capability matrix + policy registry#6
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR2-reads

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

Wires the three IsoKron read paths into IsoKronMemoryProvider:

  • read_active_role_charter — asyncpg SELECT against public.kora_role_charter with SHA-256 integrity verification. Mirrors readActiveKoraRoleCharter (TS K-1 ST4). Raises NoActiveRoleCharterError on 0 rows; RoleCharterIntegrityError on hash mismatch or NULL content_md — both fail-closed per spec.
  • read_kora_policy_registry — asyncpg SELECT against kora_policy_registry. RLS-aware: opens a transaction, sets app.current_workspace_id GUC via set_config(...,true), then SELECTs. 31-row sanity is warned-on-drift, not failed (operators may intentionally prune).
  • read_kora_capability_rowC2 Python mirror of ACTOR_CAPABILITY_MATRIX Kora column. Per PM STOP-gate resolution 2026-05-20: ship C2 now (60 LOC mirror + parity guard), swap to a kora__read_kora_capability_row MCP tool when K-7 lands. Parity test reads packages/sea-mcp-server/src/capability-matrix.ts and asserts every cap_name → kora_value matches in both directions.

on_turn_start(turn, message, **kwargs) pre-fetches all three reads in parallel via asyncio.gather (per spec acceptance). system_prompt_block() reads from the per-workspace 60s TTL cache (cold-cache triggers sync fetch on the dedicated IO loop). It assembles:

§1 Identity (Kora Role Charter v<version>)
<sections.identity>

§2 You CAN:
  - <authority_can_do bullets>

§3 You CANNOT:
  - <authority_cannot_do bullets>

§4 Active policy values
  - policy.kora_disabled = false
  - policy.kora_max_nonsecurity_overrides_per_24h = 5
  - policy.kora_output_size_cap_pull = 500
  - policy.kora_rate_limit_per_minute = 60
  - policy.kora_context_assembler_token_ceiling.opus = 180000

§5 Granted capabilities (22 of 48):
  - <granted cap names, sorted>

This identity block was assembled by IsoKronMemoryProvider on session start.
The substrate is the source of truth; if anything below conflicts with a
fresh substrate query, the substrate query wins.

IsoKronConnection now lazy-opens the asyncpg pool on first read with the JSONB codec registered (dict / list / scalar arrive as Python types — policy_value "elevenlabs" is a decoded scalar, not a JSON literal to re-decode). Pool open is deferred so existing ST1 lifecycle tests still run without a live Postgres.

What landed

File Change
plugins/memory/isokron/models.py newRoleCharter, RoleCharterSections, PolicyRegistryEntry, KoraCapabilityRow, NoActiveRoleCharterError, RoleCharterIntegrityError
plugins/memory/isokron/cache.py new — generic TTL cache (TTLCache[T]), injectable clock for tests
plugins/memory/isokron/reads.py new — three async read functions + canonical SQL + SHA-256 helper
plugins/memory/isokron/capability_matrix_mirror.py new — C2 mirror with [kora.isokron.todo] top-of-file tag
plugins/memory/isokron/connection.py lazy asyncpg pool with JSONB codec registered on init; get_pg_pool() + submit_and_wait()
plugins/memory/isokron/provider.py initialize stays minimal; on_turn_start does asyncio.gather; system_prompt_block assembles from cache; pure-function _assemble_system_prompt_block for unit testing
plugins/memory/isokron/README.md "Operator pitfalls" rewritten — capability-mirror drift, RLS GUC requirement, fail-closed integrity, workspace_id resolution, lazy pool open
BUILD_DEVIATIONS.md newD-kr2-st2-capability-matrix-mirror Open entry, closes when K-7 ships
tests/plugins/memory/test_reads.py new — 16 tests (see below)
tests/plugins/memory/test_capability_matrix_parity.py new — 2 tests (skip-aware on missing substrate repo)
tests/plugins/memory/test_isokron_provider_skeleton.py parametrize trimmed (system_prompt_block + on_turn_start now implemented; prefetch/queue_prefetch are no-op); removed test_pg_pool_accessor_raises_in_st1 (pool lazy-opens now)

Test plan

New (18 tests, all passing):

  • test_read_active_role_charter_returns_typed_shape — happy path, SQL bound with workspace_id
  • test_read_active_role_charter_integrity_error_on_hash_mismatch — SHA-256 mismatch → RoleCharterIntegrityError
  • test_read_active_role_charter_raises_when_zero_rows — 0 rows → NoActiveRoleCharterError
  • test_read_active_role_charter_null_content_treated_as_integrity_error — NULL content_md → RoleCharterIntegrityError
  • test_read_active_role_charter_handles_jsonb_as_string — defensive str-decode for content_jsonb (object-only field)
  • test_read_kora_policy_registry_31_rows_healthy_no_warning — 31 rows + no warning
  • test_read_kora_policy_registry_drift_warns_does_not_fail — 30 rows logs warning, returns the 30
  • test_read_kora_policy_registry_sets_rls_guc_before_select — asserts exact call ordering: txn.enter → set_config → SELECT → txn.exit
  • test_read_kora_policy_registry_passes_codec_decoded_values_through — Python str/bool/int/dict pass through (do NOT re-json.loads)
  • test_capability_mirror_loads_with_expected_shape — 48 entries, all bool values
  • test_read_kora_capability_row_returns_typed_kora_row — async wrapper returns KoraCapabilityRow (22 granted / 26 denied of 48)
  • test_kora_capability_row_has_lookup_is_fail_closed — known-granted, known-denied, unknown all behave correctly
  • test_ttl_cache_hits_within_ttl_and_expires_after — injected clock; t=0 hit, t=59 hit, t=60 miss + eviction
  • test_ttl_cache_invalidate_drops_entry
  • test_system_prompt_block_assembles_all_required_sections — §1/§2/§3/§4/§5 all present + non-empty
  • test_system_prompt_block_contains_rule_6_label_verbatim — exact-string check + at-the-bottom
  • test_system_prompt_block_marks_missing_policy_entries<not seeded> rendered explicitly
  • test_compute_role_charter_content_hash_matches_postgres_encoding — SHA-256 hex byte-matches encode(digest(content_md,'sha256'),'hex')
  • test_python_mirror_matches_ts_source_for_every_kora_column_value — parity test (skip-aware; CI must set KORA_ISOKRON_REPO)
  • test_python_mirror_has_expected_subset_counts — 24 SEA + 24 KORA_BROADER = 48, no overlap

ST1 regression check: 28 ST1 tests pass post-changes (one removed: test_pg_pool_accessor_raises_in_st1 — pool now lazy-opens; renamed test_mcp_client_accessor_raises_in_st1..._until_st3 since ST2 leaves MCP writes for ST3).

Gates

  • ty check7,337 diagnostics vs KR-2 ST1 baseline 7,341 (Δ −4). Zero new diagnostics introduced.
  • pytest tests/plugins/memory/44/44 passing (16 new ST2 read tests + 2 parity tests + 26 ST1 skeleton tests).
  • Full suite via xdist (-n auto): 24,443 passed / 227 failed / 129 skipped (Δ vs main same parallelism: 24,439 passed / 218 failed / 4 errors / 129 skipped → +4 passed; +9 failures).
    • All +9 deltas are in tests/tools/* (test_tts_, test_vercel_sandbox_, test_video_generation_, test_web_providers_, test_website_policy*, test_yolo_mode*) and tests/tui_gateway/*none touch plugins/memory/isokron/.
    • Re-running the same subset with -n 4 reproduces only 1 of those failures on both main and this branch — classic xdist isolation noise. Documenting per ST1 convention; not a regression.

Rule-6 / BUILD_DEVIATIONS / Open asks

  • D-kr2-st2-capability-matrix-mirror opened in BUILD_DEVIATIONS.md. Closes when K-7 (Sea MCP kora__read_kora_capability_row tool) ships. Parity test + [kora.isokron.todo] tag + README operator-pitfall guard against drift in the interim.
  • prefetch / queue_prefetch are now no-op (ABC defaults made explicit); the remaining stubs (sync_turn, handle_tool_call, on_session_end, on_session_switch, on_pre_compress, on_delegation, on_memory_write, save_config) still raise NotImplementedError with [kora.isokron.todo] markers, retargeted to ST3 / ST4.
  • Role Charter content_jsonb field structure matches the TS reader (sections.authority_can_do / sections.authority_cannot_do — the "or equivalent" the spec mentioned), confirmed via packages/sb1-substrate-shapes/src/kora-role-charter.ts:225. No STOP-gate needed.

Ready to merge. Standing by for K-7 bucket dispatch to swap the C2 mirror.

🤖 Generated with Claude Code

… + policy registry

Three async reads wired into the IsoKronMemoryProvider with a per-workspace
60s TTL cache; on_turn_start pre-fetches all three in parallel via
asyncio.gather; system_prompt_block assembles the identity block.

* read_active_role_charter — asyncpg SELECT against public.kora_role_charter
  with SHA-256 integrity check; mirrors readActiveKoraRoleCharter (K-1 ST4).
  Raises NoActiveRoleCharterError on 0 rows; RoleCharterIntegrityError on
  hash mismatch or NULL content_md (fail-closed per spec).

* read_kora_policy_registry — asyncpg SELECT against kora_policy_registry.
  RLS-aware: opens a transaction, sets app.current_workspace_id GUC via
  set_config(...,true), then SELECTs. 31-row sanity warned-on-drift, not
  failed (operators may intentionally prune).

* read_kora_capability_row — C2 Python mirror of ACTOR_CAPABILITY_MATRIX
  Kora column (PM-decided STOP-gate resolution: ship C2 now, swap to a
  kora__read_kora_capability_row MCP tool when K-7 lands). Parity test
  reads the TS source at packages/sea-mcp-server/src/capability-matrix.ts
  and asserts every cap_name → kora_value matches in both directions.
  BUILD_DEVIATIONS entry D-kr2-st2-capability-matrix-mirror tracks closure.

Connection wrapper now lazy-opens the asyncpg pool with the JSONB codec
registered on init (dict/list/scalar arrive as Python types). Pool open
is deferred to first read so existing ST1 lifecycle tests still pass
without a live Postgres.

Tests (≥10 per spec, 18 new):
* tests/plugins/memory/test_reads.py — 16 tests covering each read's
  shape, integrity errors, RLS GUC ordering, drift warnings, cache TTL,
  and the system_prompt_block assembler (all sections + Rule-6 verbatim).
* tests/plugins/memory/test_capability_matrix_parity.py — 2 tests
  (skip-aware on missing substrate repo; CI must set KORA_ISOKRON_REPO).

Local gates:
* ty check — 7,337 diagnostics vs KR-2 ST1 baseline 7,341 (delta −4).
* pytest tests/plugins/memory/ — 44/44 passing (16 new + 28 from ST1).
* Full suite via xdist (-n auto): 24,443 passed / 227 failed / 129
  skipped. Main same parallelism: 24,439 passed / 218 failed / 4 errors.
  Net delta: +4 passed; the +9 failures are all in tests/tools/* +
  tests/tui_gateway/* (none touch isokron). Re-running the same subset
  with -n 4 shows only 1 of those tests failing on either branch —
  classic xdist isolation noise that pre-existed.

Rule-6 honesty:
* [kora.isokron.todo] tag on capability_matrix_mirror.py top-of-file +
  README "Operator pitfalls" + BUILD_DEVIATIONS D-kr2-st2-capability-
  matrix-mirror entry under Open.
* README also flags: RLS GUC requirement for policy registry, fail-closed
  integrity semantics, workspace_id resolution precedence, lazy pool open
  (no fast-fail at initialize()), and MCP transport choice still deferred
  to ST3.

prefetch / queue_prefetch are now no-op (ABC defaults made explicit);
sync_turn / handle_tool_call / on_session_end / on_session_switch /
on_pre_compress / on_delegation / on_memory_write / save_config still
raise NotImplementedError with [kora.isokron.todo] markers (ST3/ST4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rafe-walker rafe-walker merged commit a3e77f6 into main May 20, 2026
rafe-walker added a commit that referenced this pull request May 22, 2026
GET /api/diag-bundle StreamingResponse zip with Content-Disposition attachment. Per-endpoint try/except — bundle never fails entirely (verified by all-endpoints-failing test). _panel_sources() explicit allowlist of 11 sources (10 panels + runbooks manifest); NOT auto-discovered. Dashboard button top-right next to Reload (Archive icon); standard <a href download> pattern + diagBundleHref() that applies HERMES_BASE_PATH for URL-prefix reverse-proxy setup.

Design decision (PM-approved): bucket §5 #6 credential-safety guard tightened from bare-substring matches (wsk_ / xoxb-) to token-shaped regex patterns (wsk_ + ≥16 alphanumeric, real Slack shapes, sk- + ≥20 chars, JSON password-field-with-value patterns). Bare substrings false-positive-flagged operator-facing copy (boot gate title 'wsk_* token valid' + runbook title 'Token rotation — wsk_*'). Spirit preserved: catch real on-the-wire credentials.

11 tests + 151/151 admin-panel suite. tsc + vite clean.
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