---
name: feature-test
description: "Orchestrate parallel feature/capability testing via subagents. Groups tests by category (MCP, API, skill, tool, channel), tracks state in the knowledge graph, reports via per-group messages with status emojis. Use when the user asks to test capabilities, run diagnostics, or verify integrations."
metadata: { "minion": { "emoji": "🧪", "always": true } }
---

# Feature Test Orchestration

Run structured capability tests by spawning one subagent per test group, tracking state in the knowledge graph, and reporting results via channel messages with live status updates.

## IMPORTANT: You Are the Orchestrator

**YOU (the parent agent) must execute this workflow directly.** Do NOT spawn a single subagent to "run the feature-test skill." You must:

1. Create the KG nodes yourself using `remember`, `update_entity`, `find_related`
2. Send the placeholder messages yourself
3. Spawn one subagent PER GROUP — each tests only its specific category
4. Collect results from subagent KG node updates

Subagents have restricted tool access. Only the parent agent can create KG nodes, send messages, and spawn further subagents.

## When to Use

- User asks to "test capabilities", "test features", "run diagnostics", "verify integrations"
- User asks to test a specific category (e.g., "test all messaging channels")
- User asks for a capability audit or health check

## Status Emojis (fixed)

| Status    | Emoji | Meaning                       |
| --------- | ----- | ----------------------------- |
| `pending` | ⏳    | Created, not started          |
| `running` | 🔄    | Actively testing              |
| `passed`  | ✅    | All tests passed              |
| `failed`  | ❌    | One or more failures          |
| `partial` | ⚠️    | Mixed results                 |
| `blocked` | 🚫    | Cannot proceed (auth, config) |

You may add a context emoji alongside status (e.g., 🔑 needs auth, 🔍 investigating).

## Workflow

### 1. Group capabilities

Analyze the available skills, tools, plugins, and channels. Group them by category at runtime based on context. Common groupings:

- **messaging** — WhatsApp, Telegram, Discord, Slack, etc.
- **mcp_tools** — MCP server integrations
- **skills_core** — Installed skills (oracle, coding-agent, etc.)
- **scheduling** — Cron jobs, timers
- **media** — Image gen, transcription, TTS
- **search** — Web search, knowledge retrieval
- **memory** — Knowledge graph, session memory
- **auth** — OAuth, calendar, email integrations

Merge small groups. Skip categories with no testable items.

### 2. Create knowledge graph nodes

Use the knowledge graph tools to create a structured node hierarchy:

```
TEST_FEATURES (anchor)
  └── <Title>_yyyyMMdd (test run)
       ├── <group_1> (subagent)
       ├── <group_2> (subagent)
       └── ...
```

#### Step 2a — Anchor node

```
recall_entity("TEST_FEATURES")
```

If not found, create it:

```
remember({
  label: "TEST_FEATURES",
  type: "entity",
  data: {
    description: "Anchor for feature test runs",
    title: "TEST_FEATURES",
    created: <now_ms>,
    last_updated: <now_ms>,
    status: "running",
    summary: "Feature test anchor node"
  }
})
```

#### Step 2b — Test run node

```
remember({
  label: "<Title>_yyyyMMdd",       // e.g., "CapabilityTest_20260405"
  type: "entity",
  data: {
    created: <now_ms>,
    last_updated: <now_ms>,
    description: "Full capability test",      // <=50 chars
    title: "CapTest",                          // <=20 chars
    status: "running",
    summary: "",
    run_id: "<uuid>",
    groups: ["messaging", "mcp_tools", ...],
    channel: "<current_channel>"
  }
})
```

Link to anchor:

```
find_related(<anchor_id>)   // check existing
linkObjects(<run_id>, <anchor_id>, "part_of")
```

#### Step 2c — Subagent nodes (one per group)

```
remember({
  label: "<group_name>",          // e.g., "messaging_channels"
  type: "entity",
  data: {
    created: <now_ms>,
    last_updated: <now_ms>,
    description: "Test messaging integrations",   // <=50 chars
    title: "Messaging",                            // <=20 chars
    status: "pending",
    summary: "",
    specialty: "messaging channels",
    scope: "whatsapp, telegram, discord",
    message_id: "",        // filled after sending message
    chat_id: "",           // filled after sending message
    channel: "",           // filled after sending message
    agent_session_key: ""  // filled after spawn
  }
})
```

Link to test run:

```
linkObjects(<subagent_node_id>, <run_id>, "part_of")
```

### Node Properties Reference

**Fixed properties (all nodes):**

| Property       | Type   | Constraint        | Purpose                         |
| -------------- | ------ | ----------------- | ------------------------------- |
| `created`      | number | unix ms, required | Creation timestamp              |
| `last_updated` | number | unix ms, required | Last modification               |
| `description`  | string | <=50 chars        | Brief purpose                   |
| `title`        | string | <=20 chars        | Short display name              |
| `status`       | string | enum (see above)  | Current state                   |
| `summary`      | string | paragraph         | Full text output / message body |

