Skip to content

Refactor dispatch/call workflow duplication with shared input, tool, and resolver helpers#33947

Merged
pelikhan merged 4 commits into
mainfrom
copilot/refactor-semantic-function-clustering-please-work
May 22, 2026
Merged

Refactor dispatch/call workflow duplication with shared input, tool, and resolver helpers#33947
pelikhan merged 4 commits into
mainfrom
copilot/refactor-semantic-function-clustering-please-work

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 22, 2026

Semantic clustering identified high-value duplication between dispatch-workflow and call-workflow safe-output paths: repeated trigger input extraction, near-identical MCP tool generation, and duplicated workflow file resolution logic. This PR consolidates those paths into shared helpers while keeping existing entry points/wrappers intact.

  • Shared trigger-input extraction (YAML + markdown frontmatter)

    • Added workflow_inputs_extractor.go with:
      • extractInputsFromYAML(workflowPath, trigger)
      • extractInputsFromMarkdown(mdPath, trigger)
      • extractInputsFromParsedWorkflow(workflow, trigger)
    • Rewired existing dispatch/call extractors to delegate to these helpers, removing repeated on -> trigger -> inputs map walking.
  • Shared safe-output tool definition builder

    • Added generateWorkflowToolDefinition(...) in safe_outputs_workflow_helpers.go.
    • Refactored:
      • generateDispatchWorkflowTool(...)
      • generateCallWorkflowTool(...)
    • Preserved behavior differences via options (descriptionFormat, metadata key).
  • Shared workflow file extension resolution

    • Added resolveWorkflowExtension(fileResult) (string, bool) in safe_outputs_workflow_helpers.go.
    • Refactored both populateDispatchWorkflowFiles(...) and populateCallWorkflowFiles(...) to use the same .lock.yml > .yml > .md(.lock.yml) priority logic.
  • Focused regression coverage

    • Added:
      • workflow_inputs_extractor_test.go
      • safe_outputs_workflow_helpers_test.go
    • Covers trigger-aware extraction and extension-priority behavior.
tool := generateWorkflowToolDefinition(workflowToolDefinitionOptions{
    workflowName:      workflowName,
    workflowInputs:    workflowInputs,
    descriptionFormat: "Call the '%s' reusable workflow via workflow_call...",
    metadataKey:       "_call_workflow_name",
})

extension, found := resolveWorkflowExtension(fileResult)
inputs := extractInputsFromParsedWorkflow(workflow, "workflow_call")

Copilot AI and others added 3 commits May 22, 2026 06:08
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor dispatch and call workflow for semantic clustering Refactor dispatch/call workflow duplication with shared input, tool, and resolver helpers May 22, 2026
Copilot AI requested a review from pelikhan May 22, 2026 06:21
@github-actions github-actions Bot mentioned this pull request May 22, 2026
@pelikhan pelikhan marked this pull request as ready for review May 22, 2026 11:57
Copilot AI review requested due to automatic review settings May 22, 2026 11:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors duplicated logic across the dispatch-workflow and call-workflow safe-output paths by consolidating common workflow-input extraction, tool-definition construction, and workflow file-extension resolution into shared helpers, with focused unit tests added for the new helpers.

Changes:

  • Added shared trigger-aware input extraction helpers for YAML workflows and Markdown frontmatter, and rewired existing dispatch/call extractors to use them.
  • Added shared safe-output helper utilities to generate MCP tool definitions and to resolve workflow file extension priority (.lock.yml > .yml > .md→.lock.yml), then refactored dispatch/call paths to delegate.
  • Updated a generated workflow lockfile as part of compilation output refresh.
