From 2925ec4229fa3bfb85f07e262f4811ba7617f173 Mon Sep 17 00:00:00 2001 From: lmiranda Date: Mon, 2 Feb 2026 11:24:51 -0500 Subject: [PATCH] feat(contract-validator): add validate_workflow_integration tool (v5.7.1) Domain Advisory Pattern Hardening - patch release to close gaps from v5.6.0/v5.7.0: ## Added - New `validate_workflow_integration` MCP tool validates domain plugins expose required advisory interfaces (gate command, review command, advisory agent) - New `MISSING_INTEGRATION` issue type for workflow integration validation - New `WorkflowIntegrationResult` Pydantic model for structured validation output - `integrates_with` field on viz-platform and data-platform in marketplace.json declaring projman integration metadata - 4 new test cases for workflow integration validation ## Fixed - scripts/setup.sh banner version updated from v5.1.0 to v5.7.1 ## Documentation - Updated mcp-tools-reference.md with new tool - Updated validation-rules.md with Workflow Integration Checks section - Added /design-gate, /design-review, /data-gate, /data-review to COMMANDS-CHEATSHEET - Added contract-validator to CONFIGURATION.md plugin table - Updated README.md Contract Validator tools table Co-Authored-By: Claude Opus 4.5 --- .claude-plugin/marketplace.json | 22 ++- CHANGELOG.md | 12 ++ README.md | 4 +- docs/COMMANDS-CHEATSHEET.md | 6 +- docs/CONFIGURATION.md | 1 + .../contract-validator/mcp_server/server.py | 24 +++ .../mcp_server/validation_tools.py | 116 ++++++++++++++ .../tests/test_validation_tools.py | 150 ++++++++++++++++++ .../commands/validate-contracts.md | 1 + .../skills/mcp-tools-reference.md | 8 + .../skills/validation-rules.md | 10 ++ scripts/setup.sh | 2 +- 12 files changed, 349 insertions(+), 7 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 246fc9b..08cfe5a 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -6,7 +6,7 @@ }, "metadata": { "description": "Project management plugins with Gitea and NetBox integrations", - "version": "5.7.0" + "version": "5.7.1" }, "plugins": [ { @@ -167,7 +167,15 @@ "hooks": ["./hooks/hooks.json"], "category": "data", "tags": ["pandas", "postgresql", "postgis", "dbt", "data-engineering", "etl"], - "license": "MIT" + "license": "MIT", + "integrates_with": { + "projman": { + "domain_label": "Domain/Data", + "gate_command": "/data-gate", + "review_command": "/data-review", + "advisory_agent": "data-advisor" + } + } }, { "name": "viz-platform", @@ -183,7 +191,15 @@ "hooks": ["./hooks/hooks.json"], "category": "visualization", "tags": ["dash", "plotly", "mantine", "charts", "dashboards", "theming", "dmc"], - "license": "MIT" + "license": "MIT", + "integrates_with": { + "projman": { + "domain_label": "Domain/Viz", + "gate_command": "/design-gate", + "review_command": "/design-review", + "advisory_agent": "design-reviewer" + } + } }, { "name": "contract-validator", diff --git a/CHANGELOG.md b/CHANGELOG.md index 994769f..99fb7c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to the Leo Claude Marketplace will be documented in this fil The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [5.7.1] - 2026-02-02 + +### Added +- **contract-validator**: New `validate_workflow_integration` MCP tool — validates domain plugins expose required advisory interfaces (gate command, review command, advisory agent) +- **contract-validator**: New `MISSING_INTEGRATION` issue type for workflow integration validation +- **marketplace.json**: `integrates_with` field on viz-platform and data-platform declaring projman integration metadata + +### Fixed +- `scripts/setup.sh` banner version updated from v5.1.0 to v5.7.1 + +--- + ## [5.7.0] - 2026-02-02 ### Added diff --git a/README.md b/README.md index 422d247..0e1bdd0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Leo Claude Marketplace - v5.7.0 +# Leo Claude Marketplace - v5.7.1 A collection of Claude Code plugins for project management, infrastructure automation, and development workflows. @@ -215,7 +215,7 @@ Cross-plugin compatibility validation tools. | Category | Tools | |----------|-------| | Parse | `parse_plugin_interface`, `parse_claude_md_agents` | -| Validation | `validate_compatibility`, `validate_agent_refs`, `validate_data_flow` | +| Validation | `validate_compatibility`, `validate_agent_refs`, `validate_data_flow`, `validate_workflow_integration` | | Report | `generate_compatibility_report`, `list_issues` | ## Installation diff --git a/docs/COMMANDS-CHEATSHEET.md b/docs/COMMANDS-CHEATSHEET.md index 8f2b09e..e3c706d 100644 --- a/docs/COMMANDS-CHEATSHEET.md +++ b/docs/COMMANDS-CHEATSHEET.md @@ -92,7 +92,11 @@ Quick reference for all commands in the Leo Claude Marketplace. | **viz-platform** | `/chart-export` | | X | Export charts to PNG, SVG, PDF via kaleido | | **viz-platform** | `/accessibility-check` | | X | Color blind validation (WCAG contrast ratios) | | **viz-platform** | `/breakpoints` | | X | Configure responsive layout breakpoints | +| **viz-platform** | `/design-review` | | X | Detailed design system audits | +| **viz-platform** | `/design-gate` | | X | Binary pass/fail design system validation gates | | **viz-platform** | *SessionStart hook* | X | | Checks DMC version (non-blocking warning) | +| **data-platform** | `/data-review` | | X | Comprehensive data integrity audits | +| **data-platform** | `/data-gate` | | X | Binary pass/fail data integrity gates | | **contract-validator** | `/validate-contracts` | | X | Full marketplace compatibility validation | | **contract-validator** | `/check-agent` | | X | Validate single agent definition | | **contract-validator** | `/list-interfaces` | | X | Show all plugin interfaces | @@ -294,4 +298,4 @@ Ensure credentials are configured in `~/.config/claude/gitea.env`, `~/.config/cl --- -*Last Updated: 2026-01-30* +*Last Updated: 2026-02-02* diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index e2dac12..51b9201 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -398,6 +398,7 @@ PR_REVIEW_AUTO_SUBMIT=false | **code-sentinel** | None | None | None needed | | **project-hygiene** | None | None | None needed | | **claude-config-maintainer** | None | None | None needed | +| **contract-validator** | None | None | `/initial-setup` | --- diff --git a/mcp-servers/contract-validator/mcp_server/server.py b/mcp-servers/contract-validator/mcp_server/server.py index bbed603..3891576 100644 --- a/mcp-servers/contract-validator/mcp_server/server.py +++ b/mcp-servers/contract-validator/mcp_server/server.py @@ -131,6 +131,24 @@ class ContractValidatorMCPServer: "required": ["agent_name", "claude_md_path"] } ), + Tool( + name="validate_workflow_integration", + description="Validate that a domain plugin exposes the required advisory interfaces (gate command, review command, advisory agent) expected by projman's domain-consultation skill", + inputSchema={ + "type": "object", + "properties": { + "plugin_path": { + "type": "string", + "description": "Path to the domain plugin directory" + }, + "domain_label": { + "type": "string", + "description": "The Domain/* label it claims to handle, e.g. Domain/Viz" + } + }, + "required": ["plugin_path", "domain_label"] + } + ), # Report tools (to be implemented in #188) Tool( name="generate_compatibility_report", @@ -198,6 +216,8 @@ class ContractValidatorMCPServer: result = await self._validate_agent_refs(**arguments) elif name == "validate_data_flow": result = await self._validate_data_flow(**arguments) + elif name == "validate_workflow_integration": + result = await self._validate_workflow_integration(**arguments) elif name == "generate_compatibility_report": result = await self._generate_compatibility_report(**arguments) elif name == "list_issues": @@ -241,6 +261,10 @@ class ContractValidatorMCPServer: """Validate agent data flow""" return await self.validation_tools.validate_data_flow(agent_name, claude_md_path) + async def _validate_workflow_integration(self, plugin_path: str, domain_label: str) -> dict: + """Validate domain plugin exposes required advisory interfaces""" + return await self.validation_tools.validate_workflow_integration(plugin_path, domain_label) + # Report tool implementations (Issue #188) async def _generate_compatibility_report(self, marketplace_path: str, format: str = "markdown") -> dict: diff --git a/mcp-servers/contract-validator/mcp_server/validation_tools.py b/mcp-servers/contract-validator/mcp_server/validation_tools.py index 47a8468..1aa550a 100644 --- a/mcp-servers/contract-validator/mcp_server/validation_tools.py +++ b/mcp-servers/contract-validator/mcp_server/validation_tools.py @@ -26,6 +26,7 @@ class IssueType(str, Enum): OPTIONAL_DEPENDENCY = "optional_dependency" UNDECLARED_OUTPUT = "undeclared_output" INVALID_SEQUENCE = "invalid_sequence" + MISSING_INTEGRATION = "missing_integration" class ValidationIssue(BaseModel): @@ -65,6 +66,17 @@ class DataFlowResult(BaseModel): issues: list[ValidationIssue] = [] +class WorkflowIntegrationResult(BaseModel): + """Result of workflow integration validation for domain plugins""" + plugin_name: str + domain_label: str + valid: bool + gate_command_found: bool + review_command_found: bool + advisory_agent_found: bool + issues: list[ValidationIssue] = [] + + class ValidationTools: """Tools for validating plugin compatibility and agent references""" @@ -336,3 +348,107 @@ class ValidationTools: ) return result.model_dump() + + async def validate_workflow_integration(self, plugin_path: str, domain_label: str) -> dict: + """ + Validate that a domain plugin exposes required advisory interfaces. + + Checks for: + - Gate command (e.g., /design-gate, /data-gate) - REQUIRED + - Review command (e.g., /design-review, /data-review) - recommended + - Advisory agent referencing the domain label - recommended + + Args: + plugin_path: Path to the domain plugin directory + domain_label: The Domain/* label it claims to handle (e.g., Domain/Viz) + + Returns: + Validation result with found interfaces and issues + """ + plugin_path_obj = Path(plugin_path) + issues = [] + + # Extract plugin name from path + plugin_name = plugin_path_obj.name + if not plugin_path_obj.exists(): + return { + "error": f"Plugin directory not found: {plugin_path}", + "plugin_path": plugin_path, + "domain_label": domain_label + } + + # Extract domain short name from label (e.g., "Domain/Viz" -> "viz", "Domain/Data" -> "data") + domain_short = domain_label.split("/")[-1].lower() if "/" in domain_label else domain_label.lower() + + # Check for gate command + commands_dir = plugin_path_obj / "commands" + gate_command_found = False + gate_patterns = ["pass", "fail", "PASS", "FAIL", "Binary pass/fail", "gate"] + + if commands_dir.exists(): + for cmd_file in commands_dir.glob("*.md"): + if "gate" in cmd_file.name.lower(): + # Verify it's actually a gate command by checking content + content = cmd_file.read_text() + if any(pattern in content for pattern in gate_patterns): + gate_command_found = True + break + + if not gate_command_found: + issues.append(ValidationIssue( + severity=IssueSeverity.ERROR, + issue_type=IssueType.MISSING_INTEGRATION, + message=f"Plugin '{plugin_name}' lacks a gate command for domain '{domain_label}'", + location=str(commands_dir), + suggestion=f"Create commands/{domain_short}-gate.md with binary PASS/FAIL output" + )) + + # Check for review command + review_command_found = False + if commands_dir.exists(): + for cmd_file in commands_dir.glob("*.md"): + if "review" in cmd_file.name.lower() and "gate" not in cmd_file.name.lower(): + review_command_found = True + break + + if not review_command_found: + issues.append(ValidationIssue( + severity=IssueSeverity.WARNING, + issue_type=IssueType.MISSING_INTEGRATION, + message=f"Plugin '{plugin_name}' lacks a review command for domain '{domain_label}'", + location=str(commands_dir), + suggestion=f"Create commands/{domain_short}-review.md for detailed audits" + )) + + # Check for advisory agent + agents_dir = plugin_path_obj / "agents" + advisory_agent_found = False + + if agents_dir.exists(): + for agent_file in agents_dir.glob("*.md"): + content = agent_file.read_text() + # Check if agent references the domain label or gate command + if domain_label in content or f"{domain_short}-gate" in content.lower() or "advisor" in agent_file.name.lower() or "reviewer" in agent_file.name.lower(): + advisory_agent_found = True + break + + if not advisory_agent_found: + issues.append(ValidationIssue( + severity=IssueSeverity.WARNING, + issue_type=IssueType.MISSING_INTEGRATION, + message=f"Plugin '{plugin_name}' lacks an advisory agent for domain '{domain_label}'", + location=str(agents_dir) if agents_dir.exists() else str(plugin_path_obj), + suggestion=f"Create agents/{domain_short}-advisor.md referencing '{domain_label}'" + )) + + result = WorkflowIntegrationResult( + plugin_name=plugin_name, + domain_label=domain_label, + valid=gate_command_found, # Only gate is required for validity + gate_command_found=gate_command_found, + review_command_found=review_command_found, + advisory_agent_found=advisory_agent_found, + issues=issues + ) + + return result.model_dump() diff --git a/mcp-servers/contract-validator/tests/test_validation_tools.py b/mcp-servers/contract-validator/tests/test_validation_tools.py index aaba6ce..2ebfacd 100644 --- a/mcp-servers/contract-validator/tests/test_validation_tools.py +++ b/mcp-servers/contract-validator/tests/test_validation_tools.py @@ -254,3 +254,153 @@ async def test_validate_data_flow_missing_producer(validation_tools, tmp_path): # Should have warning about missing producer warning_issues = [i for i in result["issues"] if i["severity"].value == "warning"] assert len(warning_issues) > 0 + + +# --- Workflow Integration Tests --- + +@pytest.fixture +def domain_plugin_complete(tmp_path): + """Create a complete domain plugin with gate, review, and advisory agent""" + plugin_dir = tmp_path / "viz-platform" + plugin_dir.mkdir() + (plugin_dir / ".claude-plugin").mkdir() + (plugin_dir / "commands").mkdir() + (plugin_dir / "agents").mkdir() + + # Gate command with PASS/FAIL pattern + gate_cmd = plugin_dir / "commands" / "design-gate.md" + gate_cmd.write_text("""# /design-gate + +Binary pass/fail validation gate for design system compliance. + +## Output + +- **PASS**: All design system checks passed +- **FAIL**: Design system violations detected +""") + + # Review command + review_cmd = plugin_dir / "commands" / "design-review.md" + review_cmd.write_text("""# /design-review + +Comprehensive design system audit. +""") + + # Advisory agent + agent = plugin_dir / "agents" / "design-reviewer.md" + agent.write_text("""# design-reviewer + +Design system compliance auditor. + +Handles issues with `Domain/Viz` label. +""") + + return str(plugin_dir) + + +@pytest.fixture +def domain_plugin_missing_gate(tmp_path): + """Create domain plugin with review and agent but no gate command""" + plugin_dir = tmp_path / "data-platform" + plugin_dir.mkdir() + (plugin_dir / ".claude-plugin").mkdir() + (plugin_dir / "commands").mkdir() + (plugin_dir / "agents").mkdir() + + # Review command (but no gate) + review_cmd = plugin_dir / "commands" / "data-review.md" + review_cmd.write_text("""# /data-review + +Data integrity audit. +""") + + # Advisory agent + agent = plugin_dir / "agents" / "data-advisor.md" + agent.write_text("""# data-advisor + +Data integrity advisor for Domain/Data issues. +""") + + return str(plugin_dir) + + +@pytest.fixture +def domain_plugin_minimal(tmp_path): + """Create minimal plugin with no commands or agents""" + plugin_dir = tmp_path / "minimal-plugin" + plugin_dir.mkdir() + (plugin_dir / ".claude-plugin").mkdir() + + readme = plugin_dir / "README.md" + readme.write_text("# Minimal Plugin\n\nNo commands or agents.") + + return str(plugin_dir) + + +@pytest.mark.asyncio +async def test_validate_workflow_integration_complete(validation_tools, domain_plugin_complete): + """Test complete domain plugin returns valid with all interfaces found""" + result = await validation_tools.validate_workflow_integration( + domain_plugin_complete, + "Domain/Viz" + ) + + assert "error" not in result + assert result["valid"] is True + assert result["gate_command_found"] is True + assert result["review_command_found"] is True + assert result["advisory_agent_found"] is True + assert len(result["issues"]) == 0 + + +@pytest.mark.asyncio +async def test_validate_workflow_integration_missing_gate(validation_tools, domain_plugin_missing_gate): + """Test plugin missing gate command returns invalid with ERROR""" + result = await validation_tools.validate_workflow_integration( + domain_plugin_missing_gate, + "Domain/Data" + ) + + assert "error" not in result + assert result["valid"] is False + assert result["gate_command_found"] is False + assert result["review_command_found"] is True + assert result["advisory_agent_found"] is True + + # Should have one ERROR for missing gate + error_issues = [i for i in result["issues"] if i["severity"].value == "error"] + assert len(error_issues) == 1 + assert "gate" in error_issues[0]["message"].lower() + + +@pytest.mark.asyncio +async def test_validate_workflow_integration_minimal(validation_tools, domain_plugin_minimal): + """Test minimal plugin returns invalid with multiple issues""" + result = await validation_tools.validate_workflow_integration( + domain_plugin_minimal, + "Domain/Test" + ) + + assert "error" not in result + assert result["valid"] is False + assert result["gate_command_found"] is False + assert result["review_command_found"] is False + assert result["advisory_agent_found"] is False + + # Should have one ERROR (gate) and two WARNINGs (review, agent) + error_issues = [i for i in result["issues"] if i["severity"].value == "error"] + warning_issues = [i for i in result["issues"] if i["severity"].value == "warning"] + assert len(error_issues) == 1 + assert len(warning_issues) == 2 + + +@pytest.mark.asyncio +async def test_validate_workflow_integration_nonexistent_plugin(validation_tools, tmp_path): + """Test error when plugin directory doesn't exist""" + result = await validation_tools.validate_workflow_integration( + str(tmp_path / "nonexistent"), + "Domain/Test" + ) + + assert "error" in result + assert "not found" in result["error"].lower() diff --git a/plugins/contract-validator/commands/validate-contracts.md b/plugins/contract-validator/commands/validate-contracts.md index e38d20c..1f01079 100644 --- a/plugins/contract-validator/commands/validate-contracts.md +++ b/plugins/contract-validator/commands/validate-contracts.md @@ -30,6 +30,7 @@ - Use `validate_compatibility` for pairwise checks - Use `validate_agent_refs` for CLAUDE.md agents - Use `validate_data_flow` for data sequences + - Use `validate_workflow_integration` for domain plugin advisory interfaces 5. **Generate report**: - Use `generate_compatibility_report` for full report diff --git a/plugins/contract-validator/skills/mcp-tools-reference.md b/plugins/contract-validator/skills/mcp-tools-reference.md index f621c35..1f36dd2 100644 --- a/plugins/contract-validator/skills/mcp-tools-reference.md +++ b/plugins/contract-validator/skills/mcp-tools-reference.md @@ -16,6 +16,7 @@ Available MCP tools for contract-validator operations. | `validate_compatibility` | Check two plugins for conflicts | | `validate_agent_refs` | Check agent tool references exist | | `validate_data_flow` | Verify data flow through agent sequence | +| `validate_workflow_integration` | Check domain plugin exposes required advisory interfaces | ### Report Tools | Tool | Description | @@ -53,6 +54,13 @@ Available MCP tools for contract-validator operations. 3. Build Mermaid diagram from results ``` +### Workflow Integration Check +``` +1. validate_workflow_integration(plugin_path, domain_label) # Check single domain plugin +2. For each domain in domain-consultation.md detection rules: + validate_workflow_integration(domain_plugin_path, domain_label) +``` + ## Error Handling If MCP tools fail: diff --git a/plugins/contract-validator/skills/validation-rules.md b/plugins/contract-validator/skills/validation-rules.md index e11bdb1..1c92f25 100644 --- a/plugins/contract-validator/skills/validation-rules.md +++ b/plugins/contract-validator/skills/validation-rules.md @@ -30,6 +30,13 @@ Rules for validating plugin compatibility and agent definitions. 3. Check for orphaned data references 4. Ensure required data is available at each step +### Workflow Integration Checks +1. Gate command exists in plugin's commands/ directory +2. Gate command produces binary PASS/FAIL output +3. Review command exists (WARNING if missing, not ERROR) +4. Advisory agent exists referencing the domain label +- Severity: ERROR for missing gate, WARNING for missing review/agent + ## Severity Levels | Level | Meaning | Action | @@ -46,6 +53,8 @@ Rules for validating plugin compatibility and agent definitions. | Data flow gap | Producer not called before consumer | Reorder workflow steps | | Name conflict | Two plugins use same command | Rename one command | | Orphan reference | Data produced but never consumed | Remove or use the data | +| Missing gate command | Domain plugin lacks /X-gate command | Create commands/{domain}-gate.md | +| Missing advisory agent | Domain plugin has no reviewer agent | Create agents/{domain}-advisor.md | ## MCP Tools @@ -54,4 +63,5 @@ Rules for validating plugin compatibility and agent definitions. | `validate_compatibility` | Check two plugins for conflicts | | `validate_agent_refs` | Check agent tool references | | `validate_data_flow` | Verify data flow sequences | +| `validate_workflow_integration` | Check domain plugin advisory interfaces | | `list_issues` | Filter issues by severity or type | diff --git a/scripts/setup.sh b/scripts/setup.sh index 343fac3..7b0ebf9 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -278,7 +278,7 @@ print_report() { # --- Main --- main() { echo "==============================================" - echo " Leo Claude Marketplace Setup (v5.1.0)" + echo " Leo Claude Marketplace Setup (v5.7.1)" echo "==============================================" echo "" -- 2.49.1