From 3be41c315ec63da6e0b0dbb4982c9f2cbf4c4180 Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 12 Mar 2026 21:19:58 +0100 Subject: [PATCH] test(BRIDGE-WP-0003): add sentinel self-validation for meta-test + MCP section in README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add test_meta_test_catches_missing_mode_gap() — validates Goal #4: injects _test_sentinel capability (cli+mcp required), provides only a cli mock item, asserts collect_capability_coverage reports the mcp gap. Proves the cross-mode gap-detection mechanism is functional. - Add MCP INTEGRATION section to README.txt (T14 requirement): documents project-scope .mcp.json, user-scope registration script, skill, and direct server invocation. 189 tests, 0 lint errors. Co-Authored-By: Claude Sonnet 4.6 --- README.txt | 28 +++++++++++ tests/test_coverage_completeness.py | 72 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/README.txt b/README.txt index 5445989..4db40ee 100644 --- a/README.txt +++ b/README.txt @@ -181,6 +181,34 @@ bridge_reconnecting, health_check_failed, health_check_recovered, bridge_stopped +MCP INTEGRATION +--------------- + +OpsBridge exposes its capabilities as a FastMCP server so Claude Code agents +can call bridge_up(), bridge_status(), catalog_list_targets(), etc. as +first-class MCP tools — no Bash required, structured JSON in/out. + +Available tools: bridge_up, bridge_down, bridge_restart, bridge_status, + bridge_logs, catalog_list_targets, catalog_show_target, + catalog_list_domains, catalog_validate, catalog_show_bridge + +Available resources: bridge://status, catalog://domains, catalog://targets + +Project-scope (auto, inside ops-bridge/): + Already configured in .mcp.json. Claude Code sessions inside this repo + see the tools automatically. + +User-scope (machine-global, any repo): + python scripts/register_mcp.py + +Human operator skill: + /bridge-status — natural-language tunnel health summary + (skill file: ~/.claude/plugins/ops-bridge/bridge-status.md) + +Run the server directly (for debugging): + uv run python src/bridge/mcp_server/server.py + + DEVELOPMENT ----------- diff --git a/tests/test_coverage_completeness.py b/tests/test_coverage_completeness.py index fd52927..91e66a9 100644 --- a/tests/test_coverage_completeness.py +++ b/tests/test_coverage_completeness.py @@ -134,6 +134,78 @@ async def test_mcp_tools_in_registry(): ) +# --------------------------------------------------------------------------- +# T12 — Self-validation: sentinel fixture proves the gap-checker catches gaps +# --------------------------------------------------------------------------- + +def test_meta_test_catches_missing_mode_gap(): + """Self-validation: the coverage checker must detect a missing-mode gap. + + Injects a synthetic _test_sentinel capability requiring both cli and mcp. + Creates mock items with *only* a cli test for it (deliberately omitting mcp). + Asserts that collect_capability_coverage reports the mcp gap — proving the + meta-test mechanism is functional, not a silent no-op. + + This test validates Goal #4 from BRIDGE-WP-0003: + "The gap-detection mechanism is itself tested: a synthetic missing-mode + fixture asserts the meta-test catches it." + """ + from bridge.capabilities import Capability + + sentinel = Capability( + name="_test_sentinel", + description="Synthetic capability for meta-test self-validation", + required_access_modes=frozenset({"cli", "mcp"}), + ) + patched_caps = CAPABILITIES + [sentinel] + + # Minimal mock: an iterable of items that respond to iter_markers() + class _Mark: + def __init__(self, arg: str): + self.args = (arg,) + + class _MockItem: + def __init__(self, capability: str, mode: str): + self._cap = capability + self._mode = mode + + def iter_markers(self, name: str): + if name == "capability": + return [_Mark(self._cap)] + if name == "access_mode": + return [_Mark(self._mode)] + return [] + + # Only supply a cli test for the sentinel — the mcp test is intentionally absent + mock_items = [_MockItem("_test_sentinel", "cli")] + + covered = collect_capability_coverage(mock_items) + + # The cli mode should be registered + assert ("_test_sentinel", "cli") in covered, ( + "collect_capability_coverage failed to record the cli mock item" + ) + # The mcp mode must NOT be covered — this is the gap we want to catch + assert ("_test_sentinel", "mcp") not in covered, ( + "collect_capability_coverage incorrectly registered an mcp test that was not provided" + ) + + # Run the same gap-detection logic used by test_all_required_modes_have_tests + gaps = [ + (cap.name, mode) + for cap in patched_caps + for mode in cap.required_access_modes + if (cap.name, mode) not in covered + ] + + assert ("_test_sentinel", "mcp") in gaps, ( + "Gap checker failed to detect the missing mcp mode for _test_sentinel. " + "The meta-test mechanism is broken." + ) + # Sanity: cli mode should NOT appear as a gap (it was covered) + assert ("_test_sentinel", "cli") not in gaps + + def test_no_orphan_capability_marks(capability_coverage): """Every (capability, mode) pair in the test suite must exist in the registry.