Skip to content

Split safe outputs handler registry by domain - #55482

Merged
pelikhan merged 8 commits into
mainfrom
copilot/file-diet-split-safe-outputs-handler
Aug 24, 2026
Merged

Split safe outputs handler registry by domain#55482
pelikhan merged 8 commits into
mainfrom
copilot/file-diet-split-safe-outputs-handler

Conversation

Copilot AI commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

pkg/workflow/safe_outputs_handler_registry.go was a 1K+ line monolith centered on one large registry literal. This refactor separates handler builders by safe-output domain while keeping registry lookup behavior unchanged.

  • Registry composition
    • Kept token-resolution helpers and handlerRegistry assembly in safe_outputs_handler_registry.go
    • Added mergeHandlerMaps(...) to compose focused domain registries without changing call sites
var handlerRegistry = mergeHandlerMaps(
	issueHandlerRegistry,
	discussionHandlerRegistry,
	pullRequestHandlerRegistry,
	workflowHandlerRegistry,
	projectHandlerRegistry,
	miscHandlerRegistry,
)
  • Domain-focused handler files

    • Moved issue handlers into safe_outputs_handler_registry_issues.go
    • Moved discussion handlers into safe_outputs_handler_registry_discussions.go
    • Moved pull request/review handlers into safe_outputs_handler_registry_pull_requests.go
    • Moved workflow, artifact, coverage, and code-scanning handlers into safe_outputs_handler_registry_workflow.go
    • Moved project and assignment handlers into safe_outputs_handler_registry_projects.go
    • Moved comments, release, diagnostic, and no-op handlers into safe_outputs_handler_registry_misc.go
  • Coverage for the split

    • Added registry tests for domain membership, full registry composition, builder enable/disable behavior, duplicate-key handling, and token helper behavior.

Copilot AI and others added 2 commits August 24, 2026 19:12
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 pkg/workflow/safe_outputs_handler_registry.go into smaller files Split safe outputs handler registry by domain Aug 24, 2026
Copilot AI requested a review from pelikhan August 24, 2026 19:30
@pelikhan
pelikhan marked this pull request as ready for review August 24, 2026 20:02
Copilot AI balanced review requested due to automatic review settings August 24, 2026 20:02
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Generated by Ponytail Reviewer for #55482

Copilot AI left a comment

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.

Pull request overview

Refactors the monolithic safe-output handler registry into domain-focused files for #55406.

Changes:

  • Composes six domain registries through mergeHandlerMaps.
  • Extracts handler builders while preserving lookup behavior.
  • Adds registry composition, builder, duplicate-key, and token tests.
Show a summary per file
File Description
safe_outputs_handler_registry.go Composes domain registries.
safe_outputs_handler_registry_issues.go Contains issue handlers.
safe_outputs_handler_registry_discussions.go Contains discussion handlers.
safe_outputs_handler_registry_pull_requests.go Contains pull-request handlers and extracted builder helpers.
safe_outputs_handler_registry_workflow.go Contains workflow and artifact handlers.
safe_outputs_handler_registry_projects.go Contains project and assignment handlers.
safe_outputs_handler_registry_misc.go Contains miscellaneous handlers.
safe_outputs_handler_registry_test.go Tests composition and helper behavior.

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 2
  • Review effort level: Balanced

@@ -0,0 +1,130 @@
package workflow

// projectHandlerRegistry contains project board and assignment handler builders.
@@ -0,0 +1,123 @@
package workflow

// miscHandlerRegistry contains comment, release, diagnostic, and no-op handler builders.
@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-08-24T00:00:00Z
review_event: COMMENT
top_themes:
  - registry split preserved behavior
  - duplicate-key merge behavior covered by tests
  - no changed-line blocking issues found
