Skip to content

Safe output manager #8098

@pelikhan

Description

@pelikhan

Agentic Task: Implement Safe Output Handler Manager with Factory Pattern

Objective

Refactor the safe output handling system to use a centralized handler manager with a factory pattern, eliminating individual workflow steps and environment variables for each handler type.

Background

Currently, safe output handlers (create_issue, add_comment, etc.) each run as separate workflow steps with their own environment variables. This creates:

  • 8+ individual steps in workflows
  • 30+ environment variables per workflow
  • Complex configuration management
  • Hidden dependencies via env vars

Target Architecture

Handler Manager (Already Implemented ✅)

  • Location: actions/setup/js/safe_output_handler_manager.cjs
  • Loads config from GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG env var
  • Creates handler factories: const messageHandler = await handlerModule.main(config)
  • Processes messages sequentially: await messageHandler(outputItem, resolvedTemporaryIds)
  • Maintains shared temporary ID map across all handlers

Factory Pattern Interface (Needs Implementation)

Each handler must export:

async function main(config = {}) {
  // Initialize with config (no env vars)
  
  return async function(outputItem, resolvedTemporaryIds) {
    // Process single message
    // Return { temporaryId?, repo, number }
  };
}

Implementation Phases

Phase 1: Simple Handlers (Start Here)

Convert these handlers to factory pattern:

  • actions/setup/js/add_labels.cjs (~50 lines)
  • actions/setup/js/close_issue.cjs
  • actions/setup/js/close_discussion.cjs

Pattern: Remove loadAgentOutput() calls, accept message as parameter, return result with temp ID if applicable.

Phase 2: Medium Complexity

  • actions/setup/js/add_comment.cjs
  • actions/setup/js/create_discussion.cjs

Phase 3: Complex Handler

  • actions/setup/js/create_issue.cjs (355 lines)
    • Sub-issue linking logic
    • Cross-repository support
    • Temporary ID resolution
    • Parent-child relationships

Phase 4: Update Factory

  • actions/setup/js/update_runner.cjs (factory generator)
  • actions/setup/js/update_issue.cjs
  • actions/setup/js/update_discussion.cjs

Phase 5: Go Compiler Cleanup

Remove individual env var generation from:

  • pkg/workflow/compiler_safe_outputs_core.go
  • pkg/workflow/compiler_safe_outputs_issues.go
  • pkg/workflow/compiler_safe_outputs_discussions.go
  • pkg/workflow/compiler_safe_outputs_shared.go

Keep only:

  • GH_AW_SAFE_OUTPUTS_STAGED
  • GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG (JSON)

Phase 6: Tests

Update test files to mock factory pattern:

  • actions/setup/js/safe_output_handler_manager.test.cjs
  • Individual handler test files (8 files)

Phase 7: Compilation

  • Run make build to rebuild binary
  • Run make recompile to regenerate all .lock.yml files (126 workflows)

Environment Variables (Final State)

Before: 30+ env vars per workflow

env:
  GH_AW_ISSUE_MAX: "5"
  GH_AW_ISSUE_EXPIRES: "7"
  GH_AW_ISSUE_ALLOWED_LABELS: "bug,feature"
  GH_AW_COMMENT_MAX: "1"
  GH_AW_HIDE_OLDER_COMMENTS: "true"
  # ... 25+ more

After: 2 env vars only

env:
  GH_AW_SAFE_OUTPUTS_STAGED: "false"
  GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: '{"create_issue":{"max":5,"expires":7},"add_comment":{"max":1}}'

Key Requirements

  1. No env var reading in handlers - All config via parameter
  2. Factory pattern - main(config) returns message processor
  3. Message-level processing - Handlers receive individual messages
  4. Temporary ID management - Shared map passed between handlers
  5. Sequential processing - Messages processed in order of appearance

Testing Strategy

  • Test each refactored handler in isolation
  • Verify factory pattern returns correct function signature
  • Test message processing with mock data
  • Integration test through handler manager
  • Validate compiled workflows

Files to Modify

JavaScript (10 files):

  • 8 handler files
  • 1 factory generator (update_runner.cjs)
  • 1 test file (safe_output_handler_manager.test.cjs)

Go (4 files):

  • compiler_safe_outputs_core.go
  • compiler_safe_outputs_issues.go
  • compiler_safe_outputs_discussions.go
  • compiler_safe_outputs_shared.go

Workflows: 126 .lock.yml files (via recompilation)

Estimated Effort

  • Phase 1-3: 4-6 hours (handler refactoring)
  • Phase 4: 1-2 hours (update factory)
  • Phase 5: 1 hour (Go compiler)
  • Phase 6: 2-3 hours (tests)
  • Phase 7: 30 minutes (compilation)

Total: 8-12 hours

Success Criteria

  • ✅ All 8 handlers use factory pattern
  • ✅ No individual env vars except staged mode
  • ✅ All tests pass
  • ✅ 126 workflows compile successfully
  • ✅ Workflows use single "Process Safe Outputs" step
  • ✅ Handler manager loads and dispatches correctly

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions