Skip to content

Normalize dispatch-repository nested keys to kebab-case while preserving snake_case aliases - #44942

Closed
pelikhan with Copilot wants to merge 4 commits into
mainfrom
copilot/deep-report-rename-nested-keys
Closed

Normalize dispatch-repository nested keys to kebab-case while preserving snake_case aliases#44942
pelikhan with Copilot wants to merge 4 commits into
mainfrom
copilot/deep-report-rename-nested-keys

Conversation

CopilotAI commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

safe-outputs.dispatch-repository was the only area mixing key styles: dashed parent key with snake_case nested fields. This change makes nested keys canonical in kebab-case (event-type, allowed-repositories) while retaining snake_case aliases for backward compatibility.

  • Schema: canonical keys + compatibility aliases

    • Updated main_workflow_schema.json to define event-type and allowed-repositories as canonical nested fields.
    • Kept event_type and allowed_repositories as deprecated-compatible aliases.
    • Adjusted required-field semantics to accept either event-type or event_type, and documented canonical-key precedence when both are present.
  • Parser/runtime: canonical-first resolution

    • Updated parseDispatchRepositoryConfig to read kebab-case first, then fallback to snake_case aliases.
    • Preserves existing workflows while steering new config toward consistent kebab-case usage.
  • Validation and docs: aligned terminology

    • Updated dispatch-repository validation messages/examples to use canonical kebab-case and explicitly mention aliases.
    • Updated frontmatter reference, safe-outputs reference, and glossary examples/descriptions to reflect canonical nested keys and alias behavior.
  • Focused behavior coverage

    • Extended dispatch-repository tests to cover:
      • canonical key parsing,
      • canonical-over-alias precedence,
      • alias-only fallback support,
      • error messaging that mentions both canonical and alias forms.
safe-outputs:
dispatch-repository:
notify-service:
workflow: notify.ymlevent-type: notify_eventallowed-repositories:
- org/service-repo

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
CopilotAI changed the title [WIP] Rename dispatch-repository nested keys to kebab-caseNormalize dispatch-repository nested keys to kebab-case while preserving snake_case aliasesJul 11, 2026
CopilotAI requested a review from pelikhanJuly 11, 2026 11:59
@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage

FieldValue
Categorychore
Risk🟡 Medium
Score55/100 (impact:25, urgency:13, quality:17)
Action📦 batch_review
Batchchore-cleanup

Rationale: Normalizes dispatch-repository nested keys to kebab-case (7 files). Breaking change risk if consumers rely on snake_case keys directly, but aliases are preserved. Draft PR.

Generated by 🔧 PR Triage Agent · 242.5 AIC · ⌖ 9.07 AIC · ⊞ 5.6K ·

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot make dispatch-positive NON experimental

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

CopilotAI commented Jul 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot make dispatch-positive NON experimental

Implemented in 42bb363: dispatch-repository is now non-experimental (removed experimental warning emission), with tests updated to assert no experimental warning and docs updated to remove experimental labeling.

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the PR — the change looks on-topic and reasonably focused, with test coverage and a clear description.

One process issue blocks alignment with this repository's contribution guidelines: this PR appears to have been opened directly by a non-core author association (CONTRIBUTOR). Per CONTRIBUTING.md, non-core contributors should propose detailed agentic plans in issues, and a core team member should create and implement the PR.

Please convert this work into an issue or have a core team member recreate/sponsor the PR path.

Review this PR against github/gh-aw contribution rules.
Required action:
1. Do not continue with direct PR iteration from a non-core contributor path.
2. Extract the implementation intent into a detailed issue/agentic plan.
3. Include: problem statement, proposed behavior, touched files, backward-compatibility notes, and validation/tests.
4. Ask a core team member (MEMBER/OWNER/COLLABORATOR) to open or recreate the PR if the change should proceed.
5. Preserve the current useful details: canonical kebab-case keys, snake_case alias compatibility, precedence behavior, and test scenarios.