files_reviewed:
  - pkg/workflow/safe_outputs_handler_registry.go
  - pkg/workflow/safe_outputs_handler_registry_discussions.go
  - pkg/workflow/safe_outputs_handler_registry_issues.go
  - pkg/workflow/safe_outputs_handler_registry_misc.go
  - pkg/workflow/safe_outputs_handler_registry_projects.go
  - pkg/workflow/safe_outputs_handler_registry_pull_requests.go
  - pkg/workflow/safe_outputs_handler_registry_workflow.go
  - pkg/workflow/safe_outputs_handler_registry_test.go
comment_count: 0

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · pi · gpt54 · 19.7 AIC · ⌖ 6.86 AIC · ⊞ 7K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

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.

Review outcome

I didn't find any changed-line correctness, security, or performance regressions in this registry split.

Notes
  • The refactor preserves the existing builder logic by moving handlers verbatim into domain-scoped registries.
  • mergeHandlerMaps deterministically keeps the first duplicate and emits a debug log, and the new tests cover registry composition plus duplicate-key behavior.
  • I discarded the requested sub-agent pass because grumpy-coder is not available in this environment.

🔎 Code quality review by PR Code Quality Reviewer · pi · gpt54 · 19.7 AIC · ⌖ 6.86 AIC · ⊞ 7K
Comment /review to run again

@github-actions github-actions Bot left a comment

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.

Review: Split safe outputs handler registry by domain

Clean structural refactor — splitting a 1000+ line monolithic registry into domain-scoped files is a good maintainability win. The mergeHandlerMaps helper and Go's dependency-driven init ordering make this functionally safe.

One minor issue: stale (see create-issue handler above) comments in two new files where create_issue is no longer co-located.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet46 · 56.6 AIC · ⌖ 9.1 AIC · ⊞ 6.2K

AddStringSlice("labels", c.Labels).
AddStringSlice("allowed_labels", c.AllowedLabels).
AddStringSlice("allowed_repos", c.AllowedRepos).
// entity-specific env key name per shared CloseOlderConfig field (see create-issue handler above)

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.

Stale cross-file comment(see create-issue handler above) is now incorrect after the split. The create_issue handler lives in safe_outputs_handler_registry_issues.go, not in this file. Update to reference the correct file:

// entity-specific env key name per shared CloseOlderConfig.Enabled; see create_issue handler
// in safe_outputs_handler_registry_issues.go for the canonical explanation.

@copilot please address this.

AddIfTrue("recreate_ref", c.RecreateRef).
AddIfNotEmpty("patch_format", c.PatchFormat).
AddBoolPtr("signed_commits", c.SignedCommits).
// entity-specific env key name per shared CloseOlderConfig field (see create-issue handler above)

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.

Stale cross-file comment(see create-issue handler above) is now incorrect after the split. The create_issue handler lives in safe_outputs_handler_registry_issues.go, not above in this file. Update the comment to reference the correct file explicitly.

@copilot please address this.

@github-actions github-actions Bot left a comment

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.

Skills-Based Review 🧠

Applied /codebase-design and /tdd — requesting minor changes.

📋 Key Themes & Highlights

Key Themes

  • Style inconsistency carried over: several new files contain multiple chained .Add* calls on the same line, copied verbatim from the original monolith. The refactor is a good opportunity to normalise to one-call-per-line throughout.
  • misc registry as an everything-else drawer: add_comment and hide_comment are cross-cutting (apply to issues, discussions, and PRs), which makes them awkward under miscHandlerRegistry. A dedicated commentsHandlerRegistry or a rename would better communicate scope.
  • Test coverage for nil-vs-empty-map semantics: add_labels, replace_label, set_issue_type, and set_issue_field all return make(map[string]any) (enabled, all-allowed) when built with an empty config — this behaviour is not exercised by the current test table.
  • Duplicate-key length assertion missing: TestMergeHandlerMapsKeepsFirstDuplicateKey checks the winning builder's value but not that the merged map has exactly one key.

