Implements the full BRIDGE-WP-0003 workplan: 188 tests passing, 0 lint errors. ## What's added **Capability registry** (`src/bridge/capabilities.py`): - 10 capabilities with required_access_modes (cli/mcp/skill) - Single source of truth for what OpsBridge does and where **MCP server** (`src/bridge/mcp_server/server.py`): - 10 FastMCP tools: bridge_up/down/restart/status/logs + 5 catalog_* tools - 3 resources: bridge://status, catalog://domains, catalog://targets - `.mcp.json` for project-scope auto-registration - `scripts/register_mcp.py` for user-scope machine-global registration **Skill** (`~/.claude/plugins/ops-bridge/bridge-status.md`): - /bridge-status: health table with emoji indicators + remediation advice **Cross-mode test coverage enforcement**: - `tests/conftest.py`: capability/access_mode marks + collect_capability_coverage() - `tests/test_mcp.py`: 31 FastMCP in-process client tests (Client(mcp) pattern) - `tests/test_skill.py`: static skill lint against capability registry - `tests/test_coverage_completeness.py`: meta-test that fails if any required (capability × mode) pair lacks a test; also validates CLI commands and MCP tools are registered in the capability registry **ADR** (`architecture/adr-001-cross-mode-capability-registry.md`): - Documents the registry pattern and FastMCP 3.x testing approach Key implementation note: FastMCP 3.x in-process results are in result.content[0].text (JSON string), not result.data directly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2.3 KiB
id, title, status, date
| id | title | status | date |
|---|---|---|---|
| ADR-001 | Cross-Mode Capability Registry and Coverage Enforcement | accepted | 2026-03-12 |
Context
OpsBridge exposes its operations through three access modes: CLI (bridge CLI), MCP server
(FastMCP stdio), and Skills (Claude plugin prompts). As the capability surface grows, there is
no guarantee that a new capability will be implemented consistently across all required modes,
or that tests exist for each mode.
Decision
Introduce a canonical Capability Registry (src/bridge/capabilities.py) that:
- Lists every operation as a
Capability(name, description, required_access_modes)dataclass. - Declares which access modes each capability must support.
- Is imported by the cross-mode meta-test to enforce complete test coverage.
Test coverage enforcement
Pytest marks @pytest.mark.capability(name) and @pytest.mark.access_mode(mode) are placed
on the canonical test for each (capability, mode) pair. tests/test_coverage_completeness.py
collects these marks at session scope and fails if any pair required by the registry has no
corresponding test.
FastMCP in-process testing
MCP tools are tested in tests/test_mcp.py using fastmcp.Client(mcp_app) — an in-process
client that calls tools without spawning a subprocess or opening a network socket. This is the
preferred approach because:
- Tests run in the same process as the server code, so patches/mocks work normally.
- No port allocation, no cleanup, no flakiness from network timeouts.
- FastMCP 3.x returns results via
result.content[0].text(JSON string) for non-empty responses, andresult.data(empty list/dict) when the return value is empty.
Skill static lint
tests/test_skill.py validates skill Markdown files in ~/.claude/plugins/ops-bridge/:
- Required frontmatter:
name,description. - Body must reference at least one registered capability name.
- The
bridge_statusskill must referencebridge_statusand the registry must declareskillas a required mode for that capability.
Consequences
- Every new capability must be added to the registry before or alongside its implementation.
- Every new (capability, mode) pair requires a marked test or the meta-test fails.
- The registry is the single source of truth for "what does OpsBridge do and where".
- Skills must reference capability names by their canonical registry IDs.