Generated by ✅ Contribution Check · 76.5 AIC · ⌖ 16.5 AIC · ⊞ 6.2K ·

@pelikhan
pelikhan marked this pull request as ready for review July 11, 2026 13:35
CopilotAI review requested due to automatic review settings July 11, 2026 13:35

CopilotAI 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

Normalizes dispatch-repository nested keys to kebab-case while retaining snake_case aliases.

Changes:

  • Adds canonical-key parsing, precedence, schema validation, and tests.
  • Updates validation messages and references.
  • Also removes the feature’s experimental warning/status.
Show a summary per file
FileDescription
pkg/workflow/dispatch_repository.goParses canonical keys with alias fallback.
pkg/workflow/dispatch_repository_validation.goUpdates validation guidance.
pkg/workflow/dispatch_repository_test.goAdds precedence and fallback tests.
pkg/workflow/dispatch_repository_experimental_warning_test.goExpects no experimental warning.
pkg/workflow/compiler_validators.goRemoves the experimental warning.
pkg/parser/schemas/main_workflow_schema.jsonDefines canonical keys and aliases.
docs/src/content/docs/reference/safe-outputs.mdUpdates configuration reference.
docs/src/content/docs/reference/glossary.mdUpdates terminology and feature status.
docs/src/content/docs/reference/frontmatter-full.mdUpdates generated schema reference.
.github/aw/safe-outputs-automation.mdRemoves experimental labeling.

Review details

Tip

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

  • Files reviewed: 10/10 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment on lines +16 to +17
// TestDispatchRepositoryNoExperimentalWarning tests that dispatch-repository no longer emits an experimental warning.
func TestDispatchRepositoryNoExperimentalWarning(t *testing.T) {

Triggers other agentic workflows using workflow_dispatch. Agent output includes `workflow_name` (without .md extension) and optional `inputs` (key-value pairs). Cross-repo dispatch is supported via `target-repo` plus an `allowed-repos` allowlist; cross-repo targets require a token with `actions: write` on the target repository.
- `dispatch-repository:` - Dispatch `repository_dispatch` events to external repositories (experimental)
- `dispatch-repository:` - Dispatch `repository_dispatch` events to external repositories
},
}

config := compiler.parseDispatchRepositoryConfig(outputMap)
@github-actions

github-actionsBot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actionsBot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actionsBot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actionsBot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actionsgithub-actionsBot 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: Normalize dispatch-repository nested keys to kebab-case

The implementation is correct and well-tested. The canonical-first fallback pattern in parseDispatchRepositoryConfig is clean, the schema anyOf change properly enforces that at least one form of event-type/event_type is present, and the new tests cover canonical, alias, and precedence cases.