Show a summary per file
File Description
pkg/workflow/workflow_inputs_extractor.go Introduces shared trigger-aware input extraction helpers for YAML and Markdown frontmatter.
pkg/workflow/workflow_inputs_extractor_test.go Adds unit tests validating trigger-aware input extraction behavior.
pkg/workflow/safe_outputs_workflow_helpers.go Adds shared helpers for MCP tool definition generation and workflow extension resolution.
pkg/workflow/safe_outputs_workflow_helpers_test.go Adds tests for workflow extension resolution priority behavior.
pkg/workflow/safe_outputs_dispatch.go Refactors dispatch safe-output tool generation and file-extension resolution to use shared helpers.
pkg/workflow/safe_outputs_call_workflow.go Refactors call-workflow safe-output tool generation and file-extension resolution to use shared helpers.
pkg/workflow/dispatch_workflow_validation.go Switches workflow_dispatch input extraction to shared YAML helper.
pkg/workflow/dispatch_workflow_file_resolver.go Switches Markdown workflow_dispatch input extraction to shared Markdown helper.
pkg/workflow/call_workflow_validation.go Switches workflow_call input extraction (YAML/MD/parsed) to shared helpers.
.github/workflows/dataflow-pr-discussion-dataset.lock.yml Updates generated workflow lockfile output (compiler/regeneration effects).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 0

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

Design Decision Gate 🏗️ failed during design decision gate check.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

PR Code Quality Reviewer completed the code quality review.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent refactoring — clean consolidation of duplicated logic

This PR successfully eliminates the semantic duplication between dispatch and call workflow paths while maintaining behavior. The new helpers are well-tested and the consolidation is straightforward.

✅ Strengths
  • Clear separation of concerns: Input extraction, tool generation, and file resolution are now separate, reusable helpers
  • Comprehensive test coverage: Both new helper modules have focused tests covering trigger-aware extraction and extension priority
  • Minimal behavior change: The refactoring preserves existing logic — just removes repetition
  • Good naming: Function names like extractInputsFromParsedWorkflow, generateWorkflowToolDefinition, and resolveWorkflowExtension are self-documenting
📊 Review Impact
  • 10 files changed: +364 -254 lines (net reduction of duplication)
  • 2 new test files: Focused regression coverage for shared helpers
  • Zero blocking issues found

🔎 Code quality review by PR Code Quality Reviewer · ● 760.7K

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /improve-codebase-architecture, /zoom-out, and /tdd — solid refactoring with opportunities to strengthen documentation and test coverage.

📋 Key Themes & Highlights

Key Themes

  • Documentation gaps: New shared helpers lack godoc — this is a great refactoring, but undocumented shared functions can create confusion
  • Test coverage: Core consolidation function generateWorkflowToolDefinition needs direct tests to verify dispatch vs. call differences are preserved
  • Naming clarity: workflowToolDefinitionOptions could be more domain-specific (consider mcpWorkflowToolOptions or similar)

Positive Highlights

  • Excellent DRY refactoring — consolidating 200+ lines of duplication into focused helpers
  • Clear trigger parameterizationextractInputsFromParsedWorkflow(workflow, trigger) makes intent explicit
  • Preserved behavioral differences — dispatch vs. call retain their distinct metadata keys via metadataKey parameter
  • Good test structure — table-driven tests with clear naming
  • Clean extension resolutionresolveWorkflowExtension() eliminates repeated priority logic
🎯 Matt Pocock Skills Applied

/improve-codebase-architecture: This refactoring creates deep modules (simple interfaces, rich behavior). The shared helpers have clear, focused responsibilities. However, domain language could be strengthened — names like workflowToolDefinitionOptions are generic; consider emphasizing the MCP tool or safe-output context.

/zoom-out: The consolidation fits the broader architecture well. Dispatch and call workflows share 90% of their logic but differ in metadata routing keys — the metadataKey parameter elegantly preserves this distinction. The refactoring doesn't introduce new abstractions unnecessarily.

/tdd: Existing tests are well-structured (table-driven, trigger-aware), but the highest-impact functiongenerateWorkflowToolDefinition — lacks direct coverage. Testing this function would provide confidence that the consolidation preserves dispatch vs. call differences.


Summary: This is a clean, well-motivated refactoring that eliminates significant duplication. The inline comments highlight opportunities to strengthen documentation and test coverage — addressing these will make the shared helpers easier to maintain and extend. Great work! 🎉

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · ● 1.2M


triggerConfig, hasTriggerConfig := onMap[trigger]
if !hasTriggerConfig {
return make(map[string]any)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/improve-codebase-architecture] Missing documentation — this is a new shared module, so godoc is essential.

