# TL DPS MCP Copilot Guide
- **Project Intent**: Parse Throne & Liberty combat logs into deterministic DPS/DPM summaries consumable by CLI, MCP tools, and the PySide6 desktop app.
- **Data Contract**: `server.analyze_logs` returns the canonical payload (`generated_at`, `source`, `runs`, `summary`) expected by the CLI, FastMCP tool, markdown reporter, and UI tables—keep field names/types stable.
- **Log Expectations**: Parser assumes UTF-8 `.txt`/`.log` rows shaped as `timestamp,event_type,skill,internal_id,damage,crit_flag,heavy_flag,hit_type,source,target`; unexpected column counts are skipped, not fatal.
- **Run Filtering**: Only `DamageDone` rows with `damage > 0` contribute to DPS math; maintain `_safe_duration` fallback to `1.0` seconds to avoid divide-by-zero regressions.
- **Rounding**: Metrics are rounded to three decimals (`dps`, `dpm`, `%` helpers) to match validation scripts and sample reports.
## Analyzer Stack
- **Parser (`dps_logs/parser.py`)**: `load_runs` yields `(run_id, events)` covering single files or newest `limit_runs` in a directory; reuse its iterator instead of reimplementing file discovery.
- **Metrics (`dps_logs/metrics.py`)**: `summarize_run` shapes per-run dictionaries; `build_summary` merges runs and mirrors `top_skills` into `top_skills_by_damage` for downstream consumers—extend both when adding new stats.
- **Reporting (`dps_logs/reporting.py`)**: Markdown builder expects the same payload shape and recomputes means/medians; update helper tables when payload fields change.
- **CLI (`server.py`)**: Treat `analyze_logs` as pure; CLI glue handles argparse, pretty-printing, and optional file mirrors via `_write_text`.
- **MCP (`mcp_server.py`)**: FastMCP exposes `analyze_dps_logs` with identical argument semantics (`log_dir`, `limit_runs`); validation relies on parity with `analyze_logs`.
## Desktop App
- **Client (`app/mcp_client.py`)**: `MCPAnalyzerClient` shells out to `python -m mcp_server`; keep stdout JSON-compatible so `_extract_payload` can parse either structured or text responses.
- **UI (`app/main.py`)**: `AnalysisWorker` runs analysis on a `QThread`; update `_update_summary`, `_update_runs_table`, `_update_skills_table` in lockstep with payload changes to avoid KeyErrors.
- **Constants (`app/constants.py`)**: Shared defaults live here (log dir autodetect, run limits, banner path, Python executable); adjust limits once so both UI and analyzers stay aligned.
- **Dependencies**: Install UI deps via `pip install -r app/requirements_app.txt` (PySide6 + `mcp[cli]`); runtime Python 3.11+.
## Developer Workflows
- **CLI Smoke**: `python -m server --sample --pretty` renders analyzer output using bundled `sample_data/example_log_01.txt`.
- **File Outputs**: Add `--output-json reports/sample.json --output-md reports/sample.md` when debugging report formatting.
- **Validation**: `python validate_output.py --sample` rechecks DPS ratios with configurable `--tolerance`; run after touching metrics math.
- **MCP Parity Test**: `python tests/smoke_mcp_tool.py --sample` ensures FastMCP responses normalize to CLI payload (ignores `generated_at`).
- **Desktop UI**: After installing requirements, launch with `python -m app.main`; the UI depends on the MCP server module being importable.
## Conventions & Tips
- **Imports**: Standard library first, then project modules (`from dps_logs...`), mirroring existing files.
- **Error Handling**: Raise `ValueError` for bad user inputs (`limit_runs <= 0`), and reuse existing validation patterns instead of silently clamping values.
- **Testing Data**: Keep `sample_data/example_log_01.txt` stable; reports under `reports/` illustrate expected formatting and are safe references for new features.
- **MCP Manifest**: `mcp.json` already points to `python -m mcp_server`; avoid hard-coding alternative paths so third-party MCP shells keep working.
- **Cross-Module Changes**: When adding new metrics, update `summarize_run`, `build_summary`, markdown tables, UI renderers, and smoke tests together to maintain parity across surfaces.