Skip to content

Flag outside contributions on the triage board — first-time contributors' PRs are the items rotting longest #98

Description

@silug

Problem

Outside contributions are the items on the Org Triage board that most need a timely human response — they often arrive without an accompanying issue, and a drive-by PR is frequently how a bug reaches us at all. They are also, measurably, the items the board is worst at surfacing.

Of the 48 PRs on the board (checked 2026-08-27), 8 are outside contributions and 5 are from first-time contributors. The rot is concentrated in exactly that group:

PR Author author_association Board status Days since update
pupmod-simp-simplib#233 jcpunk CONTRIBUTOR No Status 2170
pupmod-simp-simplib#234 jcpunk CONTRIBUTOR No Status 1826
pupmod-simp-rsync#90 greatflyingsteve FIRST_TIME_CONTRIBUTOR In Progress 1470
pupmod-simp-rsync#91 greatflyingsteve FIRST_TIME_CONTRIBUTOR In Progress 1470
pupmod-simp-rsyslog#162 dforste FIRST_TIME_CONTRIBUTOR
pupmod-simp-at#99 janbrono FIRST_TIME_CONTRIBUTOR
pupmod-simp-sssd#198 seriv FIRST_TIME_CONTRIBUTOR
pupmod-simp-simplib#290 dforste CONTRIBUTOR

The two oldest no-status items on the entire board are outside PRs (~5 and ~6 years), and the longest-stalled pair in "In Progress" is a first-time contributor's. Nothing on the board distinguishes them from the 40 MEMBER-authored PRs they're filed among, so there is no way to sweep for "outside work waiting on us."

Proposed change

Have the triage workflow label outside contributions on arrival, so the board's existing Labels field surfaces them and they can be filtered into a saved view.

      - name: Flag outside contributions
        if: >-
          github.event_name == 'pull_request_target' &&
          contains(fromJSON('["FIRST_TIME_CONTRIBUTOR","CONTRIBUTOR","NONE"]'),
                   github.event.pull_request.author_association)
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh pr edit "${{ github.event.pull_request.number }}" --add-label external-contributor

Then add an External view on the board filtered to that label, and make "has an outside contributor waiting" a thing that can be answered at a glance rather than by querying the API.

Prerequisite: the label does not exist yet

Sampled repos (simplib, rsync, at) carry only GitHub's defaults — bug, duplicate, enhancement, help wanted, invalid, question, wontfix. There is no external-contributor label anywhere, and gh pr edit --add-label fails if the label is absent, so this needs a fleet-wide label creation first — which is itself a puppetsync-shaped task (labels aren't currently part of the managed baseline at all).

Options, roughly in order of preference:

  1. Create the label fleet-wide as part of this change, and consider whether a managed label set belongs in the baseline generally.
  2. Create-if-missing in the workflow (gh label create external-contributor --force) — self-healing, at the cost of an extra API call on every outside PR.
  3. Skip labels, and set a board field via the GraphQL API instead. Avoids the label problem but needs the project item ID and a token with project scope; more moving parts.

Notes

  • author_association values worth catching are FIRST_TIME_CONTRIBUTOR, CONTRIBUTOR, and NONE. MEMBER, OWNER, and COLLABORATOR are the internal cases. (CONTRIBUTOR means they've had a PR merged before but aren't org members — still outside, and the two 5-year-old simplib PRs above are exactly that.)
  • The existing workflow does not check out any code, which is what makes its use of pull_request_target safe. This addition must preserve that — it only reads event metadata and calls the API. Do not add a checkout of the PR head.
  • Labeling needs pull-requests: write; the default GITHUB_TOKEN under pull_request_target has it, so AUTO_TRIAGE_TOKEN isn't required for this step.
  • A follow-on worth considering separately: a scheduled staleness sweep that pings when anything labeled external-contributor goes untouched for N days. The table above is the argument for it.

Related

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