Files
Orchestrator/bahn/teamlandkarte-mcp/.kiro/specs/capacity-details-enrichment/design.md
T
ankn a5f8fb49ab Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
2026-06-30 20:39:52 +02:00

7.5 KiB
Raw Blame History

Design Document: Capacity Details Enrichment

Overview

This feature enriches the existing get_capacity_details MCP tool to display additional information about a capacity: its description, references (partner + projects), and certifications. The data is already available in the database and exposed through existing DBClient methods (get_capacity_description, get_capacity_references, get_capacity_certificates). The change is purely in the tool's output formatting layer.

The tool currently returns a Markdown table with basic capacity fields (ID, Owner, Role, Competences, Availability) followed by a "Next steps" section. After this enhancement, it will include three additional sections between the table and the next steps: Beschreibung, Referenzen, and Zertifizierungen.

Architecture

The change is localized to the get_capacity_details tool function inside build_server() in src/teamlandkarte_mcp/mcp_server.py. No new modules, classes, or external dependencies are needed.

sequenceDiagram
    participant Client as MCP Client
    participant Tool as get_capacity_details
    participant DB as DBClient

    Client->>Tool: call(capacity_id)
    Tool->>DB: get_capacity_by_id(capacity_id)
    DB-->>Tool: Capacity | None
    Tool->>DB: get_capacity_description(capacity_id)
    DB-->>Tool: str | None
    Tool->>DB: get_capacity_references(capacity_id)
    DB-->>Tool: list[CapacityReferenceRow]
    Tool->>DB: get_capacity_certificates(capacity_id)
    DB-->>Tool: list[str]
    Tool-->>Client: Formatted Markdown string

Design Decisions

  1. Sequential DB calls The three additional queries are simple key lookups on indexed views. Parallelizing them would add complexity (async conversion of the tool) for negligible latency gain. Keep the tool synchronous.
  2. Formatting inline The formatting logic is simple string concatenation. No need for a separate formatter class.
  3. Empty-state handling Each section shows a "(keine)" placeholder when data is absent, keeping the output structure predictable for LLM consumers.

Components and Interfaces

Modified Component: get_capacity_details tool

Current signature (unchanged):

def get_capacity_details(capacity_id: int | str) -> str:

New internal calls added:

description: str | None = db_client.get_capacity_description(capacity_id)
references: list[CapacityReferenceRow] = db_client.get_capacity_references(capacity_id)
certificates: list[str] = db_client.get_capacity_certificates(capacity_id)

Output format (Markdown string):

| ID | Owner | Role | Competences | Availability |
| ... |

## Beschreibung

<description text or "(keine)">

## Referenzen

- **Partner A**: Projekt X, Projekt Y
- Projekt Z (no partner)

*or* Referenzen: (keine)

## Zertifizierungen

- Zertifikat 1
- Zertifikat 2

*or* Zertifizierungen: (keine)

## Next steps

Call find_matching_tasks(capacity_id=...) to see matching open tasks.

Existing Interfaces Used (no changes)

Method Returns Source
DBClient.get_capacity_description(capacity_id) str | None teamlandkarte_v_capacities_latest.description
DBClient.get_capacity_references(capacity_id) list[CapacityReferenceRow] teamlandkarte_v_capacity_references_latest joined with partners
DBClient.get_capacity_certificates(capacity_id) list[str] teamlandkarte_v_capacity_certificates_latest.description

Data Models

CapacityReferenceRow (existing, unchanged)

class CapacityReferenceRow(TypedDict):
    partner_name: str   # May be empty string when partner_id is NULL
    projects: str       # Project text from the references view

No new data models are introduced.

Correctness Properties

A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.

Property 1: All enrichment data is fetched for any capacity

For any valid capacity ID that resolves to an existing capacity, the tool SHALL invoke get_capacity_description, get_capacity_references, and get_capacity_certificates with that capacity ID.

Validates: Requirements 1.1, 2.1, 3.1

Property 2: Non-empty data appears in output

For any capacity with a non-empty description, a non-empty list of references, and a non-empty list of certificates, the formatted output SHALL contain the description text, every reference's projects text, and every certificate string.

Validates: Requirements 1.2, 2.2, 3.2

Property 3: Section ordering is fixed

For any capacity (regardless of which fields are empty or populated), the output string SHALL contain the section markers in the order: capacity table first, then "Beschreibung", then "Referenzen", then "Zertifizierungen", then "Next steps" — and each section SHALL be separated by at least one blank line.

Validates: Requirements 4.1, 4.2

Error Handling

Scenario Behaviour
get_capacity_by_id returns None Return "Capacity not found: {capacity_id}" (existing behaviour, unchanged)
get_capacity_description returns None Display "Beschreibung: (keine)"
get_capacity_references returns [] Display "Referenzen: (keine)"
get_capacity_certificates returns [] Display "Zertifizierungen: (keine)"
get_capacity_references returns a row with empty partner_name Display only the projects text (no bold partner prefix)
Any DB call raises an exception Let it propagate (existing error handling in the MCP framework catches and reports it)

Testing Strategy

Unit Tests

  • Test get_capacity_details with a mock DB client returning known data for all three new fields → verify output contains expected sections and content.
  • Test empty-state: description=None, references=[], certificates=[] → verify "(keine)" placeholders appear.
  • Test edge case: reference with empty partner_name → verify only projects text is shown.
  • Test that capacity-not-found still returns the error message unchanged.

Property-Based Tests

Library: Hypothesis (Python)

Each property test runs a minimum of 100 iterations.

  • Property 1 test: Generate random capacity IDs and mock DB responses. Verify all three DB methods are called with the correct ID.

    • Tag: Feature: capacity-details-enrichment, Property 1: All enrichment data is fetched for any capacity
  • Property 2 test: Generate random non-empty descriptions (text strategy), random lists of CapacityReferenceRow dicts with non-empty projects and partner_name, and random lists of non-empty certificate strings. Call the formatting logic and assert all generated data appears in the output.

    • Tag: Feature: capacity-details-enrichment, Property 2: Non-empty data appears in output
  • Property 3 test: Generate random combinations of present/absent data (description: str|None, references: list of 0-5 items, certificates: list of 0-5 items). Call the formatting logic and assert section headers appear in the correct order with blank-line separation.

    • Tag: Feature: capacity-details-enrichment, Property 3: Section ordering is fixed

Test Configuration

  • Property-based testing library: hypothesis (already available in the project's test dependencies)
  • Minimum iterations: 100 per property (@settings(max_examples=100))
  • Each test tagged with a comment referencing the design property