💡 Suggested documentation

Add package-level and function-level documentation:

// Package workflow provides workflow compilation and validation utilities.

// extractInputsFromParsedWorkflow extracts workflow trigger inputs from a parsed
// workflow map. The trigger parameter specifies which trigger to extract inputs
// from (e.g., "workflow_dispatch", "workflow_call").
//
// Returns an empty map if the trigger or inputs are not found.
func extractInputsFromParsedWorkflow(workflow map[string]any, trigger string) map[string]any {

This is a core extraction function that will be used across multiple modules — documenting the trigger parameter and return behavior prevents confusion.

import (
"fmt"
"sort"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/improve-codebase-architecture] Type name lacks domain context — workflowToolDefinitionOptions is too generic.

💡 Suggested naming

Consider one of these domain-specific names:

// Option 1: Emphasize the MCP tool aspect
type mcpWorkflowToolOptions struct {

// Option 2: Emphasize the safe-output aspect
type safeOutputToolOptions struct {

// Option 3: Be explicit about both
type workflowMCPToolConfig struct {

The current name "options" suggests configuration, but this is actually the definition of an MCP tool for workflow triggers. Using "options" for a struct that produces a tool schema can be confusing — consider Config or drop the suffix entirely.

type workflowToolDefinitionOptions struct {
workflowName string
workflowInputs map[string]any
descriptionFormat string
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/zoom-out] Exported function lacks documentation.

💡 Suggested documentation
// generateWorkflowToolDefinition creates an MCP tool definition for workflow
// dispatch or call operations. The returned tool schema includes normalized
// naming, input parameter validation, and metadata for handler routing.
//
// The metadataKey parameter determines which internal field is used for routing
// (e.g., "_workflow_name" for dispatch, "_call_workflow_name" for call).
func generateWorkflowToolDefinition(opts workflowToolDefinitionOptions) map[string]any {

This function is central to the refactoring — documenting its purpose and the significance of metadataKey helps future maintainers understand why dispatch and call use different keys.

"testing"

"github.com/stretchr/testify/assert"
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] Missing test coverage for generateWorkflowToolDefinition — only resolveWorkflowExtension is tested.

💡 Suggested test cases

Add tests for the core tool generation function:

func TestGenerateWorkflowToolDefinition(t *testing.T) {
	tests := []struct {
		name     string
		opts     workflowToolDefinitionOptions
		assertFn func(*testing.T, map[string]any)
	}{
		{
			name: "generates dispatch tool with required inputs",
			opts: workflowToolDefinitionOptions{
				workflowName: "test-workflow",
				workflowInputs: map[string]any{
					"environment": map[string]any{"type": "string", "required": true},
				},
				descriptionFormat: "Dispatch '%s'",
				metadataKey:       "_workflow_name",
			},
			assertFn: func(t *testing.T, tool map[string]any) {
				assert.Equal(t, "test_workflow", tool["name"])
				assert.Equal(t, "test-workflow", tool["_workflow_name"])
				assert.Contains(t, tool["description"], "Dispatch 'test-workflow'")
			},
		},
		{
			name: "generates call tool with different metadata key",
			opts: workflowToolDefinitionOptions{
				workflowName:      "reusable-workflow",
				workflowInputs:    map[string]any{},
				descriptionFormat: "Call '%s'",
				metadataKey:       "_call_workflow_name",
			},
			assertFn: func(t *testing.T, tool map[string]any) {
				assert.Equal(t, "reusable-workflow", tool["_call_workflow_name"])
				assert.NotContains(t, tool, "_workflow_name")
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tool := generateWorkflowToolDefinition(tt.opts)
			tt.assertFn(t, tool)
		})
	}
}

This is the highest-impact function in the refactoring — testing it ensures the consolidation preserves dispatch vs. call differences.


"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] Good trigger-aware test coverage, but missing edge cases.

💡 Additional test cases to consider

Add tests for error paths and malformed input:

func TestExtractInputsFromParsedWorkflow_EdgeCases(t *testing.T) {
	tests := []struct {
		name     string
		workflow map[string]any
		trigger  string
		expected map[string]any
	}{
		{
			name:     "missing 'on' section",
			workflow: map[string]any{},
			trigger:  "workflow_dispatch",
			expected: map[string]any{},
		},
		{
			name: "trigger exists but has no inputs",
			workflow: map[string]any{
				"on": map[string]any{
					"workflow_dispatch": map[string]any{},
				},
			},
			trigger:  "workflow_dispatch",
			expected: map[string]any{},
		},
		{
			name: "inputs is not a map",
			workflow: map[string]any{
				"on": map[string]any{
					"workflow_dispatch": map[string]any{
						"inputs": "invalid",
					},
				},
			},
			trigger:  "workflow_dispatch",
			expected: map[string]any{},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := extractInputsFromParsedWorkflow(tt.workflow, tt.trigger)
			assert.Equal(t, tt.expected, result)
		})
	}
}

These edge cases protect against malformed workflow files that could cause runtime panics.

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

Analyzed 3 test(s): 3 design, 0 implementation, 0 guideline violation(s).

📊 Metrics & Test Classification (3 tests analyzed)
Metric Value
New/modified tests analyzed 3
✅ Design tests (behavioral contracts) 3 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 3 (100%)
Duplicate test clusters 0
Test inflation detected NO
🚨 Coding-guideline violations 0 (all build tags present, no mock libraries)

Test Classification Details

Test File Classification Issues Detected
TestResolveWorkflowExtension pkg/workflow/safe_outputs_workflow_helpers_test.go:11 ✅ Design Table-driven (4 scenarios); enforces file resolution priority
TestExtractInputsFromParsedWorkflow_TriggerAware pkg/workflow/workflow_inputs_extractor_test.go:14 ✅ Design Validates trigger isolation for parsed workflows
TestExtractInputsFromMarkdown_TriggerAware pkg/workflow/workflow_inputs_extractor_test.go:39 ✅ Design Validates trigger isolation for markdown parsing path

Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 3 tests — unit (//go:build !integration)

Test Inflation Analysis

Test File Production File Ratio Status
safe_outputs_workflow_helpers_test.go (+51) safe_outputs_workflow_helpers.go (+56) 0.91:1 ✅ PASS
workflow_inputs_extractor_test.go (+68) workflow_inputs_extractor.go (+64) 1.06:1 ✅ PASS
💡 Suggestions for Improvement (non-blocking)

Missing Assertion Messages

All three test functions use bare assertions without descriptive messages. While this doesn't affect the test quality score, adding messages improves debuggability when tests fail.

Examples from the code:

// Current
assert.Equal(t, tt.expected, extension)
assert.Contains(t, dispatchInputs, "environment")

// Suggested
assert.Equal(t, tt.expected, extension, "extension should match expected resolution priority")
assert.Contains(t, dispatchInputs, "environment", "workflow_dispatch should include environment input")

Impact: Low severity — tests are otherwise excellent, but assertion failures will be easier to diagnose with context messages.

Project guideline: "Every testify/stdlib assertion in this codebase should have a descriptive message argument."

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%).

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.


Highlights:

  • ✅ All tests enforce behavioral contracts (file resolution priority, trigger isolation)
  • ✅ Excellent edge case coverage (no file found, both trigger types, negative assertions)
  • ✅ Proper use of table-driven tests and require.* vs assert.* discipline
  • ✅ No mock libraries (adheres to "test real component interactions" guideline)
  • ✅ All build tags present
  • ✅ Proportional test growth (no test inflation)
  • 💡 Minor suggestion: add assertion messages for better debuggability

🧪 Test quality analysis by Test Quality Sentinel · ● 931.9K ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 100/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 3 new tests enforce behavioral contracts with comprehensive edge case coverage.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 22, 2026

@copilot review all comments

I reviewed all comments on this PR. There are no actionable review findings requiring code changes at this time.

@pelikhan pelikhan merged commit 86fd419 into main May 22, 2026
74 of 87 checks passed
@pelikhan pelikhan deleted the copilot/refactor-semantic-function-clustering-please-work branch May 22, 2026 12:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[refactor] Semantic function clustering: dispatch/call-workflow duplicates and permission factory consolidation

3 participants