---
id: T01
parent: S02
milestone: M010
provides: []
requires: []
affects: []
key_files: ["backend/schemas.py", "backend/routers/techniques.py", "backend/tests/test_public_api.py"]
key_decisions: ["Python-side scoring instead of SQL for clarity and testability — dataset is small", "Curated join-table links take absolute priority; dynamic results fill remaining slots up to 4"]
patterns_established: []
drill_down_paths: []
observability_surfaces: []
duration: ""
verification_result: "Ran pytest with -k "technique_detail or dynamic_related" — all 6 tests pass including existing test_get_technique_detail (backward compat) and 4 new dynamic related tests."
completed_at: 2026-03-31T06:13:47.548Z
blocker_discovered: false
---

# T01: Added scored dynamic related-techniques query returning up to 4 ranked results with creator_name, topic_category, and reason fields

> Added scored dynamic related-techniques query returning up to 4 ranked results with creator_name, topic_category, and reason fields

## What Happened
---
id: T01
parent: S02
milestone: M010
key_files:
  - backend/schemas.py
  - backend/routers/techniques.py
  - backend/tests/test_public_api.py
key_decisions:
  - Python-side scoring instead of SQL for clarity and testability — dataset is small
  - Curated join-table links take absolute priority; dynamic results fill remaining slots up to 4
duration: ""
verification_result: passed
completed_at: 2026-03-31T06:13:47.548Z
blocker_discovered: false
---

# T01: Added scored dynamic related-techniques query returning up to 4 ranked results with creator_name, topic_category, and reason fields

**Added scored dynamic related-techniques query returning up to 4 ranked results with creator_name, topic_category, and reason fields**

## What Happened

Enriched RelatedLinkItem schema with creator_name, topic_category, and reason fields. Added _find_dynamic_related helper that loads candidates, scores them in Python (same creator+category: 3, same creator: 2, same category: 2, +1 per shared tag), returns top N enriched results. Curated join-table links take priority; dynamic fills remaining slots up to 4. Dynamic query failure is non-blocking (logs WARNING). Wrote 4 integration tests covering ranking, self-exclusion, no-peers, and NULL tags.

## Verification

Ran pytest with -k "technique_detail or dynamic_related" — all 6 tests pass including existing test_get_technique_detail (backward compat) and 4 new dynamic related tests.

## Verification Evidence

| # | Command | Exit Code | Verdict | Duration |
|---|---------|-----------|---------|----------|
| 1 | `cd backend && python -m pytest tests/test_public_api.py -v -k 'technique_detail or dynamic_related'` | 0 | ✅ pass | 2830ms |


## Deviations

None.

## Known Issues

Pre-existing test failures in topics (7 vs 6 categories) and creators (response shape mismatch) are unrelated to this task.

## Files Created/Modified

- `backend/schemas.py`
- `backend/routers/techniques.py`
- `backend/tests/test_public_api.py`


## Deviations
None.

## Known Issues
Pre-existing test failures in topics (7 vs 6 categories) and creators (response shape mismatch) are unrelated to this task.
