Skip to content

create-issue: deduplicate-by-title is parsed but never emitted to the handler config #43038

Description

@zkoppert

Summary

The create-issue safe output accepts a deduplicate-by-title option, but the compiler parses it into the config struct and then never emits it into the runtime handler config. As a result the option is silently ignored: it has no effect at runtime, and the compiler reports no error or warning. Sibling options like close-older-issues and group-by-day work correctly, which makes the gap easy to miss.

I hit this while adding a monthly scheduled workflow that opens one tracking issue per run. I wanted deduplicate-by-title to prevent duplicate issues on manual re-runs, and discovered the setting compiles away with no diagnostic.

Reproduction

Minimal workflow (.github/workflows/dedup-repro.md):

---
name: Dedup Repro
description: minimal repro
on:
  workflow_dispatch:
permissions:
  contents: read
  issues: read
engine:
  id: copilot
  model: gpt-5-mini
timeout-minutes: 10
safe-outputs:
  create-issue:
    title-prefix: "Repro - "
    max: 1
    deduplicate-by-title: true
    close-older-issues: true
---

# Dedup Repro

This body is only here to satisfy the compiler minimum length for the agent instructions section.

Compile it and inspect the emitted handler config:

$ gh aw compile dedup-repro
$ grep -oE '"create_issue":\{[^}]*\}' .github/workflows/dedup-repro.lock.yml
"create_issue":{"close_older_issues":true,"max":1,"title_prefix":"Repro - "}

close_older_issues is present, but deduplicate-by-title is absent from the emitted config. The same happens for deduplicate-by-title: 0 and deduplicate-by-title: 1.

Expected vs actual

  • Expected: the emitted create_issue handler config includes the deduplication setting (for example "deduplicate_by_title": true), so the runtime handler deduplicates by title as documented in safe-outputs.md.
  • Actual: the field is dropped from the emitted config with no error or warning, so deduplication never runs.

Root cause

I traced this in pkg/workflow. The field is declared on the config struct but is not wired into the emission path:

  • pkg/workflow/create_issue.go:20 declares DeduplicateByTitle any with the yaml tag deduplicate-by-title.
  • pkg/workflow/create_issue.go:37-38 passes the field lists that drive normalization and emission:
    BoolFields: []string{"close-older-issues", "group", "footer", "group-by-day"},
    IntFields:  []string{"max"},
    deduplicate-by-title is in neither list. Because it can be a boolean or a non-negative integer, it fits neither BoolFields nor IntFields cleanly.
  • pkg/workflow/create_entity_helpers.go:59-71 normalizes only the fields named in BoolFields and IntFields on the raw config map. Fields outside those lists are not carried into the emitted handler config.
  • A search of pkg/workflow/*.go (non-test) finds DeduplicateByTitle only at that struct declaration, with no reference in the config-generation code. By contrast, close-older-issues, group-by-day, footer, and max are all named in the field lists and do get emitted.

So the value is unmarshaled onto the struct and then never propagated to the runtime handler config.

Proposed fix and implementation plan

deduplicate-by-title accepts either a boolean (true for exact-title match) or a non-negative integer (edit distance), so it needs handling that neither BoolFields nor IntFields provides today.

  1. Add a normalization path for mixed boolean-or-integer fields (for example a BoolOrIntFields list in CreateParseOptions, or a dedicated preprocess step) in pkg/workflow/create_entity_helpers.go, so the raw value is normalized and preserved on the emitted config map.
  2. Register deduplicate-by-title through that path in parseCreateIssuesConfig (pkg/workflow/create_issue.go), so it is emitted as a stable key (for example deduplicate_by_title).
  3. Confirm the runtime handler in actions/setup/js reads that key and applies title deduplication for both the boolean and integer forms.
  4. Add a compiler test alongside the existing create-issue output tests (see pkg/workflow/compile_outputs_issue_test.go) asserting the emitted create_issue config contains the deduplication key for deduplicate-by-title: true, 0, and 1.
  5. Consider a validation error when the value is neither a boolean nor a non-negative integer, following the error template in CONTRIBUTING ([what's wrong]. [what's expected]. [example]).

As an interim guardrail, the compiler could warn when a schema-valid create-issue field is dropped from the emitted config, so silently-ignored options surface at compile time rather than at runtime.

Environment

  • Reproduced with gh aw extension v0.76.1.
  • Root cause traced against githubnext/gh-aw main (current v0.82.x), where the same field-list omission is present.

Metadata

Metadata

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions