# Knowledge Ingest UX — Problem Analysis, Plan & Grounding

Last updated: 2026-03-05 20:42 CET

> Date: 2026-03-05
> Status: Approved for implementation
> Reviewed by: Claude Opus 4.6 + GPT Plan Reviewer (Codex)

## Problem

When calling `knowledge_ingest`, users and LLM agents must **guess property names** for each Weaviate collection. The tool accepts a generic `dict` for `properties` and validates against the collection schema at runtime — but the schema is never exposed.

This creates a trial-and-error loop:

```
1. Call knowledge_ingest with intuitive property names
2. Get "Unknown properties" error (no hints about what IS allowed)
3. Search existing objects to reverse-engineer the schema
4. Retry with (hopefully) correct names
5. Hit type errors (e.g., string instead of text[])
6. Retry again
```

### Session Evidence (2026-03-05)

Real-world session: GPT-5.4 video analysis with cross-platform sentiment research via 4 parallel researcher agents.

**8 failed calls** before successful ingestion:

| Collection | Rejected Properties | Correct Properties |
|------------|--------------------|--------------------|
| `VideoMetadata` | `channel`, `local_filepath`, `source_url`, `screenshot_dir` | `channel_title` |
| `VideoAnalyses` | `key_points` as string | `key_points` as `text[]` |
| `CommunityReactions` | `platform`, `reaction_summary`, `sentiment_score`, `source_url` | `consensus`, `themes_positive`, `themes_critical`, `notable_opinions_json` |
| `ResearchFindings` | `finding`, `sources` | `claim`, `supporting` |
| `ConceptKnowledge` | `category`, `name`, `related_concepts` | `concept_name`, `description`, `state`, `source_tool` |

### Impact

- **Token waste**: ~500-1000 tokens per failed attempt (8 failures = ~6000 tokens wasted)
- **Agent failures**: Background agents can't self-correct without a schema discovery mechanism
- **Adoption barrier**: New users hit this wall on first manual ingest
- **Stale docs**: `docs/tutorials/KNOWLEDGE_STORE.md:339` claims the error already lists allowed fields — it doesn't

## Root Cause

The schema is defined in `weaviate_schema/*.py` as `CollectionDef` objects with `name`, `data_type`, and `description` per property. The `ALLOWED_PROPERTIES` dict in `tools/knowledge/helpers.py` validates against these at runtime (line ~17). But this information is **never surfaced** to the caller — not in errors, not in docstrings, not via any discovery tool.

### Key code locations

| File | What |
|------|------|
| `src/video_research_mcp/weaviate_schema/base.py:15` | `CollectionDef` dataclass — `name`, `data_type`, `description` (no `required` field) |
| `src/video_research_mcp/weaviate_schema/collections.py` | All 12 collection definitions with property lists |
| `src/video_research_mcp/tools/knowledge/helpers.py:17` | `ALLOWED_PROPERTIES` dict — source of truth for validation |
| `src/video_research_mcp/tools/knowledge/ingest.py:52-56` | Validation logic — rejects unknown keys, but error only shows rejected names |
| `src/video_research_mcp/tools/knowledge/__init__.py:5` | Tool registration — currently exports 7 tools |
| `docs/tutorials/KNOWLEDGE_STORE.md:339` | Stale claim that error lists allowed fields |

## Plan

Six changes, ordered by dependency. All ship together in one PR.

### Step 1: Enrich error message in `knowledge_ingest` (3-5 lines)

**File**: `tools/knowledge/ingest.py:54`

Current error:
```python
f"Unknown properties for {collection}: {sorted(unknown)}"
```

New error — includes `name:type` pairs and a pointer to the schema tool:
```python
f"Unknown properties for {collection}: {sorted(unknown)}. "
f"Allowed: {', '.join(f'{k}:{v}' for k, v in sorted(allowed_with_types.items()))}. "
f"Use knowledge_schema(collection='{collection}') for full details."
```

**Rationale**: Reactive fix. Even without the schema tool, this halves the trial-and-error loop by showing correct names AND types in the error itself.

### Step 2: Fix stale documentation (1-2 lines)

**File**: `docs/tutorials/KNOWLEDGE_STORE.md:339`

The tutorial claims the error already shows allowed fields. This is false. Either update the text to match the new behavior (after step 1) or remove the inaccurate claim.

### Step 3: Add `knowledge_schema` tool (~40 lines)

**File**: New tool, likely in `tools/knowledge/schema.py` or added to an existing knowledge tool file.

```python
@knowledge_server.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def knowledge_schema(
    collection: Annotated[
        KnowledgeCollection | None,
        Field(description="Collection name, or omit for all collections"),
    ] = None,
) -> dict:
    """Show the property schema for knowledge collections.

    Returns property names, types, and descriptions. Use before
    knowledge_ingest to see what properties are expected.

    Args:
        collection: Optional collection name to filter.

    Returns:
        Dict with collection schemas.
    """
```

Key design decisions:

- **No Weaviate connection required** — reads from local `CollectionDef` Python objects, not from the Weaviate instance. Works even when `WEAVIATE_URL` is empty.
- **No `required` flag** — `CollectionDef` has no concept of required vs optional. Don't fabricate metadata that doesn't exist.
- **Single-collection is the primary path** — all-collections response can bloat agent context (12 collections x ~10 properties each). Single-collection lookup should be the recommended usage.
- **Compact response** — return `name`, `type`, `description` per property. No references (those aren't writable via `knowledge_ingest`).

### Step 4: Register tool + add discoverability hint (5 lines)

**Files**:
- `tools/knowledge/__init__.py` — add `knowledge_schema` to exports
- `tools/knowledge/ingest.py` — add one line to `knowledge_ingest` docstring:

```python
"""Manually insert data into a knowledge collection.

Tip: call knowledge_schema(collection=...) first to see expected properties.
...
"""
```

**Rationale**: A tool only helps if callers know it exists. The docstring hint is the discoverability bridge from ingest to schema. Unlike fix #3 (rejected docstring with hardcoded field lists), this is a pointer — it won't go stale.

### Step 5: Tests (4 cases, ~60 lines)

**File**: `tests/test_knowledge_schema.py` (or added to existing knowledge test file)

| Test | What it verifies |
|------|-----------------|
| `test_knowledge_schema_single_collection` | Returns correct properties for one collection |
| `test_knowledge_schema_all_collections` | Returns all 12 collections with schemas |
| `test_knowledge_schema_no_weaviate` | Works without Weaviate configured |
| `test_knowledge_ingest_error_shows_allowed` | Error message includes `name:type` pairs and schema hint |

### Step 6: Documentation updates (~10 lines across files)

Update all references to "7 knowledge tools" to "8 knowledge tools":

| File | Location |
|------|----------|
| `README.md` | Tool count in features section |
| `CLAUDE.md` | Architecture table — knowledge row |
| `docs/ARCHITECTURE.md` | Knowledge sub-server section |
| `docs/tutorials/KNOWLEDGE_STORE.md` | Tool inventory + fixed stale claim (step 2) |

Add `knowledge_schema` to the knowledge tool table with description.

## Grounding — Why This Plan, Not Alternatives

### Why not just fix #2 (error message) alone?

Fix #2 is reactive — it only helps **after** a failure. For human users, one failure + good error is acceptable. For **agent workflows** (the primary consumer of these tools), any failure is a wasted round-trip. The schema tool enables first-try success, which is the real goal.

### Why not fold schema info into the error message and skip the separate tool?

The error message should be actionable (it now will be), but it's the wrong place for full documentation. Errors are reactive; schema discovery is proactive. Different usage patterns, different tools.

### Why not hardcode property lists in the docstring (fix #3)?

Creates a second source of truth that **will** drift from the actual schema. Every schema change requires remembering to update the docstring — and forgetting is silent (no test catches it). The pointer-based approach (step 4) is durable: it says "ask the schema tool" rather than "here are the fields."

### Why no `required` vs `optional`?

`CollectionDef` in `weaviate_schema/base.py` has three fields: `name`, `data_type`, `description`. There is no `required` attribute. Fabricating one would be dishonest. If required/optional semantics are added to the schema later, `knowledge_schema` can expose them then.

### Why must `knowledge_schema` work without Weaviate?

The schema is defined in Python code (`weaviate_schema/collections.py`), not in the Weaviate instance. Requiring a live Weaviate connection would make the tool useless in the exact scenario where it's most needed: initial setup, testing, and agents running without a configured knowledge store. The validation in `helpers.py` already works from local data — the schema tool should too.

### Why ship all 6 steps together?

Steps 1-2 are trivially small. Step 3 is the core feature. Steps 4-6 are housekeeping. Splitting across PRs creates intermediate states where docs are wrong or the discoverability bridge is missing. One atomic PR is cleaner.

## Effort Estimate

| Step | Lines changed | Risk |
|------|--------------|------|
| 1. Error message | 3-5 | None |
| 2. Stale docs | 1-2 | None |
| 3. Schema tool | ~40 | Low — read-only, no side effects |
| 4. Registration + hint | ~5 | None |
| 5. Tests | ~60 | None |
| 6. Doc updates | ~10 | None |
| **Total** | **~120** | **Low** |

## Decision Log

| Decision | Chose | Over | Why |
|----------|-------|------|-----|
| Priority order | #2 first, #1 next | #1 first | Error fix is 3 lines with zero risk; ship immediately |
| Fix #3 | Skip | Implement | Fragile, creates drift risk, unnecessary with #1+#2 |
| `required` field | Omit | Include | No source of truth in `CollectionDef` |
| Weaviate dependency | Not required | Required | Schema is local Python data, not instance data |
| Separate tool vs error-only | Separate tool | Fold into error | Different usage patterns (proactive vs reactive) |
| Ship strategy | Single PR | Split PRs | Avoids intermediate broken states |