Positive Highlights

  • ✅ Excellent use of mergeHandlerMaps — registry composition is clean and call sites are unchanged
  • ✅ New test file covers domain membership, builder enable/disable, token-helper paths, and duplicate-key policy — great baseline
  • ✅ Stale inline comments that referenced "see create-issue handler above" now make less sense in a cross-file split — though the moved comment (// entity-specific env key name per shared CloseOlderConfig field (see create-issue handler above)) still appears in discussions.go; worth updating the cross-reference.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet46 · 102.3 AIC · ⌖ 10.2 AIC · ⊞ 7.6K
Comment /matt to run again

AddTemplatableInt("max", c.Max).
AddStringSlice("allowed_fields", c.AllowedFields).
AddBoolPtr("issue_intent", c.IssueIntent).
AddIfNotEmpty("target", c.Target).AddStringSlice("required_labels", c.RequiredLabels).

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.

[/codebase-design] Chained Add calls on one line were carried over verbatim from the original monolith — this inconsistency makes the new file harder to scan than the handlers where each call is on its own line.

💡 Suggested fix

Split each call onto its own line:

			AddIfNotEmpty("target", c.Target).
			AddStringSlice("required_labels", c.RequiredLabels).
			AddIfNotEmpty("required_title_prefix", c.RequiredTitlePrefix).
			AddIfNotEmpty("target-repo", c.TargetRepoSlug).

The same style inconsistency recurs in misc.go (~line 34), projects.go (~line 57), and pull_requests.go (~lines 68, 165).

@copilot please address this.

@@ -0,0 +1,123 @@
package workflow

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.

[/codebase-design] add_comment is a cross-cutting handler that works on issues, discussions, and PRs, yet it lives in miscHandlerRegistry whose doc-comment says "comment, release, diagnostic, and no-op handlers." The misc bucket risks growing into an everything-else drawer over time, making domain navigation harder.

💡 Options
  • Move add_comment and hide_comment into a dedicated safe_outputs_handler_registry_comments.go with a commentsHandlerRegistry.
  • Or rename this file's registry to crossCuttingHandlerRegistry and update the doc-comment to explicitly describe its scope.

Either approach prevents the misc bucket from silently absorbing future cross-entity handlers.

@copilot please address this.

cfg *SafeOutputsConfig
}{
{name: "create_issue", cfg: &SafeOutputsConfig{CreateIssues: &CreateIssuesConfig{}}},
{name: "close_issue", cfg: &SafeOutputsConfig{CloseIssues: &CloseIssuesConfig{}}},

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] TestHandlerRegistryBuilders tests the enabled path with minimal structs (e.g. &CreateIssuesConfig{}), but handlers that return make(map[string]any) for an empty config — like add_labels, replace_label, set_issue_type, and set_issue_field — are not tested for the "configured with null / no options means all allowed" semantic.

💡 Suggested additions
// Test that add_labels with explicit nil sub-fields still returns non-nil (all-allowed)
{name: "add_labels_all_allowed", cfg: &SafeOutputsConfig{AddLabels: &AddLabelsConfig{}}, wantNonNil: true},

Add a wantNonEmpty bool field to the test table to distinguish between "returns nil map" (disabled), "returns non-nil empty map" (enabled, all allowed), and "returns non-nil populated map" (enabled, restricted).

@copilot please address this.

{name: "create_report_incomplete_issue", cfg: &SafeOutputsConfig{ReportIncomplete: &ReportIncompleteConfig{CreateIssue: strPtr("true")}}},
}

for _, tt := range tests {

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] The duplicate-key test (TestMergeHandlerMapsKeepsFirstDuplicateKey) only checks the value; it doesn't assert that the merged map has exactly one entry for the duplicate key. A bug that keeps both keys under different aliases would not be caught.

💡 Suggested addition
if len(got) != 1 {
    t.Fatalf("mergeHandlerMaps: want 1 key, got %d", len(got))
}

@copilot please address this.

@github-actions github-actions Bot left a comment

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.

The main simplification I’d make here is to collapse the category-split registry back into a single table and drop the extra merge helper; the runtime behavior is unchanged and the code becomes easier to scan. net: -17 lines possible.

