From 5345f2a8343bedb447a3888223365363a7d5b52e Mon Sep 17 00:00:00 2001
From: Steven Enamakel <31011319+senamakel@users.noreply.github.com>
Date: Sat, 30 May 2026 14:38:50 -0700
Subject: [PATCH] test: expand e2e raw coverage across agent, channels,
inference, memory, tools (#3023)
---
docs/TEST-COVERAGE-MATRIX.md | 8 +-
package.json | 1 +
scripts/check-domain-e2e-coverage.mjs | 130 +
scripts/test-rust-e2e.sh | 16 +
src/openhuman/agent/harness/mod.rs | 2 +-
.../harness/subagent_runner/extract_tool.rs | 40 +-
.../agent/harness/subagent_runner/ops.rs | 12 +-
src/openhuman/app_state/schemas.rs | 31 +-
src/openhuman/approval/types.rs | 21 +
src/openhuman/channels/bus.rs | 36 +
src/openhuman/channels/controllers/ops.rs | 30 +-
.../channels/controllers/ops_tests.rs | 155 +
src/openhuman/channels/mod.rs | 3 +
.../channels/providers/discord/api.rs | 40 +
.../channels/providers/email_channel.rs | 24 +
src/openhuman/channels/providers/irc.rs | 41 +
src/openhuman/channels/providers/lark.rs | 98 +-
.../channels/providers/mattermost.rs | 37 +
src/openhuman/channels/providers/mod.rs | 3 +
.../channels/providers/presentation.rs | 36 +
.../channels/providers/telegram/mod.rs | 11 +
src/openhuman/channels/providers/web.rs | 61 +-
.../channels/providers/yuanbao/connection.rs | 121 +
src/openhuman/channels/runtime/dispatch.rs | 15 +
src/openhuman/channels/runtime/mod.rs | 3 +
src/openhuman/channels/runtime/startup.rs | 12 +
.../channels/runtime/test_support.rs | 476 ++
src/openhuman/composio/client.rs | 24 +
.../composio/connected_integrations.rs | 13 +
src/openhuman/composio/ops_tests.rs | 87 +-
src/openhuman/composio/tools/direct.rs | 102 +-
src/openhuman/composio/tools/direct_tests.rs | 20 +
src/openhuman/composio/tools_tests.rs | 56 +-
src/openhuman/connectivity/mod.rs | 1 +
src/openhuman/connectivity/ops.rs | 8 +-
src/openhuman/cost/rpc.rs | 15 +
src/openhuman/cwd_jail/macos.rs | 24 +-
src/openhuman/embeddings/cohere.rs | 17 +-
src/openhuman/embeddings/mod.rs | 3 +-
src/openhuman/embeddings/voyage.rs | 17 +
.../inference/local/install_piper.rs | 22 +-
.../inference/local/install_whisper.rs | 7 +
src/openhuman/inference/model_context.rs | 14 +-
.../inference/provider/compatible.rs | 158 +
src/openhuman/memory/query/query_global.rs | 2 +
.../composio/providers/slack/provider.rs | 25 +-
.../memory_sync/composio/providers/types.rs | 103 +-
src/openhuman/tokenjuice/tool_integration.rs | 18 +-
...rchivist_debug_round21_raw_coverage_e2e.rs | 450 ++
...gent_harness_leftovers_raw_coverage_e2e.rs | 672 ++
tests/agent_harness_raw_coverage_e2e.rs | 411 ++
tests/agent_large_round25_raw_coverage_e2e.rs | 433 ++
...agent_prompts_subagent_raw_coverage_e2e.rs | 592 ++
tests/agent_round26_raw_coverage_e2e.rs | 506 ++
.../agent_session_round24_raw_coverage_e2e.rs | 665 ++
tests/agent_session_turn_raw_coverage_e2e.rs | 1014 +++
tests/agent_tool_loop_raw_coverage_e2e.rs | 634 ++
...riage_dispatch_round23_raw_coverage_e2e.rs | 210 +
...turn_builder_leftovers_raw_coverage_e2e.rs | 611 ++
..._turn_toolloop_round22_raw_coverage_e2e.rs | 361 +
...threads_memory_sources_raw_coverage_e2e.rs | 778 +++
...ntials_threads_round24_raw_coverage_e2e.rs | 381 ++
...hreads_sources_round26_raw_coverage_e2e.rs | 310 +
.../app_state_credentials_raw_coverage_e2e.rs | 533 ++
...nnels_bus_presentation_raw_coverage_e2e.rs | 171 +
...channels_large_round25_raw_coverage_e2e.rs | 369 ++
...email_dispatch_round21_raw_coverage_e2e.rs | 273 +
...channels_provider_deep_raw_coverage_e2e.rs | 490 ++
...els_provider_leftovers_raw_coverage_e2e.rs | 561 ++
tests/channels_round24_raw_coverage_e2e.rs | 151 +
tests/channels_round26_raw_coverage_e2e.rs | 484 ++
tests/channels_runtime_raw_coverage_e2e.rs | 436 ++
.../channels_web_startup_raw_coverage_e2e.rs | 256 +
.../channels_web_telegram_raw_coverage_e2e.rs | 630 ++
...ls_web_yuanbao_round22_raw_coverage_e2e.rs | 399 ++
...osio_credentials_state_raw_coverage_e2e.rs | 884 +++
...s_credentials_appstate_raw_coverage_e2e.rs | 718 ++
tests/composio_ops_raw_coverage_e2e.rs | 741 +++
tests/composio_raw_coverage_e2e.rs | 2252 +++++++
.../composio_tools_direct_raw_coverage_e2e.rs | 437 ++
...mposio_tools_ops_state_raw_coverage_e2e.rs | 564 ++
.../config_auth_app_state_connectivity_e2e.rs | 5897 +++++++++++++++++
tests/config_credentials_raw_coverage_e2e.rs | 484 ++
tests/connectivity_raw_coverage_e2e.rs | 588 ++
...ntials_threads_round22_raw_coverage_e2e.rs | 326 +
tests/domain_modules_e2e.rs | 720 ++
tests/embeddings_ollama_raw_coverage_e2e.rs | 822 +++
tests/embeddings_rpc_e2e.rs | 147 +-
tests/inference_agent_raw_coverage_e2e.rs | 4667 +++++++++++++
...atible_admin_leftovers_raw_coverage_e2e.rs | 1000 +++
...mpatible_admin_round25_raw_coverage_e2e.rs | 373 ++
...ence_compatible_matrix_raw_coverage_e2e.rs | 836 +++
.../inference_local_admin_raw_coverage_e2e.rs | 794 +++
...erence_local_ops_piper_raw_coverage_e2e.rs | 346 +
...local_services_round21_raw_coverage_e2e.rs | 550 ++
...provider_admin_round22_raw_coverage_e2e.rs | 883 +++
tests/inference_provider_raw_coverage_e2e.rs | 693 ++
tests/inference_round26_raw_coverage_e2e.rs | 525 ++
...nce_voice_http_round23_raw_coverage_e2e.rs | 507 ++
tests/memory_core_threads_raw_coverage_e2e.rs | 726 ++
tests/memory_raw_coverage_e2e.rs | 650 ++
...ources_closure_round23_raw_coverage_e2e.rs | 266 +
...ources_readers_round21_raw_coverage_e2e.rs | 282 +
.../memory_sync_providers_raw_coverage_e2e.rs | 645 ++
tests/memory_sync_round23_raw_coverage_e2e.rs | 493 ++
.../memory_sync_slack_bus_raw_coverage_e2e.rs | 474 ++
tests/memory_sync_sources_raw_coverage_e2e.rs | 662 ++
...mory_sync_tree_round21_raw_coverage_e2e.rs | 589 ++
tests/memory_threads_raw_coverage_e2e.rs | 4869 ++++++++++++++
...ory_tree_embed_round25_raw_coverage_e2e.rs | 91 +
...ry_tree_memory_round23_raw_coverage_e2e.rs | 330 +
.../memory_tree_sync_deep_raw_coverage_e2e.rs | 779 +++
tests/memory_tree_sync_raw_coverage_e2e.rs | 647 ++
tests/near90_closure_raw_coverage_e2e.rs | 800 +++
tests/owned_domain_raw_coverage_e2e.rs | 875 +++
...tool_registry_approval_raw_coverage_e2e.rs | 1511 +++++
...gent_credentials_state_raw_coverage_e2e.rs | 929 +++
...ools_approval_channels_raw_coverage_e2e.rs | 4099 ++++++++++++
tests/tools_channels_raw_coverage_e2e.rs | 961 +++
...ools_composio_adapters_raw_coverage_e2e.rs | 553 ++
...composio_large_round25_raw_coverage_e2e.rs | 424 ++
...osio_network_leftovers_raw_coverage_e2e.rs | 920 +++
...tools_composio_round22_raw_coverage_e2e.rs | 570 ++
...tools_composio_round24_raw_coverage_e2e.rs | 385 ++
...tools_composio_round26_raw_coverage_e2e.rs | 554 ++
...tools_network_channels_raw_coverage_e2e.rs | 605 ++
tests/worker_b_domain_e2e.rs | 738 +++
tests/worker_b_raw_coverage_e2e.rs | 685 ++
tests/worker_c_modules_e2e.rs | 1238 ++++
129 files changed, 67834 insertions(+), 250 deletions(-)
create mode 100644 scripts/check-domain-e2e-coverage.mjs
create mode 100644 src/openhuman/channels/runtime/test_support.rs
create mode 100644 tests/agent_archivist_debug_round21_raw_coverage_e2e.rs
create mode 100644 tests/agent_harness_leftovers_raw_coverage_e2e.rs
create mode 100644 tests/agent_harness_raw_coverage_e2e.rs
create mode 100644 tests/agent_large_round25_raw_coverage_e2e.rs
create mode 100644 tests/agent_prompts_subagent_raw_coverage_e2e.rs
create mode 100644 tests/agent_round26_raw_coverage_e2e.rs
create mode 100644 tests/agent_session_round24_raw_coverage_e2e.rs
create mode 100644 tests/agent_session_turn_raw_coverage_e2e.rs
create mode 100644 tests/agent_tool_loop_raw_coverage_e2e.rs
create mode 100644 tests/agent_triage_dispatch_round23_raw_coverage_e2e.rs
create mode 100644 tests/agent_turn_builder_leftovers_raw_coverage_e2e.rs
create mode 100644 tests/agent_turn_toolloop_round22_raw_coverage_e2e.rs
create mode 100644 tests/app_credentials_threads_memory_sources_raw_coverage_e2e.rs
create mode 100644 tests/app_credentials_threads_round24_raw_coverage_e2e.rs
create mode 100644 tests/app_credentials_threads_sources_round26_raw_coverage_e2e.rs
create mode 100644 tests/app_state_credentials_raw_coverage_e2e.rs
create mode 100644 tests/channels_bus_presentation_raw_coverage_e2e.rs
create mode 100644 tests/channels_large_round25_raw_coverage_e2e.rs
create mode 100644 tests/channels_lark_email_dispatch_round21_raw_coverage_e2e.rs
create mode 100644 tests/channels_provider_deep_raw_coverage_e2e.rs
create mode 100644 tests/channels_provider_leftovers_raw_coverage_e2e.rs
create mode 100644 tests/channels_round24_raw_coverage_e2e.rs
create mode 100644 tests/channels_round26_raw_coverage_e2e.rs
create mode 100644 tests/channels_runtime_raw_coverage_e2e.rs
create mode 100644 tests/channels_web_startup_raw_coverage_e2e.rs
create mode 100644 tests/channels_web_telegram_raw_coverage_e2e.rs
create mode 100644 tests/channels_web_yuanbao_round22_raw_coverage_e2e.rs
create mode 100644 tests/composio_credentials_state_raw_coverage_e2e.rs
create mode 100644 tests/composio_ops_credentials_appstate_raw_coverage_e2e.rs
create mode 100644 tests/composio_ops_raw_coverage_e2e.rs
create mode 100644 tests/composio_raw_coverage_e2e.rs
create mode 100644 tests/composio_tools_direct_raw_coverage_e2e.rs
create mode 100644 tests/composio_tools_ops_state_raw_coverage_e2e.rs
create mode 100644 tests/config_auth_app_state_connectivity_e2e.rs
create mode 100644 tests/config_credentials_raw_coverage_e2e.rs
create mode 100644 tests/connectivity_raw_coverage_e2e.rs
create mode 100644 tests/credentials_threads_round22_raw_coverage_e2e.rs
create mode 100644 tests/domain_modules_e2e.rs
create mode 100644 tests/embeddings_ollama_raw_coverage_e2e.rs
create mode 100644 tests/inference_agent_raw_coverage_e2e.rs
create mode 100644 tests/inference_compatible_admin_leftovers_raw_coverage_e2e.rs
create mode 100644 tests/inference_compatible_admin_round25_raw_coverage_e2e.rs
create mode 100644 tests/inference_compatible_matrix_raw_coverage_e2e.rs
create mode 100644 tests/inference_local_admin_raw_coverage_e2e.rs
create mode 100644 tests/inference_local_ops_piper_raw_coverage_e2e.rs
create mode 100644 tests/inference_local_services_round21_raw_coverage_e2e.rs
create mode 100644 tests/inference_provider_admin_round22_raw_coverage_e2e.rs
create mode 100644 tests/inference_provider_raw_coverage_e2e.rs
create mode 100644 tests/inference_round26_raw_coverage_e2e.rs
create mode 100644 tests/inference_voice_http_round23_raw_coverage_e2e.rs
create mode 100644 tests/memory_core_threads_raw_coverage_e2e.rs
create mode 100644 tests/memory_raw_coverage_e2e.rs
create mode 100644 tests/memory_sources_closure_round23_raw_coverage_e2e.rs
create mode 100644 tests/memory_sources_readers_round21_raw_coverage_e2e.rs
create mode 100644 tests/memory_sync_providers_raw_coverage_e2e.rs
create mode 100644 tests/memory_sync_round23_raw_coverage_e2e.rs
create mode 100644 tests/memory_sync_slack_bus_raw_coverage_e2e.rs
create mode 100644 tests/memory_sync_sources_raw_coverage_e2e.rs
create mode 100644 tests/memory_sync_tree_round21_raw_coverage_e2e.rs
create mode 100644 tests/memory_threads_raw_coverage_e2e.rs
create mode 100644 tests/memory_tree_embed_round25_raw_coverage_e2e.rs
create mode 100644 tests/memory_tree_memory_round23_raw_coverage_e2e.rs
create mode 100644 tests/memory_tree_sync_deep_raw_coverage_e2e.rs
create mode 100644 tests/memory_tree_sync_raw_coverage_e2e.rs
create mode 100644 tests/near90_closure_raw_coverage_e2e.rs
create mode 100644 tests/owned_domain_raw_coverage_e2e.rs
create mode 100644 tests/tool_registry_approval_raw_coverage_e2e.rs
create mode 100644 tests/tools_agent_credentials_state_raw_coverage_e2e.rs
create mode 100644 tests/tools_approval_channels_raw_coverage_e2e.rs
create mode 100644 tests/tools_channels_raw_coverage_e2e.rs
create mode 100644 tests/tools_composio_adapters_raw_coverage_e2e.rs
create mode 100644 tests/tools_composio_large_round25_raw_coverage_e2e.rs
create mode 100644 tests/tools_composio_network_leftovers_raw_coverage_e2e.rs
create mode 100644 tests/tools_composio_round22_raw_coverage_e2e.rs
create mode 100644 tests/tools_composio_round24_raw_coverage_e2e.rs
create mode 100644 tests/tools_composio_round26_raw_coverage_e2e.rs
create mode 100644 tests/tools_network_channels_raw_coverage_e2e.rs
create mode 100644 tests/worker_b_domain_e2e.rs
create mode 100644 tests/worker_b_raw_coverage_e2e.rs
create mode 100644 tests/worker_c_modules_e2e.rs
diff --git a/docs/TEST-COVERAGE-MATRIX.md b/docs/TEST-COVERAGE-MATRIX.md
index c3562812b..cb2076f0b 100644
--- a/docs/TEST-COVERAGE-MATRIX.md
+++ b/docs/TEST-COVERAGE-MATRIX.md
@@ -286,7 +286,7 @@ Canonical mapping of every product feature to its test source(s). Drives gap-fil
| ID | Feature | Layer | Test path(s) | Status | Notes |
| ----- | ------------------ | ----- | ----------------------------------------- | ------ | --------------------------------- |
| 8.2.1 | Context Injection | RI | `tests/autocomplete_memory_e2e.rs` | ✅ | |
-| 8.2.2 | Memory Consistency | RI | `tests/memory_graph_sync_e2e.rs` | ✅ | |
+| 8.2.2 | Memory Consistency | RI | `tests/memory_graph_sync_e2e.rs`, `tests/worker_c_modules_e2e.rs` | ✅ | Worker C RPC E2E verifies memory-tree ingest is reflected by `memory_sync_status_list` |
| 8.2.3 | Memory Scaling | RU | `src/openhuman/memory/ingestion_tests.rs` | 🟡 | Soak/scale benchmark not asserted |
### 8.3 Memory Retrieval Benchmarks
@@ -386,7 +386,7 @@ Canonical mapping of every product feature to its test source(s). Drives gap-fil
| ID | Feature | Layer | Test path(s) | Status | Notes |
| ------ | ---------------------- | ----- | ------------------------------------------ | ------ | -------------------- |
| 10.5.1 | Channel Isolation | RU | `src/openhuman/channels/tests/identity.rs` | ✅ | |
-| 10.5.2 | Unified Inbox Handling | WD | `channels-smoke.spec.ts` | 🟡 | UI assertion shallow |
+| 10.5.2 | Unified Inbox Handling | WD+RI | `channels-smoke.spec.ts`, `tests/worker_c_modules_e2e.rs` | 🟡 | UI assertion shallow; RI covers config-only channel status after connect/disconnect |
| 10.5.3 | Context Preservation | RU | `src/openhuman/channels/tests/context.rs` | ✅ | |
### 10.6 Permission Enforcement
@@ -401,7 +401,7 @@ Canonical mapping of every product feature to its test source(s). Drives gap-fil
| ID | Feature | Layer | Test path(s) | Status | Notes |
| ------ | ---------------------- | ----- | ------------------------------------------- | ------ | -------------------------------- |
-| 10.7.1 | Integration Disconnect | WD | `gmail-flow.spec.ts` | ✅ | |
+| 10.7.1 | Integration Disconnect | WD+RI | `gmail-flow.spec.ts`, `tests/worker_c_modules_e2e.rs` | ✅ | RI covers `channels_disconnect` clearing config-only iMessage state |
| 10.7.2 | Token Revocation | RU | `src/openhuman/credentials/` | ✅ | |
| 10.7.3 | Re-Authorization Flow | WD | `skill-oauth.spec.ts` | 🟡 | Re-auth post-revoke not asserted |
| 10.7.4 | Permission Re-Sync | WD | _missing_ — tracked #968 | ❌ | |
@@ -418,7 +418,7 @@ Canonical mapping of every product feature to its test source(s). Drives gap-fil
| 11.1.2 | Actionable Item Extraction | VU | `app/src/components/intelligence/__tests__/utils.test.ts` (this PR) | ✅ | Was ❌ |
| 11.1.3 | Analyze Trigger | WD | `app/test/e2e/specs/insights-dashboard.spec.ts` mounts the route (this PR); explicit analyze-handler invocation TBD | 🟡 | Route mounts and search/filter UI assert — full analyze trigger flow tracked as follow-up |
| 11.1.4 | MCP server (stdio + HTTP) | RU | `src/openhuman/mcp_server/` | ✅ | Stdio framing plus Streamable HTTP/SSE session lifecycle; `McpHttpClient` round-trip tests |
-| 11.1.5 | Global tool registry | RI | `src/openhuman/tool_registry/`, `tests/json_rpc_e2e.rs` | ✅ | Read-only MCP/controller discovery with routes, schemas, version, allowed agents, and health |
+| 11.1.5 | Global tool registry | RI | `src/openhuman/tool_registry/`, `tests/json_rpc_e2e.rs`, `tests/domain_modules_e2e.rs`, `tests/worker_b_domain_e2e.rs` | ✅ | Read-only MCP/controller discovery with routes, schemas, version, allowed agents, and health |
| 11.1.6 | SearXNG MCP search | RU | `src/openhuman/integrations/searxng.rs`, `src/openhuman/mcp_server/tools.rs`, `src/openhuman/tools/schemas.rs` | ✅ | Self-hosted search config, normalized results, MCP argument validation, and mocked HTTP execution |
| 11.1.7 | Bundled prompt resources | RU | `src/openhuman/mcp_server/resources.rs`, `src/openhuman/mcp_server/protocol.rs` | ✅ | `resources/list` catalog + `resources/read` happy path, -32002 unknown URI, -32602 missing param, catalog-mirrors-BUILTINS parity test |
| 11.1.8 | Resource templates list | RU | `src/openhuman/mcp_server/resources.rs`, `src/openhuman/mcp_server/protocol.rs` | ✅ | `resources/templates/list` returns `{resourceTemplates: []}` (static catalog), tolerates unknown/cursor params |
diff --git a/package.json b/package.json
index 5eb28072c..f325aa858 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"test:coverage": "pnpm --filter openhuman-app test:coverage",
"test:rust": "pnpm --filter openhuman-app test:rust",
"test:rust:e2e": "bash scripts/test-rust-e2e.sh",
+ "test:rust:e2e:coverage": "node scripts/check-domain-e2e-coverage.mjs",
"test:e2e": "pnpm --filter openhuman-app test:e2e:all",
"test:e2e:flows": "pnpm --filter openhuman-app test:e2e:all:flows",
"mascot:render": "pnpm --dir remotion render:runtime-assets",
diff --git a/scripts/check-domain-e2e-coverage.mjs b/scripts/check-domain-e2e-coverage.mjs
new file mode 100644
index 000000000..69ce83098
--- /dev/null
+++ b/scripts/check-domain-e2e-coverage.mjs
@@ -0,0 +1,130 @@
+#!/usr/bin/env node
+import fs from 'node:fs';
+import path from 'node:path';
+
+const ROOT = process.cwd();
+const rawThreshold = process.env.DOMAIN_E2E_COVERAGE_THRESHOLD ?? '90';
+const THRESHOLD = Number(rawThreshold);
+if (!Number.isFinite(THRESHOLD) || THRESHOLD < 0 || THRESHOLD > 100) {
+ // A non-numeric value would make THRESHOLD NaN, turning every `percent <
+ // THRESHOLD` comparison false and silently disabling the gate. Fail loudly.
+ console.error(
+ `Invalid DOMAIN_E2E_COVERAGE_THRESHOLD="${rawThreshold}". Expected a number between 0 and 100.`,
+ );
+ process.exit(2);
+}
+
+const MODULES = [
+ { label: 'config', namespaces: ['config'] },
+ { label: 'credentials', namespaces: ['auth'] },
+ { label: 'app_state', namespaces: ['app_state'] },
+ { label: 'connectivity', namespaces: ['connectivity'] },
+ { label: 'inference', namespaces: ['inference'] },
+ { label: 'agent', namespaces: ['agent'] },
+ { label: 'tools', namespaces: ['tools'] },
+ { label: 'tool_registry', namespaces: ['tool_registry'] },
+ { label: 'approval', namespaces: ['approval'] },
+ { label: 'memory', namespaces: ['memory'] },
+ { label: 'memory_tree', namespaces: ['memory_tree'] },
+ { label: 'memory_sync', namespaces: ['memory_sync'] },
+ { label: 'memory_sources', namespaces: ['memory_sources'] },
+ { label: 'embeddings', namespaces: ['embeddings'] },
+ { label: 'channels', namespaces: ['channels'] },
+ { label: 'composio', namespaces: ['composio'] },
+ { label: 'threads', namespaces: ['threads'] },
+];
+
+const TARGET_NAMESPACES = new Set(MODULES.flatMap((module) => module.namespaces));
+
+function walk(dir, predicate, out = []) {
+ if (!fs.existsSync(dir)) return out;
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
+ const full = path.join(dir, entry.name);
+ if (entry.isDirectory()) {
+ walk(full, predicate, out);
+ } else if (predicate(full)) {
+ out.push(full);
+ }
+ }
+ return out;
+}
+
+function read(file) {
+ return fs.readFileSync(file, 'utf8');
+}
+
+function collectInvokedMethods() {
+ const methods = new Set();
+ const testsDir = path.join(ROOT, 'tests');
+ const files = walk(testsDir, (file) => file.endsWith('_e2e.rs'));
+
+ for (const file of files) {
+ const text = read(file);
+ for (const match of text.matchAll(/"((?:openhuman)\.[A-Za-z0-9_]+)"/g)) {
+ methods.add(match[1]);
+ }
+ }
+
+ return methods;
+}
+
+function collectSchemaMethods() {
+ const methodsByNamespace = new Map([...TARGET_NAMESPACES].map((namespace) => [namespace, new Set()]));
+ const files = walk(path.join(ROOT, 'src', 'openhuman'), (file) => {
+ const normalized = file.split(path.sep).join('/');
+ return file.endsWith('.rs') && /(^|\/)schemas?(\.rs|\/)/.test(normalized);
+ });
+
+ for (const file of files) {
+ const text = read(file);
+ const constNamespace = text.match(/const\s+NAMESPACE:\s*&str\s*=\s*"([a-z_]+)"/)?.[1];
+ for (const match of text.matchAll(/ControllerSchema\s*\{([\s\S]*?)\n\s*\}/g)) {
+ const block = match[1];
+ const namespaceToken = block.match(/namespace:\s*(?:NAMESPACE|"([a-z_]+)")/);
+ const functionName = block.match(/function:\s*"([A-Za-z0-9_]+)"/)?.[1];
+ const namespace = namespaceToken?.[1] ?? (namespaceToken ? constNamespace : undefined);
+ if (!namespace || !functionName || functionName === 'unknown') continue;
+ if (!TARGET_NAMESPACES.has(namespace)) continue;
+ methodsByNamespace.get(namespace).add(`openhuman.${namespace}_${functionName}`);
+ }
+ }
+
+ return methodsByNamespace;
+}
+
+const invoked = collectInvokedMethods();
+const schemas = collectSchemaMethods();
+let failed = false;
+
+console.log(`Domain Rust E2E controller coverage threshold: ${THRESHOLD}%`);
+console.log('');
+console.log('| Module | Namespace(s) | Covered | Percent | Missing |');
+console.log('| --- | --- | ---: | ---: | --- |');
+
+for (const module of MODULES) {
+ const expected = new Set();
+ const covered = new Set();
+ for (const namespace of module.namespaces) {
+ for (const method of schemas.get(namespace) ?? []) expected.add(method);
+ }
+ for (const method of expected) {
+ if (invoked.has(method)) covered.add(method);
+ }
+
+ const missing = [...expected].filter((method) => !covered.has(method)).sort();
+ const percent = expected.size === 0 ? 100 : (covered.size / expected.size) * 100;
+ const missingText = missing.length === 0 ? '-' : missing.join('
');
+
+ console.log(
+ `| ${module.label} | ${module.namespaces.join(', ')} | ${covered.size}/${expected.size} | ${percent.toFixed(1)}% | ${missingText} |`,
+ );
+
+ if (expected.size > 0 && percent < THRESHOLD) failed = true;
+}
+
+if (failed) {
+ console.error(`\nDomain Rust E2E controller coverage is below ${THRESHOLD}% for one or more modules.`);
+ process.exit(1);
+}
+
+console.log(`\nAll named modules meet the ${THRESHOLD}% Rust E2E controller coverage threshold.`);
diff --git a/scripts/test-rust-e2e.sh b/scripts/test-rust-e2e.sh
index f863a1683..6afd1e6e2 100755
--- a/scripts/test-rust-e2e.sh
+++ b/scripts/test-rust-e2e.sh
@@ -34,15 +34,31 @@ ALL_E2E_SUITES=(
agent_retrieval_e2e
autocomplete_memory_e2e
calendar_grounding_e2e
+ config_auth_app_state_connectivity_e2e
+ composio_post_oauth_retry_e2e
+ cwd_jail_e2e
+ domain_modules_e2e
+ embeddings_rpc_e2e
+ inference_provider_e2e
json_rpc_e2e
keyring_secretstore_fresh_e2e
keyring_secretstore_e2e
linux_cef_deb_runtime_e2e
live_routing_e2e
+ mcp_registry_e2e
+ mcp_setup_e2e
+ memory_artifacts_e2e
memory_graph_sync_e2e
memory_roundtrip_e2e
+ memory_sources_e2e
+ memory_tree_summarizer_e2e
+ memory_tree_walk_e2e
+ ollama_embeddings_fallback_e2e
screen_intelligence_vision_e2e
subconscious_e2e
+ vault_sync_e2e
+ worker_b_domain_e2e
+ worker_c_modules_e2e
)
# Parse args: --suite can be passed multiple times to filter.
diff --git a/src/openhuman/agent/harness/mod.rs b/src/openhuman/agent/harness/mod.rs
index 1fee0268f..9f76fc0f4 100644
--- a/src/openhuman/agent/harness/mod.rs
+++ b/src/openhuman/agent/harness/mod.rs
@@ -19,7 +19,7 @@
//! - **[`fork_context`]**: Task-local storage for parent context sharing.
//! - **[`interrupt`]**: Infrastructure for graceful cancellation of agent loops.
-pub(crate) mod archivist;
+pub mod archivist;
pub(crate) mod builtin_definitions;
mod credentials;
pub mod definition;
diff --git a/src/openhuman/agent/harness/subagent_runner/extract_tool.rs b/src/openhuman/agent/harness/subagent_runner/extract_tool.rs
index 1d07f216d..65dbf94b4 100644
--- a/src/openhuman/agent/harness/subagent_runner/extract_tool.rs
+++ b/src/openhuman/agent/harness/subagent_runner/extract_tool.rs
@@ -44,11 +44,27 @@ const EXTRACT_MODEL_ID: &str = "summarization-v1";
/// answer, without straying into creative territory.
const EXTRACT_TEMPERATURE: f64 = 0.2;
-/// Char budget per extraction call. Chosen so a single chunk + prompt
-/// scaffolding + output stays well below the extraction model's context
-/// window (~196k tokens) — at ~4 chars/token that leaves comfortable
-/// headroom for the extraction contract and response.
-const EXTRACT_CHUNK_CHAR_BUDGET: usize = 60_000;
+/// Char budget per extraction call, derived from the extraction model's
+/// context window. A payload at or under this budget is extracted in a single
+/// shot over its **entire** content — higher quality than the chunk+concat
+/// fallback, which has no reduce stage and can miss facts that span a chunk
+/// boundary or need global context. `summarization-v1` resolves to a
+/// long-context flash model (~1M tokens), so this is large; only payloads that
+/// exceed it fall back to parallel chunked extraction. Headroom is reserved for
+/// the extraction contract, the query, and the response.
+fn extract_chunk_char_budget() -> usize {
+ /// Fallback window (tokens) when the model id is unknown to the registry.
+ const FALLBACK_WINDOW_TOKENS: u64 = 128_000;
+ /// Approximate chars per token used for budgeting.
+ const CHARS_PER_TOKEN: u64 = 4;
+ /// Fraction of the window spent on the payload slice; the remainder covers
+ /// the prompt scaffolding, query, and model response.
+ const USABLE_PCT: u64 = 70;
+
+ let window_tokens = crate::openhuman::inference::context_window_for_model(EXTRACT_MODEL_ID)
+ .unwrap_or(FALLBACK_WINDOW_TOKENS);
+ (window_tokens * USABLE_PCT / 100 * CHARS_PER_TOKEN) as usize
+}
/// System prompt fed to the provider on every `extract_from_result`
/// call. Lifted in spirit from the old `summarizer` agent's prompt but
@@ -168,8 +184,16 @@ impl Tool for ExtractFromResultTool {
}
};
+ // Allow test harnesses to lower the chunk budget so multi-chunk
+ // extraction can be exercised on compacted payloads. Never consulted
+ // in production (env var absent).
+ let effective_chunk_budget = std::env::var("OPENHUMAN_TEST_EXTRACT_CHUNK_BUDGET")
+ .ok()
+ .and_then(|v| v.parse::().ok())
+ .unwrap_or_else(extract_chunk_char_budget);
+
// Fast path: payload fits in a single provider turn.
- if cached.content.len() <= EXTRACT_CHUNK_CHAR_BUDGET {
+ if cached.content.len() <= effective_chunk_budget {
tracing::debug!(
tool = %cached.tool_name,
bytes = cached.content.len(),
@@ -195,12 +219,12 @@ impl Tool for ExtractFromResultTool {
// failure when the upstream provider stalls. For
// listing/extraction queries concatenation is equivalent; for
// top-N / global-ordering queries the caller can post-process.
- let chunks = chunk_content(&cached.content, EXTRACT_CHUNK_CHAR_BUDGET);
+ let chunks = chunk_content(&cached.content, effective_chunk_budget);
tracing::info!(
tool = %cached.tool_name,
total_bytes = cached.content.len(),
chunk_count = chunks.len(),
- chunk_budget = EXTRACT_CHUNK_CHAR_BUDGET,
+ chunk_budget = effective_chunk_budget,
"[extract_from_result] chunked extraction"
);
diff --git a/src/openhuman/agent/harness/subagent_runner/ops.rs b/src/openhuman/agent/harness/subagent_runner/ops.rs
index 97dd61853..18cd8a239 100644
--- a/src/openhuman/agent/harness/subagent_runner/ops.rs
+++ b/src/openhuman/agent/harness/subagent_runner/ops.rs
@@ -1387,7 +1387,15 @@ fn apply_handoff(
cleaned
};
let tokens = cleaned.len().div_ceil(4);
- if !skip_cleaning && tokens > HANDOFF_OVERSIZE_THRESHOLD_TOKENS {
+ // Allow test harnesses (lib tests AND integration test binaries) to lower
+ // the threshold so the handoff path can be exercised on payloads that
+ // survive tokenjuice's compaction cap. Never consulted in production
+ // (the env var is absent) so there is zero runtime cost.
+ let effective_threshold = std::env::var("OPENHUMAN_TEST_HANDOFF_THRESHOLD_TOKENS")
+ .ok()
+ .and_then(|v| v.parse::().ok())
+ .unwrap_or(HANDOFF_OVERSIZE_THRESHOLD_TOKENS);
+ if !skip_cleaning && tokens > effective_threshold {
let id = cache.store(tool_name.to_string(), cleaned.clone());
let placeholder = build_handoff_placeholder(tool_name, &id, &cleaned);
tracing::info!(
@@ -1396,7 +1404,7 @@ fn apply_handoff(
tool = %tool_name,
raw_tokens = tokens,
raw_bytes = cleaned.len(),
- threshold_tokens = HANDOFF_OVERSIZE_THRESHOLD_TOKENS,
+ threshold_tokens = effective_threshold,
result_id = %id,
"[subagent_runner:handoff] stashed oversized tool output; substituted placeholder into history"
);
diff --git a/src/openhuman/app_state/schemas.rs b/src/openhuman/app_state/schemas.rs
index d051c737e..bae42fa99 100644
--- a/src/openhuman/app_state/schemas.rs
+++ b/src/openhuman/app_state/schemas.rs
@@ -1,3 +1,4 @@
+use serde::de::{self, DeserializeOwned};
use serde::Deserialize;
use serde_json::{Map, Value};
@@ -9,9 +10,9 @@ use super::ops::StoredAppStatePatch;
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct UpdateLocalStateParams {
- #[serde(default)]
+ #[serde(default, deserialize_with = "deserialize_nullable_patch")]
encryption_key: Option