**Test run additional:**

| Property  | Type     | Purpose              |
| --------- | -------- | -------------------- |
| `run_id`  | string   | Unique run ID        |
| `groups`  | string[] | Subagent group names |
| `channel` | string   | Originating channel  |

**Subagent additional:**

| Property            | Type   | Purpose              |
| ------------------- | ------ | -------------------- |
| `specialty`         | string | Agent focus area     |
| `scope`             | string | What's being tested  |
| `message_id`        | string | Channel message ID   |
| `chat_id`           | string | Channel chat ID      |
| `channel`           | string | Channel identifier   |
| `agent_session_key` | string | Subagent session key |

**Custom properties** are encouraged. Add any test-specific fields:

- `error_details` — error messages for failed tests
- `test_count` — total number of test items
- `passed_count` — number that passed
- `duration_ms` — total test duration
- `auth_required` — whether auth is blocking

### 3. Send one message per group

Before spawning subagents, send a placeholder message for each group to the current channel:

```
⏳ <Group Title>
Testing: <scope items>
Status: pending
```

Store the returned `message_id` and `chat_id` in the subagent node:

```
update_entity(<subagent_node_id>, {
  data: {
    message_id: "<returned_message_id>",
    chat_id: "<chat_id>",
    channel: "<current_channel>"
  }
})
```

### 4. Spawn subagents

Spawn one subagent per group using `sessions_spawn`. Include in the task prompt:

- The subagent's KG node ID
- The message ID and chat details
- The list of items to test in this group
- Instructions to update the node via `update_entity` as tests complete

Example task:

```
You are testing the messaging group. Your KG node ID is <node_id>.

Test items: WhatsApp send, Telegram send, Discord send, Slack send

For each test:
1. Attempt the test
2. Record pass/fail
3. Update your KG node with update_entity after each test

Summary format (set in data.summary):
🔄 Messaging Channels
- ✅ WhatsApp send — msg delivered
- ✅ Telegram send — msg delivered
- ❌ Discord send — bot token missing
- ⏳ Slack send — testing...

Update data.status to reflect overall result:
- "passed" if all pass
- "failed" if any fail
- "partial" if mixed
- "blocked" if cannot proceed

The kg-message-sync hook will automatically edit the channel
message when you update the summary field.
```

### 5. Subagent responsibilities

Each subagent MUST:

1. **Update status to `running`** immediately:

   ```
   update_entity(<node_id>, { data: { status: "running", last_updated: <now> } })
   ```

2. **Run each test** in its scope

3. **Update summary progressively** after each test item:

   ```
   update_entity(<node_id>, {
     data: {
       summary: "<formatted_results>",
       last_updated: <now>,
       passed_count: N,
       test_count: M
     }
   })
   ```

4. **Set final status** when done:
   ```
   update_entity(<node_id>, {
     data: {
       status: "passed" | "failed" | "partial" | "blocked",
       last_updated: <now>,
       summary: "<final_formatted_results>"
     }
   })
   ```

### 6. Summary format spec

Subagent summaries should be brief and scannable:

```
<status_emoji> <Group Title>
- ✅ <item> — <brief result>
- ❌ <item> — <error reason>
- 🚫 <item> — <blocked reason>
- ⏳ <item> — testing...

<N>/<M> passed
```

Keep each line under ~60 chars. Use emojis for visual scanning.

### 7. Collect results

After all subagents complete, update the test run node:

```
update_entity(<run_node_id>, {
  data: {
    status: "<overall_status>",
    last_updated: <now>,
    summary: "<aggregated_summary>"
  }
})
```

Send a final summary message to the user listing all groups and their outcomes.

### 8. Channel behavior

- **Telegram/Discord/Slack**: The `kg-message-sync` hook automatically edits messages when `summary` updates. Status reactions are also synced.
- **WhatsApp**: Message edits are skipped. Status reactions are applied. The final summary is sent as a single new message at the end.

## Hook: kg-message-sync

This skill relies on the `kg-message-sync` bundled hook. It listens to `memory:node_updated` events and:

1. Checks if the node has `message_id`, `chat_id`, `channel` in its data
2. If `summary` changed, edits the channel message with new content
3. If `status` changed, updates the reaction emoji

The hook handles channel routing automatically. Subagents don't need to call edit/react tools directly — just update the KG node.

## Querying Past Runs

To check previous test results:

```
recall_entity("TEST_FEATURES")           // get anchor
find_related(<anchor_id>)                 // list all runs
find_related(<run_id>)                    // list subagent results
recall_entity("<Title>_yyyyMMdd")         // find specific run
```

Node data contains full history: timestamps, status, summary, custom metrics.