One minor observation (non-blocking): The validation error messages still prefix errors with dispatch_repository: (snake_case) while the YAML examples now correctly use dispatch-repository:. This is internally consistent (it's an error prefix, not a YAML key), but it might briefly confuse users comparing the error message prefix to the frontmatter key. Consider aligning to dispatch-repository: in a follow-up if consistency is a goal.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 16.4 AIC · ⌖ 4.33 AIC · ⊞ 4.8K

…ch-repository nested keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Design Decision Gate - ADR Required

This PR makes significant changes to core business logic (161 new lines in pkg/) but does not have a linked Architecture Decision Record (ADR).

Draft ADR committed: docs/adr/44942-normalize-dispatch-repository-nested-keys-to-kebab-case.md -- review and complete it before merging.

This PR cannot merge until an ADR is linked in the PR body.

What to do next
  1. Review the draft ADR committed to your branch -- it was generated from the PR diff
  2. Complete the missing sections -- add context the AI could not infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as: ADR: [ADR-44942: Normalize dispatch-repository Nested Keys to Kebab-Case](docs/adr/44942-normalize-dispatch-repository-nested-keys-to-kebab-case.md)

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

Why ADRs Matter

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context -- What is the problem? What forces are at play?
  • Decision -- What did you decide? Why?
  • Alternatives Considered -- What else could have been done?
  • Consequences -- What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 54.8 AIC · ⌖ 12.2 AIC · ⊞ 8.5K ·
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 92/100 — Excellent

Analyzed 1 test(s): 1 design test, 0 implementation tests, 0 violation(s).

📊 Metrics (1 test modified)
MetricValue
Test files analyzed1 (Go)
Tests modified1 (TestDispatchRepositoryNoExperimentalWarning)
Design-focused1 (100%)
Implementation0 (0%)
Edge/error coverage✅ 3 scenarios (basic, absent, allowed_repos)
Assertions per scenario3 (compile + stderr + warning count)
Duplicate clusters0
Test inflationNo (–14 net lines)
🚨 Violations0
TestFileClassificationIssues
TestDispatchRepositoryNoExperimentalWarningdispatch_repository_experimental_warning_test.gobehavioral_contractNone
i️ Context

Modified: dispatch_repository_experimental_warning_test.go (12 added, 26 deleted)

  • Renamed test to reflect new behavior (feature no longer experimental)
  • Removed expectWarning conditional; now asserts absence of warning
  • Maintains 3 scenarios: basic usage, absent config, with allowed_repositories
  • Each scenario verifies: compilation succeeds, no stderr warning, 0 warning count
  • Design signal: Clear behavioral contract — dispatch-repository is production-ready

Not modified in current commit: dispatch_repository_test.go (25 test functions from prior commit)

  • Comprehensive parsing, validation, generation, and integration tests
  • Proper build tags (//go:build !integration)
  • No forbidden mock libraries
  • Strong edge-case coverage (expressions, precedence, validation errors)

Verdict

Passed. 0% implementation tests (threshold: 30%); 0 violations.

Test modifications cleanly reflect the feature graduation from experimental to stable. The single modified test is well-structured, design-focused, and includes proper edge-case coverage. No concerns with test quality or infrastructure.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
allowed:
- defaults
- "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 18.7 AIC · ⌖ 9.48 AIC · ⊞ 6.8K ·
Comment /review to run again

@github-actionsgithub-actionsBot 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.

✅ Test Quality Sentinel: 92/100. 0% implementation tests (threshold: 30%). All test modifications pass quality checks.

@github-actionsgithub-actionsBot 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 changes on two issues.

📋 Key Themes & Highlights

Issues

  1. Error prefix inconsistency (dispatch_repository_validation.go): All six error messages use dispatch_repository: as prefix while the body of those same messages uses canonical dispatch-repository:. This leaks the old snake_case form precisely where users are most likely to see it.

  2. Test fixtures still use legacy keys (dispatch_repository_experimental_warning_test.go, lines 34 & 64–65): The no-experimental-warning test suite exercises event_type/allowed_repositories alias paths, not the new canonical event-type/allowed-repositories paths. This misses testing that canonical keys compile clean.

Positive Highlights

  • ✅ Canonical-first fallback logic in parseDispatchRepositoryConfig is clean and explicit.
  • ✅ Comprehensive unit tests added for all four alias/canonical combinations.
  • anyOf schema approach for backward compatibility is correct and expressive.
  • ✅ Removing the experimental caution banner is a good signal of feature maturity.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 48 AIC · ⌖ 4.67 AIC · ⊞ 6.6K
Comment /matt to run again

Comments that could not be inline-anchored

pkg/workflow/dispatch_repository_validation.go:29

[/codebase-design] Error message prefixes throughout this file still say dispatch_repository: (snake_case) while all examples and field references in the same messages now use canonical dispatch-repository: — this inconsistency will confuse users who copy-paste error output.

<details>
<summary>💡 Suggested fix</summary>

Change the six dispatch_repository: error prefixes in this file to dispatch-repository:, e.g.:

// beforereturn errors.New(&quot;dispatch_repository: mustspecif</details><details><summary>pkg/workflow/dispatch_repository_experimental_warning_test.go:34</summary>**[/tdd]**Testfixturesinthisfilestillusesnake_casekeys (`event_type`, `allowed_repositories`) — theyareexercisingthelegacyaliaspath, notthecanonicalkebab-case path. Thisleavesthecanonicalpathuntestedintheexperimentalwarningsuite.
&lt;details&gt;
&lt;summary&gt;💡 Suggestedfix&lt;/summary&gt;
UpdatetestYAMLcontenttouse `event-type` and `allowed-repositories` to prove canonical keys compile without warnings:```yamlsafe-outputs: dispatch-repository: notify-service:</details><details><summary>pkg/workflow/dispatch_repository_validation.go:48</summary>**[/tdd]** Validation error for missing `event-type` does not mention that either canonical OR alias form is accepted. A user who writes `event_type` and makes a typo would see an error that only suggests `event-type`, missing the hint that `event_type` is also valid.&lt;details&gt;&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;The message already says `(alias: &#39;event_type&#39;)` which is good — this comment is confirming it&#39;s correct as-is. However there&#39;s no test that verifies a config with *no event-type fie…
</details>

@github-actionsgithub-actionsBot 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.

Non-blocking observations — safe to merge

The core logic is correct: canonical-first lookup with alias fallback, schema updated to accept either form, tests covering all four cases (canonical-only, alias-only, canonical-over-alias, alias-over-canonical). The removal of the experimental warning is appropriately reflected everywhere.

Findings (all medium/low, non-blocking)
  1. Inconsistent error prefix (dispatch_repository: vs the canonical dispatch-repository:) — error messages in dispatch_repository_validation.go updated their example YAML bodies to kebab-case but left the leading label in snake_case. Confusing for users who read the error and then look at the docs.

  2. anyOf required schema — the anyOf with two single-field branches is fragile. It works now, but the semantics are not obvious and future schema changes could silently weaken the constraint. Worth a clarifying comment or a refactor to oneOf.

  3. GetWarningCount() called twice in the test assertion — minor, but worth a local variable for clarity and safety.

None of these are correctness bugs or security issues.

🔎 Code quality review by PR Code Quality Reviewer · 41.2 AIC · ⌖ 4.7 AIC · ⊞ 5.4K
Comment /review to run again

Comments that could not be inline-anchored

pkg/workflow/dispatch_repository_experimental_warning_test.go:325

GetWarningCount() called twice in assertion — second call may observe stale state if the method has side effects or if compiler state is mutated between calls.

<details>
<summary>💡 Suggested fix</summary>

Extract to a local variable so both the condition and the error message reflect the same value:

warnCount:=compiler.GetWarningCount()
ifwarnCount!=0 {
t.Errorf(&quot;Expectedwarningcounttobe0, got%d&quot;, warnCount)
}

While GetWarningCount() is likely a pure read t…

pkg/workflow/dispatch_repository_validation.go:489

Error prefix dispatch_repository: (snake_case) is inconsistent with the now-canonical kebab-case key dispatch-repository — users reading this error will be confused about the correct spelling.

<details>
<summary>💡 Suggested fix</summary>

Change the error prefix to match the canonical key in all error messages in this file:

// before&quot;dispatch_repository: mustspecifyatleastonedispatchtool...&quot;
// after&quot;dispatch-repository: mustspecifyatleastonedispatchtool...&quot;

pkg/parser/schemas/main_workflow_schema.json:188

anyOf required-field validation allows a config with neitherevent-type nor event_type to pass schema validation if other anyOf branches are added in the future — the current structure is also semantically misleading.

<details>
<summary>💡 Suggested fix</summary>

The anyOf enforces that at least one ofevent-type or event_type is present. This is correct for backward compatibility. However, consider using oneOf or documenting that both-present is valid (canonical wins)…

@github-actions
github-actionsBot deleted the copilot/deep-report-rename-nested-keys branch July 19, 2026 03:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[deep-report] Rename dispatch-repository nested keys to kebab-case (event_type, allowed_repositories)

3 participants

@pelikhan