simp / simp/puppetsync

Automate board Status with a scheduled reconciler in gha-workflows (member PRs only; add an In Review column)

Open
#99 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
1
Forks
5
Avg merge
8d 1h
Merged PRs (30d)
4

Description

Goal

Keep the Org Triage board Status column accurate without hand-dragging cards: draft PRs and issues with an open PR land in In Progress, PRs awaiting review land in a new In Review column — and only for simp org members, so outside contributions stay in the triage queue until a human looks at them.

What the built-in project workflows can't do

Projects v2 built-ins are trigger → set-a-field, with no conditions. Member-gating is therefore impossible with them, which settles the architecture: this needs Actions + the GraphQL API regardless of anything else.

They also have no trigger for draft↔ready-for-review transitions, and none for "this issue gained a linked PR."

(The board currently has 5 built-ins enabled: Auto-archive items, Item added, Item closed, Item reopened, Pull request merged. The catalog also includes Code review approved and Code changes requested, which aren't in the list — worth enabling in the UI regardless, but they can't be member-gated either.)

How many columns this actually justifies

Review state of all 48 PRs on the board, measured 2026-08-27:

State Count
Ready, awaiting review 30
Draft 16
Approved, unmerged 2
Changes requested 0

So one new column, In Review. "Approved but unmerged" is 2 transient items and doesn't justify board machinery — is:pr is:open review:approved org:simp answers it natively as a saved search.

Proposed mapping

Member = author_association ∈ {MEMBER, OWNER, COLLABORATOR} — the same signal as #98, inverted.

Condition Status
Member PR, draft In Progress
Member PR, ready, review required In Review
Member PR, changes requested In Progress
Member PR, approved In Review (saved search covers it)
Issue with a linked member PR In Progress
Outside PR untouched — stays in New

Leaving outside PRs alone matters for a second reason beyond the org-member rule: a drive-by draft marked "In Progress" would falsely imply we are working it, and it would leave the triage queue without anyone having looked at it. Those should sit in New with the external-contributor label from #98.

The automation must also refuse to move anything out of Blocked or Parked (if those columns get added), or it will fight deliberate placements.

Architecture: a scheduled reconciler, not per-repo event handlers

Recommended shape: one scheduled workflow in simp/gha-workflows that walks the board's items, computes the desired Status from each item's live PR state and author association, and updates only the mismatches.

Why not event-driven workflows in each repo:

  • It would be another file copied into ~88 repos, with the same drift and coverage failure modes as #84, #96, and #97.
  • A reconciler is idempotent — a missed or failed event self-heals on the next pass instead of leaving an item permanently wrong.
  • It covers repos outside the sync set for free, which is the exact blind spot #96 is about.
  • It's one file to change when the column set changes.

Trade-off is latency. A 15-minute schedule seems fine for a triage board; event-driven nudges can be added later without changing the reconciler.

Does this need a per-repo stub?

The reconciler itself does not. It's a scheduled workflow reading the org project through the API — it never runs in the module repos, so there is nothing to call it from. This is unlike create_release_tag.yml, where the per-repo stub exists because the trigger (workflow_dispatch in that repo) has to originate there.

A stub is only needed if we also want instant updates on PR events, since those events only fire in the repo that owns the PR. That would be a thin caller in the established style:

# NOTICE: **This file is maintained with puppetsync**
---
name: 'Triage: sync board status'
on:
  pull_request_target:
    types: [opened, reopened, converted_to_draft, ready_for_review]
  pull_request_review:
    types: [submitted]
jobs:
  sync-status:
    uses: simp/gha-workflows/.github/workflows/triage_sync_board_status.yml@v1.0.0
    secrets: inherit

Suggested order: ship the reconciler first with no stubs at all, run it for a couple of weeks, and only add the per-repo layer if the schedule latency actually proves annoying. That keeps 88 files out of the picture unless they earn their place.

Mechanics

IDs are stable:

project:      PVT_kwDOALnDas4ANYjr
Status field: PVTSSF_lADOALnDas4ANYjrzgIin5o
options:      New 62562ffa · Todo f75ad846 · In Progress 47fc9ee4 · Done 98236657

In Review (and Blocked/Parked, if adopted) must be created first and will have new option IDs — the reconciler should look options up by name at runtime rather than hardcoding them, so a renamed or re-created column doesn't silently break it.

Reads: organization.projectV2.items with content{... on PullRequest{isDraft reviewDecision authorAssociation closingIssuesReferences}} — everything needed comes back in one paginated query. Writes: updateProjectV2ItemFieldValue. The token needs project scope; AUTO_TRIAGE_TOKEN presumably qualifies already, since add-to-project works with it.

reviewDecision is null (not REVIEW_REQUIRED) when no review has been requested — handle that case explicitly rather than treating null as "needs review."

Depends on

The column set. This proposal assumes In Review gets added; the mapping table also references Blocked/Parked from the wider board-reorganization discussion. Worth settling those before writing the reconciler, since the mapping is only as good as the columns it targets.

Related

  • #96, #97, #98 — the other triage-board changes. Those three all touch the per-repo add_new_issue_to_triage_project.yml; this one deliberately does not.
  • #85 — the workflow_call migration and simp/gha-workflows, which is where this code would live.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in simp/gha-workflows and review #85 before choosing the scheduled workflow entry point, including the proposed triage_sync_board_status.yml name. Confirm the project, Status field, option lookup, GraphQL reads, and updateProjectV2ItemFieldValue write path. Done means the reconciler handles member PR states, linked member PRs, null reviewDecision, and preserves outside, Blocked, and Parked items after In Review and any other columns are settled.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, graphql
Domain
ci-cd, devops, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.