From a667744ab1e2c230be75bb660ba5d99ca3219098 Mon Sep 17 00:00:00 2001 From: Sasa Junuzovic Date: Thu, 19 Mar 2026 22:48:41 -0700 Subject: [PATCH 1/4] fix: use target: ${{ inputs.pr_number }} for quality gate safe outputs The submit_pull_request_review safe output doesn't support target: "*" because its schema has no pull_request_number field. Per gh-aw docs, the correct approach for workflow_dispatch is to set target to the actual input value: ${{ inputs.pr_number }}. Fixes #168 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/quality-gate.lock.yml | 12 ++++++------ .github/workflows/quality-gate.md | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/quality-gate.lock.yml b/.github/workflows/quality-gate.lock.yml index bbbb403..b4d26ca 100644 --- a/.github/workflows/quality-gate.lock.yml +++ b/.github/workflows/quality-gate.lock.yml @@ -22,7 +22,7 @@ # For more information: https://github.github.com/gh-aw/introduction/overview/ # # -# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"60b4615ad157c90c645c083aa4d397b8ccbd63a66cf2caf1bf4a61ce4baf8215","compiler_version":"v0.60.0","strict":true} +# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"0b1e84693c9ae3b74ffc39a9e7fe469e500a67902c50ddbac1ad62241fad4305","compiler_version":"v0.60.0","strict":true} name: "Quality Gate" "on": @@ -319,16 +319,16 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' - {"add_comment":{"max":1,"target":"*"},"add_labels":{"max":3,"target":"*"},"close_pull_request":{"github-token":"${{ secrets.GH_AW_WRITE_TOKEN }}","max":1,"target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1},"submit_pull_request_review":{"max":1}} + {"add_comment":{"max":1,"target":"${{ inputs.pr_number }}"},"add_labels":{"max":3,"target":"${{ inputs.pr_number }}"},"close_pull_request":{"github-token":"${{ secrets.GH_AW_WRITE_TOKEN }}","max":1,"target":"${{ inputs.pr_number }}"},"missing_data":{},"missing_tool":{},"noop":{"max":1},"submit_pull_request_review":{"max":1}} GH_AW_SAFE_OUTPUTS_CONFIG_EOF - name: Write Safe Outputs Tools run: | cat > /opt/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF' { "description_suffixes": { - "add_comment": " CONSTRAINTS: Maximum 1 comment(s) can be added. Target: *.", - "add_labels": " CONSTRAINTS: Target: *.", - "close_pull_request": " CONSTRAINTS: Maximum 1 pull request(s) can be closed. Target: *.", + "add_comment": " CONSTRAINTS: Maximum 1 comment(s) can be added. Target: ${{ inputs.pr_number }}.", + "add_labels": " CONSTRAINTS: Target: ${{ inputs.pr_number }}.", + "close_pull_request": " CONSTRAINTS: Maximum 1 pull request(s) can be closed. Target: ${{ inputs.pr_number }}.", "submit_pull_request_review": " CONSTRAINTS: Maximum 1 review(s) can be submitted." }, "repo_params": {}, @@ -1033,7 +1033,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"*\"},\"add_labels\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"target\":\"*\"},\"close_pull_request\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"submit_pull_request_review\":{\"footer\":\"always\",\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"*\"}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"},\"add_labels\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"target\":\"${{ inputs.pr_number }}\"},\"close_pull_request\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"},\"missing_data\":{},\"missing_tool\":{},\"submit_pull_request_review\":{\"footer\":\"always\",\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/quality-gate.md b/.github/workflows/quality-gate.md index 3985a44..6afc44f 100644 --- a/.github/workflows/quality-gate.md +++ b/.github/workflows/quality-gate.md @@ -28,18 +28,18 @@ safe-outputs: report-as-issue: false submit-pull-request-review: max: 1 - target: "*" + target: ${{ inputs.pr_number }} footer: "always" github-token: ${{ secrets.GH_AW_WRITE_TOKEN }} close-pull-request: max: 1 - target: "*" + target: ${{ inputs.pr_number }} github-token: ${{ secrets.GH_AW_WRITE_TOKEN }} add-comment: - target: "*" + target: ${{ inputs.pr_number }} github-token: ${{ secrets.GH_AW_WRITE_TOKEN }} add-labels: - target: "*" + target: ${{ inputs.pr_number }} github-token: ${{ secrets.GH_AW_WRITE_TOKEN }} --- From 39a0a4a7702227c0ffd70fc32e2c265528be183c Mon Sep 17 00:00:00 2001 From: Sasa Junuzovic Date: Thu, 19 Mar 2026 23:00:10 -0700 Subject: [PATCH 2/4] fix: use target: "*" for add_labels, target: pr_number for review/close/comment add_labels needs target: "*" because its handler resolves the PR from item_number in the agent output. submit_pull_request_review, close_pull_request, and add_comment use target: ${{ inputs.pr_number }} which the handler resolves directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/quality-gate.lock.yml | 8 ++++---- .github/workflows/quality-gate.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/quality-gate.lock.yml b/.github/workflows/quality-gate.lock.yml index b4d26ca..dbcf3d3 100644 --- a/.github/workflows/quality-gate.lock.yml +++ b/.github/workflows/quality-gate.lock.yml @@ -22,7 +22,7 @@ # For more information: https://github.github.com/gh-aw/introduction/overview/ # # -# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"0b1e84693c9ae3b74ffc39a9e7fe469e500a67902c50ddbac1ad62241fad4305","compiler_version":"v0.60.0","strict":true} +# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"9065f7641c6a8a15be280ac5bba1b5ab2bb0013c35a17e4d9c87058357b704da","compiler_version":"v0.60.0","strict":true} name: "Quality Gate" "on": @@ -319,7 +319,7 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' - {"add_comment":{"max":1,"target":"${{ inputs.pr_number }}"},"add_labels":{"max":3,"target":"${{ inputs.pr_number }}"},"close_pull_request":{"github-token":"${{ secrets.GH_AW_WRITE_TOKEN }}","max":1,"target":"${{ inputs.pr_number }}"},"missing_data":{},"missing_tool":{},"noop":{"max":1},"submit_pull_request_review":{"max":1}} + {"add_comment":{"max":1,"target":"${{ inputs.pr_number }}"},"add_labels":{"max":3,"target":"*"},"close_pull_request":{"github-token":"${{ secrets.GH_AW_WRITE_TOKEN }}","max":1,"target":"${{ inputs.pr_number }}"},"missing_data":{},"missing_tool":{},"noop":{"max":1},"submit_pull_request_review":{"max":1}} GH_AW_SAFE_OUTPUTS_CONFIG_EOF - name: Write Safe Outputs Tools run: | @@ -327,7 +327,7 @@ jobs: { "description_suffixes": { "add_comment": " CONSTRAINTS: Maximum 1 comment(s) can be added. Target: ${{ inputs.pr_number }}.", - "add_labels": " CONSTRAINTS: Target: ${{ inputs.pr_number }}.", + "add_labels": " CONSTRAINTS: Target: *.", "close_pull_request": " CONSTRAINTS: Maximum 1 pull request(s) can be closed. Target: ${{ inputs.pr_number }}.", "submit_pull_request_review": " CONSTRAINTS: Maximum 1 review(s) can be submitted." }, @@ -1033,7 +1033,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"},\"add_labels\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"target\":\"${{ inputs.pr_number }}\"},\"close_pull_request\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"},\"missing_data\":{},\"missing_tool\":{},\"submit_pull_request_review\":{\"footer\":\"always\",\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"},\"add_labels\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"target\":\"*\"},\"close_pull_request\":{\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"},\"missing_data\":{},\"missing_tool\":{},\"submit_pull_request_review\":{\"footer\":\"always\",\"github-token\":\"${{ secrets.GH_AW_WRITE_TOKEN }}\",\"max\":1,\"target\":\"${{ inputs.pr_number }}\"}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/quality-gate.md b/.github/workflows/quality-gate.md index 6afc44f..cf48ae7 100644 --- a/.github/workflows/quality-gate.md +++ b/.github/workflows/quality-gate.md @@ -39,7 +39,7 @@ safe-outputs: target: ${{ inputs.pr_number }} github-token: ${{ secrets.GH_AW_WRITE_TOKEN }} add-labels: - target: ${{ inputs.pr_number }} + target: "*" github-token: ${{ secrets.GH_AW_WRITE_TOKEN }} --- From c41a974e29e97b514df1d4c95ba7edced8e962cc Mon Sep 17 00:00:00 2001 From: Sasa Junuzovic Date: Thu, 19 Mar 2026 23:52:25 -0700 Subject: [PATCH 3/4] feat: enable 5-minute cron on orchestrator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Public repo — Actions minutes are unlimited and free. Cron catches new aw-labeled issues when the pipeline is idle and no event-driven triggers are firing. Part of #135 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/pipeline-orchestrator.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pipeline-orchestrator.yml b/.github/workflows/pipeline-orchestrator.yml index 31d2107..3a6fae0 100644 --- a/.github/workflows/pipeline-orchestrator.yml +++ b/.github/workflows/pipeline-orchestrator.yml @@ -32,9 +32,8 @@ on: required: false type: string - # Cron disabled until testing complete — uncomment when ready - # schedule: - # - cron: "*/5 * * * *" + schedule: + - cron: "*/5 * * * *" concurrency: group: pipeline-orchestrator From 61de2e39c41c02007be5dc99369a358bcdf88cce Mon Sep 17 00:00:00 2001 From: Sasa Junuzovic Date: Thu, 19 Mar 2026 23:52:35 -0700 Subject: [PATCH 4/4] docs: update changelog and agentic-workflows for quality gate dispatch + cron - Changelog: quality gate fix, safe output target lessons, cron enable - Pitfall #18: updated with target: ${{ inputs.pr_number }} guidance - Pitfall #21: safe output target values differ by handler type - History: 2026-03-19/20 entry (autonomous PRs, quality gate fix, cron) - Agent table: quality gate trigger updated, orchestrator triggers updated Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/agentic-workflows.md | 20 +++++++++++++++++--- docs/changelog.md | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/agentic-workflows.md b/docs/agentic-workflows.md index 2a7a3a6..21774f7 100644 --- a/docs/agentic-workflows.md +++ b/docs/agentic-workflows.md @@ -474,7 +474,7 @@ When agents post comments or replies using `GH_AW_WRITE_TOKEN` (a PAT), the comm Adding `if: "contains(github.event.pull_request.labels.*.name, 'aw')"` to a workflow's frontmatter compiles to a job-level `if:` on the activation job. When the condition is false, the workflow skips entirely at the GitHub Actions level — zero tokens burned, no agent activation. This is fundamentally different from checking labels in the agent prompt (which still activates the agent, burns compute, then noops). ### 18. Safe output `target` config determines PR context resolution -Safe outputs like `reply-to-pull-request-review-comment` and `push-to-pull-request-branch` default to `target: "triggering"`, which looks up the PR from `github.event.pull_request`. This only works with event-based triggers (`pull_request_review`, `pull_request`). With `workflow_dispatch`, there is no PR in the event context and safe outputs fail with "not running in a pull request context." Fix: set `target: "*"` in the safe output config — the agent includes `pull_request_number` in each message. Also requires `checkout: { fetch: ["*"], fetch-depth: 0 }` for push operations. Use `labels: [aw]` to restrict which PRs can receive pushes. +Safe outputs like `reply-to-pull-request-review-comment` and `push-to-pull-request-branch` default to `target: "triggering"`, which looks up the PR from `github.event.pull_request`. This only works with event-based triggers (`pull_request_review`, `pull_request`). With `workflow_dispatch`, there is no PR in the event context and safe outputs fail with "not running in a pull request context." Fix: set `target: "*"` for handlers whose schema includes a PR/issue number field (like `add-labels` with `item_number`, `reply-to-pull-request-review-comment` with `comment_id`). For handlers without a number field (like `submit-pull-request-review`), use `target: ${{ inputs.pr_number }}` to pass the PR number directly. Also requires `checkout: { fetch: ["*"], fetch-depth: 0 }` for push operations. Use `labels: [aw]` to restrict which PRs can receive pushes. ### 19. `pull_request_review` trigger fires on ALL review submissions The `pull_request_review` trigger fires when ANY actor submits a review — not just the intended reviewer. Combined with `roles: all` (workaround for gh-aw#21098), this means Copilot reviews, quality gate approvals, and human comments ALL trigger the workflow. This caused infinite loops: responder fires → pushes → Copilot reviews → responder fires again. Fix: use `workflow_dispatch` instead and have the orchestrator decide when to run the responder. @@ -482,6 +482,9 @@ The `pull_request_review` trigger fires when ANY actor submits a review — not ### 20. Don't over-specify agent instructions The responder originally worked with simple instructions: "Read the unresolved review comment threads" and "Reply to the comment thread." Adding explicit `gh api graphql` queries, ordering constraints, and MCP avoidance notes broke the agent's ability to discover threads. The agent is capable of figuring out how to read threads on its own — telling it exactly which API to use interfered with that. +### 21. Safe output `target` values differ by handler type +Not all safe output handlers resolve `target` the same way. `submit-pull-request-review` with `target: "*"` fails because its tool schema has no `pull_request_number` field — the agent can't specify which PR to review. Use `target: ${{ inputs.pr_number }}` instead (per gh-aw docs). Meanwhile, `add-labels` works with `target: "*"` because its schema has `item_number`. When using `workflow_dispatch`, check each handler's schema to pick the right `target` value. Don't assume one value works for all. + --- @@ -535,8 +538,8 @@ gh run view --log-failed # View failed job logs | `issue-implementer.md` | `workflow_dispatch` (issue number) | Implement fix from issue spec, open PR | `create-pull-request` (draft: false, auto-merge), `push-to-pull-request-branch` | | `ci-fixer.md` | `workflow_dispatch` (PR number) | Fix CI failures on agent PRs | `push-to-pull-request-branch`, `add-labels`, `add-comment` | | `review-responder.md` | `pull_request_review` (moving to `workflow_dispatch`) | Address review comments | `push-to-pull-request-branch`, `reply-to-pull-request-review-comment`, `add-labels` | -| `quality-gate.md` | `pull_request_review` | Evaluate quality + blast radius, approve or close | `submit-pull-request-review`, `close-pull-request`, `add-comment`, `add-labels` | -| `pipeline-orchestrator.yml` | `workflow_run` / `push` / `workflow_dispatch` | Resolve threads, rebase PRs | N/A (bash, not gh-aw) | +| `quality-gate.md` | `workflow_dispatch` | Evaluate quality + blast radius, approve or close | `submit-pull-request-review`, `close-pull-request`, `add-comment`, `add-labels` | +| `pipeline-orchestrator.yml` | `workflow_run` / `push` / `pull_request_review` / `workflow_dispatch` | Dispatch implementer/ci-fixer/responder/quality-gate, resolve threads, rebase PRs | N/A (bash, not gh-aw) | ### Loop prevention @@ -661,6 +664,17 @@ The enhanced PR rescue (#116) went through three complete rewrites: - Issues closed: #89 (quality gate close), #88 (gh-aw outdated), #117 (thread resolution), #66 (code quality cleanups via PR #113). - **Key insight**: Bash orchestrator in 7 seconds vs gh-aw agent in 7-10 minutes. Same logic, 60x faster. +### 2026-03-19/20 — Quality gate dispatch fix + first fully autonomous PR cycle + +- PR #163: Merged orchestrator v3 + responder fix + ci-fixer fix + label renames. All tested on sandbox PRs before merge. +- PR #162: **First fully autonomous PR merge.** Issue #60 → implementer created PR → Copilot reviewed (4 comments) → responder addressed all 4 → threads auto-resolved → quality gate approved → auto-merge. Zero human intervention. +- PR #166: Second autonomous merge (issue #126). Responder addressed 1 comment, quality gate approved. +- PR #167: Exposed the quality gate happy-path bug. CI green, Copilot review clean (0 comments), but quality gate never fired because `pull_request_review` trigger has a bot filter that blocks Copilot-submitted reviews. +- PRs #169, #170: Fixed quality gate — switched to `workflow_dispatch`, orchestrator dispatches it. PR #170 was emergency fix after manually editing the lock file instead of running `gh aw compile` (broke frontmatter hash). +- Discovered `submit_pull_request_review` safe output doesn't support `target: "*"` — no `pull_request_number` field in tool schema. Fix: use `target: ${{ inputs.pr_number }}` per gh-aw docs. `add_labels` uses `target: "*"` (different handler, has `item_number` field). +- PR #167 eventually merged after testing the fix from branch via `gh workflow run --ref`. +- Enabled 5-minute cron on orchestrator. Public repo — Actions minutes are unlimited. Cron catches new issues when pipeline is idle. Closes #135. + ### 2026-03-17/18 — Orchestrator v3 attempt, responder investigation, revert - PR #144: Merged orchestrator v3 (issue dispatch, cron, review loop) + docs + daily test-analysis. Not adequately tested before merge. diff --git a/docs/changelog.md b/docs/changelog.md index 5a138dc..5a54897 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,23 @@ Append-only history of repo-level changes (CI, infra, shared config). Tool-speci --- +## fix: quality gate dispatch + review approval + cron — 2026-03-19/20 + +**Problem**: The quality gate workflow triggered on `pull_request_review: submitted`, but the gh-aw pre-activation job filters out bot-submitted reviews. Since the autonomous pipeline has no human reviewers, the quality gate never fired — clean PRs (green CI, no review comments) sat open indefinitely. Example: PR #167 was stuck for 30+ minutes. + +**Fix (PRs #169, #170, this PR)**: +1. Switched quality gate trigger from `pull_request_review` to `workflow_dispatch` with `pr_number` input. +2. Added Step 4 to orchestrator: when CI green + 0 open threads → dispatch quality gate. +3. Added `aw-quality-gate-evaluated` label to prevent re-dispatch loops for HIGH impact PRs. +4. Fixed `submit_pull_request_review` safe output: `target: "*"` doesn't work because the tool schema has no `pull_request_number` field. Per gh-aw docs, the correct approach for `workflow_dispatch` is `target: ${{ inputs.pr_number }}`. Labels use `target: "*"` (different handler, resolves via `item_number` from agent output). +5. Enabled 5-minute cron on orchestrator. Public repo — Actions minutes are unlimited. Cron catches new `aw`-labeled issues when the pipeline is idle and no event-driven triggers are firing. Closes #135. + +**Lesson**: Lock files are auto-generated — always edit the `.md` and run `gh aw compile`. Manually editing the lock file breaks the frontmatter hash validation (PR #170 was an emergency fix for this). + +**Lesson**: Each safe output handler resolves PR context differently. `submit_pull_request_review` needs an explicit target number. `add_labels` needs `target: "*"` with `item_number` in agent output. Read the gh-aw docs for each handler before configuring. + +--- + ## revert: undo orchestrator v3, responder changes, and trigger disable — 2026-03-18 **Problem**: Three PRs were merged to main without adequate testing, creating cascading failures: