fix(triage-panel): dispatch project-sync per themed issue#971
fix(triage-panel): dispatch project-sync per themed issue#971danielmeppiel merged 1 commit intomainfrom
Conversation
GitHub does not trigger downstream 'issues: labeled' workflows from label changes written under GITHUB_TOKEN. The Triage Panel's safe-outputs.add-labels applies theme/* labels under GITHUB_TOKEN, so project-sync.yml's listener silently no-op'd, leaving every panel-triaged issue off the PGS project board. Wire the panel through gh-aw's safe-outputs.dispatch-workflow channel: after applying any theme/* label, the agent dispatches project-sync.yml for that issue with its GraphQL node ID as the content_id input. Cap is max:10 (matches the per-sweep issue ceiling); gh-aw enforces a 5s delay between consecutive dispatches so worst-case latency add is ~50s/sweep. This preserves project-sync.yml as the sole project writer (one source of truth for label->field mapping in scripts/project/sync_item.py) and adds no new secrets - same security posture as the existing safe-outputs. Validated: gh aw compile triage-panel succeeded; lock.yml shows dispatch_workflow(max:10, workflows: [project-sync]). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes a production gap in the Triage Panel automation where applying theme/* labels via GITHUB_TOKEN does not trigger downstream issues: labeled workflows, preventing project-sync.yml from syncing themed issues into the PGS project board. It does so by explicitly dispatching project-sync via gh-aw safe-outputs for each themed issue.
Changes:
- Add
safe-outputs.dispatch-workflowconfiguration to the triage panel workflow source and update issue fetch JSON fields to include GraphQLid. - Regenerate the compiled workflow lockfile to include the new dispatch tool and required permissions.
- Add a changelog entry describing the fix.
Show a summary per file
| File | Description |
|---|---|
| CHANGELOG.md | Adds an Unreleased Fixed entry describing the dispatch-based fan-out workaround. |
| .github/workflows/triage-panel.md | Configures dispatch-workflow safe-output and documents when/how the agent should dispatch project-sync; adds id to gh issue queries. |
| .github/workflows/triage-panel.lock.yml | Recompiled workflow including dispatch tool wiring and actions: write permission for dispatching workflows. |
Copilot's findings
- Files reviewed: 3/3 changed files
- Comments generated: 2
| ### Fixed | ||
|
|
||
| - Fixed TLS validation failure behind corporate TLS-intercepting proxies and firewalls: `install/validation.py` now uses `requests` (honouring `REQUESTS_CA_BUNDLE`) instead of stdlib `urllib`, and surfaces a single CA-trust hint at default verbosity instead of a misleading auth error. (#911) | ||
| - Triage Panel themed issues now reach the PGS project board: the workflow dispatches `project-sync` per themed issue via the new `safe-outputs.dispatch-workflow` channel, working around GitHub's rule that `GITHUB_TOKEN`-driven label changes never fire downstream `issues: labeled` workflows. Without this, sweeps applied `theme/*` labels but the project-sync trigger silently no-op'd, leaving the board empty. |
There was a problem hiding this comment.
Changelog entries in this repo consistently end with the PR number in parentheses (e.g. "(#911)"). This new Fixed entry is missing the required "(#PR_NUMBER)" suffix, which will break the one-line-per-PR convention used throughout CHANGELOG.md.
| - Triage Panel themed issues now reach the PGS project board: the workflow dispatches `project-sync` per themed issue via the new `safe-outputs.dispatch-workflow` channel, working around GitHub's rule that `GITHUB_TOKEN`-driven label changes never fire downstream `issues: labeled` workflows. Without this, sweeps applied `theme/*` labels but the project-sync trigger silently no-op'd, leaving the board empty. | |
| - Triage Panel themed issues now reach the PGS project board: the workflow dispatches `project-sync` per themed issue via the new `safe-outputs.dispatch-workflow` channel, working around GitHub's rule that `GITHUB_TOKEN`-driven label changes never fire downstream `issues: labeled` workflows. Without this, sweeps applied `theme/*` labels but the project-sync trigger silently no-op'd, leaving the board empty. (#PR_NUMBER) |
| - **`dispatch_workflow` (project-sync)**: For every issue where you | ||
| added at least one `theme/*` label in this run, you MUST also call | ||
| `dispatch_workflow` with `workflow_name: "project-sync"` and inputs | ||
| `{"content_id": "<issue node id>"}` -- where `<issue node id>` is | ||
| the `id` field returned by `gh issue list --json id` / `gh issue | ||
| view --json id` (it looks like `I_kwDO...`, NOT the integer issue | ||
| number). This triggers the PGS project board sync for that issue. | ||
| It is required because gh-aw applies `add-labels` under | ||
| `GITHUB_TOKEN`, and GitHub does NOT fire downstream workflow events | ||
| from `GITHUB_TOKEN`-driven label changes -- so without this dispatch | ||
| the issue gets the right labels but never lands on the project | ||
| board. If you did NOT add any `theme/*` label (for example a | ||
| re-triage that only touches `status/*`), do NOT dispatch -- the | ||
| project-sync workflow only acts on themed items, so the dispatch | ||
| would be a no-op. Cap is 10 dispatches per run (matches sweep | ||
| ceiling); gh-aw enforces a 5s delay between consecutive dispatches. |
There was a problem hiding this comment.
The new dispatch guidance appears to describe calling a generic dispatch_workflow tool with workflow_name + inputs, but the compiled lockfile exposes a workflow-specific safe-output tool named project_sync that only accepts a content_id argument. Please align the instructions with the actual tool name/signature generated by gh-aw (and explicitly state that the dispatched content_id must come from the same issue(s) in BATCH_ALLOW_LIST to preserve the prompt-injection safety rail).
| - **`dispatch_workflow` (project-sync)**: For every issue where you | |
| added at least one `theme/*` label in this run, you MUST also call | |
| `dispatch_workflow` with `workflow_name: "project-sync"` and inputs | |
| `{"content_id": "<issue node id>"}` -- where `<issue node id>` is | |
| the `id` field returned by `gh issue list --json id` / `gh issue | |
| view --json id` (it looks like `I_kwDO...`, NOT the integer issue | |
| number). This triggers the PGS project board sync for that issue. | |
| It is required because gh-aw applies `add-labels` under | |
| `GITHUB_TOKEN`, and GitHub does NOT fire downstream workflow events | |
| from `GITHUB_TOKEN`-driven label changes -- so without this dispatch | |
| the issue gets the right labels but never lands on the project | |
| board. If you did NOT add any `theme/*` label (for example a | |
| re-triage that only touches `status/*`), do NOT dispatch -- the | |
| project-sync workflow only acts on themed items, so the dispatch | |
| would be a no-op. Cap is 10 dispatches per run (matches sweep | |
| ceiling); gh-aw enforces a 5s delay between consecutive dispatches. | |
| - **`project_sync`**: For every issue where you added at least one | |
| `theme/*` label in this run, you MUST also call the dedicated | |
| safe-output tool `project_sync` with only | |
| `content_id: "<issue node id>"` -- where `<issue node id>` is the | |
| `id` field for that same issue returned by `gh issue list --json id` | |
| / `gh issue view --json id` (it looks like `I_kwDO...`, NOT the | |
| integer issue number). Do NOT construct `content_id` from model | |
| output or copy it from any other issue, comment, or external source: | |
| the dispatched `content_id` MUST come from the same issue currently | |
| being processed, and therefore from the same issue set already | |
| admitted by `BATCH_ALLOW_LIST`. This triggers the PGS project board | |
| sync for that issue. It is required because gh-aw applies | |
| `add-labels` under `GITHUB_TOKEN`, and GitHub does NOT fire | |
| downstream workflow events from `GITHUB_TOKEN`-driven label changes | |
| -- so without this dispatch the issue gets the right labels but | |
| never lands on the project board. If you did NOT add any `theme/*` | |
| label (for example a re-triage that only touches `status/*`), do | |
| NOT dispatch -- the project-sync workflow only acts on themed | |
| items, so the dispatch would be a no-op. Cap is 10 dispatches per | |
| run (matches sweep ceiling); gh-aw enforces a 5s delay between | |
| consecutive dispatches. |
Live verification: merged fix works as designed (one nuance to flag)Verified the dispatch-workflow wiring against Test 1 — Fast path on a new theme application: PASSED [+]
The sibling Test 2 — Scheduled sweep on issues with pre-existing themes: PASSED with one design nuance to surfaceManually dispatched the panel sweep at 20:37:21Z. Run 24966483357 (
Agent log explicitly records the rationale: "No project-sync dispatches — no new The nuanceThis sweep happened to pick a population where every themed issue had been themed previously by a human (PAT-driven, which DID trigger project-sync at the time). So the live sweep didn't exercise the "agent applies brand-new theme inside a sweep" code path — Test 1 covered that for the fast path, and the same handler/dispatcher is used in both modes (one tools list, one safe-outputs config), so the code path is equivalent. If we ever observe a future issue that the panel themes for the first time and that issue ends up missing from the board, the prompt rule to revisit is: "dispatch on every triage-touched issue carrying a VerdictThe fix delivered in this PR works in production. Test 1 is a clean end-to-end proof: agent-applied theme on issue #841 produced a single Recommend: keep the worktree for one more sweep cycle to catch a sweep that themes a brand-new issue, then close out. No code change needed in the meantime. |
* chore(release): cut 0.9.4 CHANGELOG entry for 0.9.4 covers all 7 PRs merged since v0.9.3: - #974 SKILL_BUNDLE day-0 install parity (Added) - #954 automate apm-triage-panel workflow (Added) - #970 python-architect mermaid classDiagram trap (Changed) - #911 REQUESTS_CA_BUNDLE TLS validation (Fixed) - #971 triage-panel project-sync dispatch (Fixed) - #910 CLI consistency cleanup (Fixed) - #958 issue templates label taxonomy (Fixed) - #953 docs auto-deploy after bot-cut releases (Fixed) Open milestone 0.9.4 issues (41) reassigned to 0.9.5. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(changelog): tighten 0.9.4 entries (so-what for developers) Refactor per Keep-a-Changelog spirit: lead with developer impact, trim agent-internals prose, group maintainer-only changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(changelog): add #660 install.sh air-gapped entry to 0.9.4 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
TL;DR
The Triage Panel applies
theme/*labels but the PGS project board never gets the issues: GitHub does not fire downstreamissues: labeledworkflows when the label change was written underGITHUB_TOKEN, which is exactly whatsafe-outputs.add-labelsdoes. We had to manually backfill 46 issues into project #2304 after the first 7 sweeps. This PR wires the panel through gh-aw'ssafe-outputs.dispatch-workflowchannel so it dispatchesproject-sync.ymlper themed issue, restoring the trigger fan-out without introducing new secrets.Problem (WHY)
issues-event runs ofproject-sync.ymlfired in the sweep window — confirmed viagh run list --workflow=project-sync.yml. Project board stayed empty for newly-themed issues.GITHUB_TOKENto perform tasks, events triggered by theGITHUB_TOKENwill not create a new workflow run." gh-aw'ssafe-outputs.add-labelswrites labels viaGITHUB_TOKENby default, soproject-sync.yml'son: issues: labeledfilter sees nothing.gh workflow run project-sync.yml -f content_id=...once per themed issue is a manual rescue that has to happen after every sweep, indefinitely.Approach (WHAT)
Use gh-aw v0.68.3's
safe-outputs.dispatch-workflow— same security model asadd-labels(same-repo only, allowlisted workflow names, compile-time validated):dispatch-workflowfrom inside the paneladd-labels(broadens PAT blast radius);update-projectsafe-output (duplicates the label→field mapping that already lives insync_item.py); independent daily sweep workflow (extra moving piece)theme/*label was applied this runstatus/*-only re-triages); never (the bug stays)max: 10max: 1(default — too low for sweep mode);max: 50(gh-aw ceiling — wasteful, signals nothing)gh aw compile triage-paneland ship.lock.ymlin the same commitThe panel knows the GraphQL node ID for every issue it processes —
gh issue list --json idalready returns it in the formI_kwDO..., so the only data-flow change is addingidto the existing--jsonfield set.Implementation (HOW)
.github/workflows/triage-panel.mddispatch-workflow: { workflows: [project-sync], max: 10 }tosafe-outputs; extended bothgh issue list --json(SCHEDULED_SWEEP) andgh issue view --json(OPT_IN_RETRIAGE / MANUAL_DISPATCH) with theidfield; added a newdispatch_workflowbullet to the Output safety rails section that explains when to dispatch (only when ≥1theme/*was applied), what node ID format to use, and why the dispatch is required..github/workflows/triage-panel.lock.ymlgh aw compile triage-panel. Confirmeddispatch_workflow(max:10, workflows: [project-sync])appears in the tool list and handler config.CHANGELOG.md### Fixedbullet under[Unreleased]describing the symptom and the fan-out fix.No changes to
project-sync.yml— it already supportsworkflow_dispatchwith acontent_idinput, which is exactly what we used during the manual backfill.Sequence (what changes at runtime)
sequenceDiagram autonumber participant Sched as Cron 12:49 UTC participant Panel as Triage Panel<br/>(agent) participant SO as gh-aw safe-outputs<br/>handler participant Issues as Issues API participant Sync as project-sync.yml participant Board as PGS Project 2304 Sched->>Panel: schedule fire Panel->>Issues: gh issue list --json ...,id Issues-->>Panel: 10 candidates incl. node IDs Panel-->>SO: add_labels theme/*, area/*, ... Panel-->>SO: dispatch_workflow project-sync<br/>{ content_id: I_kwDO... } SO->>Issues: PATCH labels (under GITHUB_TOKEN) Note over Issues,Sync: GITHUB_TOKEN label event<br/>does NOT fan out SO->>Sync: workflow_dispatch (under GITHUB_TOKEN)<br/>5s rate-limit between dispatches Sync->>Board: sync_item.py --content-id ... Board-->>Sync: Theme/Area/Kind/Priority/Tier setNote
Step 7 (
workflow_dispatch) IS the fix. Theworkflow_dispatchevent type is one of the few events GitHub fans out even when triggered byGITHUB_TOKEN— that's whydispatch-workflowworks where letting the naturalissues: labeledevent do the work does not.Trade-offs
project-syncexplicitly. Acceptable: both workflows are repo-internal, both ship in this repo, and gh-aw compile-time validation rejects the workflow ifproject-sync.ymlever moves or loses itsworkflow_dispatchtrigger.MUSTin the Output safety rails section, paired with aMUST NOTfor the case where notheme/*was applied.max: 10. No headroom is wasted.Benefits
gh workflow runbackfill after every sweep.dispatch-workflowthe same way.project-sync.ymlremains the sole project writer — one source of truth for the label→field mapping inscripts/project/sync_item.py.Validation
The compiler cross-checks that
project-sync.ymlexists and declaresworkflow_dispatch— both true inmain.Manual backfill evidence (the bug this fixes)
After the 7-sweep manual drain on 2026-04-26, 46 themed issues were missing from project 2304. Running
gh workflow run project-sync.yml -f content_id=<node_id>once per issue produced 47 successful runs, all of which set Theme/Area/Kind/Priority/Tier as expected. Sample log for issue #944 confirmed full field population. This PR removes the need for that manual step.How to test
status/needs-triageto any open issue that lacks atheme/*label (fast-path trigger).theme/*label applied.workflow_dispatch(event column will readworkflow_dispatch, notissues).Tip
If you want to test the SCHEDULED_SWEEP path before the next 12:49 UTC fire, run
gh workflow run triage-panel.lock.yml(no inputs). It will pick up to 10 untriaged issues and dispatch project-sync for each themed one.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com