Generated by ✂️ Ponytail Reviewer for #55482 · codex · mai10 · 6.73 AIC · ⌖ 1.59 AIC · ⊞ 18.3K
Comment /ponytail to run again

if len(c.AwContextWorkflows) > 0 {
builder.AddStringSlice("aw_context_workflows", c.AwContextWorkflows)
}
var handlerRegistry = mergeHandlerMaps(

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.

pkg/workflow/safe_outputs_handler_registry.go:57-77: yagni: split registry into six files plus a merge helper for a fixed lookup table. Keep one map in one file.

@github-actions

Copy link
Copy Markdown
Contributor

ADR Required — Draft Generated

Status: Draft ADR committed to this branch · Merge blocked pending author review

A draft Architecture Decision Record was automatically generated for this PR because it adds 1,347 lines of code to pkg/workflow/ (threshold: 100).

The draft has been committed to this branch at:
docs/adr/55482-split-safe-outputs-handler-registry-by-domain.md

What to do next
  1. Review the draft ADR at docs/adr/55482-split-safe-outputs-handler-registry-by-domain.md
  2. Edit if needed — verify the Decision, Alternatives, and Consequences sections reflect your actual intent
  3. Change status from DraftAccepted once the team agrees
Draft ADR summary

Decision: Decompose the monolithic handlerRegistry map (1 000+ lines) into six domain-focused sub-registries (issues, discussions, pull_requests, workflow, projects, misc), composed at package init via mergeHandlerMaps(...). All call sites remain unchanged.

Key trade-offs captured:

  • Positive: Domain handlers reviewable and changeable in isolation; mergeHandlerMaps adds duplicate-key detection
  • Negative: First-wins collision policy is logged but not enforced at compile time; initialization order is implicit

Blocking notice: This PR exceeds the code-volume threshold for ADR enforcement. Please review and finalize the draft ADR before merging.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · claude · sonnet46 · 96.8 AIC · ⌖ 18.2 AIC · ⊞ 8.6K ·
Comment /review to run again

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

gh-aw-pr-sous-chef
@copilot PR Sous Chef triage: this PR still needs a forward-progress pass before maintainer investigation is likely to be productive.

Please do one focused follow-up pass:

  • address the current blocking github-actions review and any remaining reviewer feedback directly in the PR threads
  • refresh the branch if needed and use the pr-finisher skill before handing back for review
  • the blocked workflow approvals for this head were handled in this run; no extra workflow action is needed unless new commits land

Run: https://github.com/github/gh-aw/actions/runs/32774702076

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 25.7 AIC · ⌖ 8.08 AIC · ⊞ 8.7K ·
Comment /souschef to run again

pelikhan and others added 3 commits August 24, 2026 13:52
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

gh-aw-pr-sous-chef
@copilot PR Sous Chef triage: this PR still needs a forward-progress pass before maintainer investigation is likely to be productive.
...

Follow-up pass pushed:

  • projectHandlerRegistry now only holds project-board handlers; assignment and agent-session handlers moved to safe_outputs_handler_registry_assignments.go (49881a6).
  • The catch-all miscHandlerRegistry is gone, replaced by commentHandlerRegistry, releaseHandlerRegistry, and diagnosticHandlerRegistry, each composed directly in mergeHandlerMaps (49881a6).
  • Stale see create-issue handler above cross-references now point at safe_outputs_handler_registry_issues.go, and the duplicate-key test asserts the merged map size (c3f7fe8).

Registry tests pass; remaining golint-custom findings are pre-existing and unrelated to these files.

Copilot AI requested a review from gh-aw-bot August 24, 2026 20:58
@pelikhan
pelikhan merged commit affd150 into main Aug 24, 2026
34 checks passed
@pelikhan
pelikhan deleted the copilot/file-diet-split-safe-outputs-handler branch August 24, 2026 22:16
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.87.5

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.

[file-diet] File Diet: Split pkg/workflow/safe_outputs_handler_registry.go (1091 lines)

4 participants