feat: process_folder MCP tool for single-call folder workflows (v4.2.0)#60
Merged
Conversation
Adds automatic tracking of every Active Chamber Calibration run plus a GUI + MCP workflow for comparing any two runs. Built on the foundation restored in e142a8c so chamber/equipment drift (and methodology changes) are caught before they corrupt downstream measurements. Core (plot_antenna/cal_drift.py): - CalRunMeta: one row per TRP Cal file + SHA-256 of every input file + header-parsed signal source / receiver / output level from the HPol ref. - parse_trp_cal_file / parse_cal_file_header / parse_ref_file_header / parse_cal_summary_file reuse the "Test Frequency" header-scan pattern. - history_dir() resolves env RFLECT_CAL_DRIFT_DIR > user_settings.json > platform default (~/.config/RFlect/cal_drift on Linux). - record_run() is idempotent on output_sha256; list_runs / load_points / get_run / update_notes / set_setup_group / delete_run round-trip CSV. - import_historical_dir() walks a directory tree, pairs each TRP Cal file with its sibling summary, and falls back to antenna/band-aware scanning so BLPA cals never get matched with the HORN gain standard that sits in the same folder. - compute_drift() outer-joins baseline vs current on frequency, returns per-pol stats (mean/std/max|Δ|/pct>0.5dB/pct>1dB), a method-consistency map, and a missing-frequency audit. Cross-setup_group comparisons are flagged on the consistency tab. - render_delta_plot() / export_markdown() / export_pdf() produce the two-panel freq-vs-ΔdB view and printable reports. Auto-capture (plot_antenna/file_utils.py): - generate_active_cal_file() appends to the drift log right before return. Failures are logged and swallowed — drift recording never breaks cal generation. Batch and MCP callers are covered since the hook lives in the library, not the GUI. GUI (plot_antenna/gui/cal_drift_dialog.py + main_window.py + tools_mixin.py): - New "Tools -> Calibration Drift History..." opens a three-pane dialog: runs tree (grouped antenna / band / date) on the left, metric notebook (summary stats, consistency, missing-freq audit, raw deltas) in the middle, matplotlib plot + PNG/PDF/Markdown export on the right. - Right-click menu: Set as Baseline, Set as Current, Edit setup group, Edit notes, Delete run. - [Import Historical...] button ingests the user's Downloads archive in one click; [Change History Folder...] persists a custom path. MCP (rflect-mcp/tools/cal_drift_tools.py): - Eight tools: cal_drift_ingest, cal_drift_list_runs, cal_drift_compare, cal_drift_report, cal_drift_history_dir, cal_drift_set_history_dir, cal_drift_set_setup_group, cal_drift_set_notes. All delegate to the core library so GUI and MCP share identical logic. Testing (tests/test_cal_drift.py + conftest.py + fixtures): - 20 tests covering parse / record idempotency / cross-epoch consistency / missing-freq audit / historical import / exports. - tests/conftest.py autouse fixture routes RFLECT_CAL_DRIFT_DIR at a per-session tmp dir so the auto-capture hook never pollutes a user's real history during testing. - Synthetic fixtures under tests/fixtures/cal_drift/ keep CI free of any ~/Downloads dependency. End-to-end test with real 2026-04-14 samples is guarded by the same skip-if-missing pattern as test_active_calibration.py. Verified against the user's ~/Downloads/Calibration Data archive: 12 historical runs (2023-06, 2024-08, 2024-11, 2026-04 x BLPA 690-2700 / BLPA 4800-6000 / HORN 5850-8200-or-8250) ingested cleanly. BLPA 690-2700 drift 2024 -> 2026 is <0.65 dB and 0% of points over 1 dB; BLPA 4800-6000 drift in the same window is max 4.97 dB and 99% of points over 1 dB — the tracker immediately surfaced a methodology/hardware issue on the 5 GHz path that was not obvious from any single run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add `process_folder(folder_path, intent, report, freqs, report_path)` so MCP clients (Claude, Cline, etc.) can run a standard RFlect procedure on a directory with one call instead of chaining list_measurement_files → bulk_process_* → analyze → generate_report. - Intent auto-detection scans for cal-drift, passive HPOL/VPOL pairs, active TRP files, and UWB S-parameter sweeps. Priority on tie: cal_drift > passive > active > uwb; mixed folders surface a warning. - Delegates to existing batch helpers (no duplicated logic). UWB analysis body extracted from analyze_uwb_channel into _analyze_uwb_channel_dict so both the existing MCP tool and process_folder share it. - Never raises — folder-missing, no-match, partial pairs, per-file UWB errors, and report write failures all return as structured warnings[]. - Bumps version 4.1.9 → 4.2.0 and adds RELEASE_NOTES entry. Tests: 9 new tests in tests/test_mcp_process_folder.py (intent detection, mixed-intent priority, explicit intents with monkey-patched delegates, real-delegate cal-drift end-to-end, report-failure isolation). Full MCP regression suite (133 tests) still passes; 74 skips are the chamber-data tests that need the local TestFiles directory and remain unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
Apply Black 24 formatting to plot_antenna/. The Black CI step in tests.yml was failing on Python 3.11 because cal_drift.py and several GUI mixins introduced via eed9c5a had not been formatted. No behavior change. Black config: line-length 100, target-version py311. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The selection-combining test asserted `combined == 5.0` exactly, which fails as `4.999999999999999 == 5.0` on some numpy/Python builds (notably ubuntu CI under Python 3.12) because combining_gain() roundtrips through a linear → dB conversion. Use pytest.approx(5.0, abs=1e-9) so the assertion is robust to last-bit float rounding without weakening the contract. Pre-existing failure surfaced now because the cal_drift commit (eed9c5a) that PR #60 carries forward had never been pushed to origin before, so CI on this PR is the first run that hits this code on Python 3.12. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
process_folder(folder_path, intent, report, freqs, report_path)— a single MCP entry point that scans a directory, picks the right RFlect workflow (passive HPOL/VPOL pair, active TRP, cal-drift archive, or UWB sweep), runs it, and optionally produces a DOCX report.Replaces the previous
list → bulk → analyze → reportchain that MCP clients (Claude Code, Cline, …) had to script manually:What changed
rflect-mcp/tools/orchestration.py—register_orchestration_tools(mcp)exposingprocess_folder. Auto-detect priority:cal_drift > passive > active > uwb. Mixed folders proceed with the winner and surface amixed_intents_detectedwarning.rflect-mcp/tools/uwb_tools.py— analyze body extracted to_analyze_uwb_channel_dict()so both the existinganalyze_uwb_channelMCP tool and the new orchestrator share it.rflect-mcp/server.py— registered, help-text extended.tests/test_mcp_process_folder.py— 9 new tests covering folder-missing, invalid-intent, no-match, mixed-intent priority, explicit passive/active/uwb (monkey-patched delegates), real-delegate cal-drift end-to-end with fixtures, report-failure isolation.pyproject.toml,plot_antenna/__init__.py,README.md,installer.iss,settings.json,.bumpversion.cfg. RELEASE_NOTES entry added.Behavior contract
warnings[]entries._measurements_lock; delegates that do (e.g.,get_loaded_measurements()) take it briefly and release.Test plan
pytest tests/test_mcp_process_folder.py -v— 9/9 passpytest tests/test_mcp_integration.py tests/test_mcp_tools.py tests/test_mcp_report.py tests/test_uwb_analysis.py tests/test_uwb_real_data.py tests/test_cal_drift.py— 133 passed, 74 skipped (skips are chamber-data tests unchanged from baseline)process_folderpresent🤖 Generated with Claude Code