Files
Orchestrator/bahn/teamlandkarte-mcp/openspec/changes/add-capacity-to-task-matching-tools/tasks.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

150 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks: Add capacity→task matching tools and embedding-based inference
> Change: `add-capacity-to-task-matching-tools`
>
> Status: **Implemented**
## Phase 1: Requirements + Configuration decisions
- [x] 1.1 Define `list_free_capacities` ordering precisely:
- order by most recent `creation_date` (descending)
- [x] 1.2 Confirm “Owner/Team” display:
- use `owner_name` (contains the team name)
- [x] 1.3 Introduce a new role inference tool and remove the old:
- add `infer_primary_role(task_id? | task_text?)` that returns the single closest role as a Markdown table with `Role | Similarity` columns
- remove `infer_roles(...)` MCP tool completely (no deprecation period)
- remove `TaskAnalyzer.extract_ranked_roles()` method completely
- update `extract_requirements()` and other callers to use new primary-role inference
- [x] 1.4 Add configuration for competence inference:
- `matching.inference.max_competences` (int, default: 8; if not specified, no limit)
- `matching.inference.min_similarity` (float in [0,1], default: 0.4; if not specified, no threshold)
- at least one parameter MUST be specified to avoid unbounded results
- selection rule: pick top X among those >= threshold when both are set
- [x] 1.5 Define startup-only refresh behavior:
- on startup embed only cache-missing role/competence vocab entries
- on startup embed **all open tasks** (title+description by task_id)
- at runtime still embed on-demand for misses (strict failure semantics)
## Phase 2: Data Lake queries (roles, competences, capacities)
- [x] 2.0 Verify Data Lake schema:
- confirm `teamlandkarte_v_capacity_roles_latest` has columns: `name`, `active`, `staffing_board_relevant`
- confirm capacities view has `creation_date` column
- [x] 2.1 Add `TrinoClient.get_recent_free_capacities(limit)` query returning:
- `capacity_id`, `owner_name` (team), `role_name`, `creation_date`, `begin_date`, `end_date`, `competences[]`
- ordering: `creation_date DESC`
- [x] 2.2 Add `TrinoClient.get_capacity_by_id(capacity_id)` query returning the same fields.
- [x] 2.3 Add `TrinoClient.get_all_role_names()`:
- source: `teamlandkarte_v_capacity_roles_latest`
- filter: `active=true AND staffing_board_relevant=true`
- return unique, non-empty role names
- [x] 2.4 Add `TrinoClient.get_all_competence_names()`:
- source: `beschaffungstool_kmp_skill_latest.skillname__c`
- return unique, non-empty competence names
- [x] 2.5 Add unit tests for SQL read-only guard + query shape (where applicable).
## Phase 3: Startup embedding preload (vocabularies + tasks)
- [x] 3.1 Define stable cache-key scheme (explicit format as documented in design.md):
- role vocab entries: `f"role_vocab:{model}:{dims}:{normalized_role_name}"`
- competence vocab entries: `f"comp_vocab:{model}:{dims}:{normalized_competence_name}"`
- task text embeddings by task_id: `f"task_id:{model}:{dims}:{task_id}"`
- [x] 3.2 Implement `VocabularyCache` component (`src/teamlandkarte_mcp/matching/vocabulary.py`):
- fetch role vocabulary + competence vocabulary from Trino
- normalize/deduplicate
- embed only cache-missing entries (batch + chunking via `SimilarityEngine.prefetch_embeddings(...)`)
- store into SQLite embedding cache
- keep in-memory memoization for fast repeated inference
- invoked from `build_server()` after DB + similarity engine init
- [x] 3.3 Implement a “task embedding preload” routine executed on startup:
- fetch **all open tasks** (no limit)
- build `task_text = title + "\n\n" + description` (title optional)
- embed only cache-missing `task_id` vectors
- store into SQLite embedding cache
- [x] 3.4 Runtime fallback:
- if a role/competence/task embedding is missing during a tool call, embed on-demand (strict semantics)
- [x] 3.5 Tests:
- preload embeds only cache misses
- preload writes to SQLite
- missing-at-runtime triggers on-demand embedding
## Phase 4: Embedding-only inference (roles + competences)
- [x] 4.1 Implement primary role inference against role vocabulary:
- input: combined `title+description` (or description-only for ad-hoc)
- output: single closest role with similarity score as Markdown table: `Role | Similarity`
- [x] 4.2 Add a new MCP tool:
- `infer_primary_role(task_id? | task_text?)`
- returns: Markdown table `Role | Similarity` (single best matching role)
- validation: exactly one of `task_id` or `task_text` must be provided
- [x] 4.3 Remove deprecated tools and methods:
- remove `infer_roles(...)` MCP tool completely
- remove `TaskAnalyzer.extract_ranked_roles()` method completely
- [x] 4.4 Update callers to use new primary-role inference:
- update `get_task_details` to use `infer_primary_role`
- update `extract_requirements()` to use new primary-role inference
- update any internal helpers relying on `TaskAnalyzer.extract_ranked_roles()`
## Phase 5: Rework task validation (embedding-only)
- [x] 5.1 Replace chat-based extraction in `validate_task_requirements` / `extract_requirements_from_task` with embedding-based inference:
- roles: infer primary role via role vocabulary (Markdown table output)
- competences: infer competences via competence vocabulary with max X and threshold (Markdown table output)
- [x] 5.2 Update output format:
- keep current table-first display
- add inferred primary role as Markdown table: `Role | Similarity` (single row)
- add inferred competences as Markdown table: `Competence | Similarity` (descending order by similarity)
- [x] 5.3 Tests:
- validation uses embeddings path only (no chat calls)
- respects max X and threshold rules
- output includes role and competence similarity tables
## Phase 6: New MCP tools (capacity browsing + capacity→task matching)
- [x] 6.1 Implement `list_free_capacities(limit=20)`:
- ordering: `creation_date DESC`
- Markdown table columns: `capacity_id`, `Owner/Team`, `Role`, `Competences`, `Availability`
- stable empty-table handling (dummy row)
- [x] 6.2 Implement `get_capacity_details(capacity_id)`:
- table-first, same fields as list
- include a “Next steps” pointer to `find_matching_tasks(capacity_id=...)`
- [x] 6.3 Implement `find_matching_tasks(capacity_id)`:
- signature: takes only `capacity_id` (no optional params)
- fetch capacity + all open tasks
- infer each tasks primary role via embedding similarity (title+description)
- infer each tasks competences via embedding similarity (title+description) with max/threshold
- compute a similarity score (role + competences) and categorize results
- return output as Markdown table with columns:
- `task_id`, `Title`, `Required Competences`, `Availability`, `Score`, `Category`
- results are sorted by similarity score (descending)
- output structure matches `find_matching_capacities` (includes summary counts table + results table for first non-empty category)
- paginated via same search session conventions used by `find_matching_capacities`
- [x] 6.4 Tests for new tools:
- `list_free_capacities`: ordering by `creation_date DESC`, empty-table handling
- `get_capacity_details`: not-found handling, "Next steps" section
- `find_matching_tasks`: categorization (Top/Good/Partial/Low), search session conventions, table structure, score sorting
## Phase 7: Remove Azure chat API
- [x] 7.1 Remove chat config fields and environment variables if no longer needed (`AZURE_OPENAI_LLM_API_KEY`, chat deployment, chat codepaths).
- [x] 7.2 Delete/retire chat client methods and `TaskAnalyzer` chat-based methods.
- [x] 7.3 Update docs to remove chat setup instructions.
- [x] 7.4 Ensure all gates pass (ruff/mypy/pytest).
## Phase 8: Documentation + assistant prompt + architecture
- [x] 8.1 Update `README.md`:
- describe new tools and capacity→task workflow
- document startup embedding preload and inference config knobs
- [x] 8.2 Update `docs/assistant_system_prompt.md`:
- add guidance for new tools and matching direction
- update role/competence inference description (embeddings-only)
- [x] 8.3 Update architecture docs (Arc42 / design docs):
- reflect removal of chat API
- describe vocab/task embedding preload and cache keys
## Phase 9: OpenSpec hygiene
- [x] 9.1 Update spec deltas to reflect confirmed tool shapes + config.
- [x] 9.2 Run `openspec validate add-capacity-to-task-matching-tools --strict`.