Skip to content

feat: add AI automation stack and OSS governance for open-source launch#55

Merged
EricAndrechek merged 15 commits into
mainfrom
feat/43-ai-code-review
Apr 21, 2026
Merged

feat: add AI automation stack and OSS governance for open-source launch#55
EricAndrechek merged 15 commits into
mainfrom
feat/43-ai-code-review

Conversation

@EricAndrechek

Copy link
Copy Markdown
Member

Summary

Prepares WaveHouse to go open source. Three tracks, one PR:

AI automation (four workflows)

  • Issue triage (triage.yml) — GitHub Models (gpt-4o-mini) classifies new / edited issues and applies area/*, security, and breaking-change labels. When PROJECT_BOARD_TOKEN is set, also writes the Priority field on Task Board docs: add initial Astro-based documentation site #7; soft-fails otherwise.
  • PR review — Claude (claude-review.yml) — auto-reviews PRs from OWNER / MEMBER / COLLABORATOR authors on open/push/ready-for-review. Sticky-comment mode; Dependabot and drafts skipped. Fork PRs from first-time contributors aren't auto-reviewed; a maintainer can invoke Claude by commenting @claude.
  • PR review — Gemini — Marketplace App installed separately, reads .gemini/styleguide.md. Runs alongside Claude; both advisory.
  • Agent (claude-agent.yml) — Claude makes code changes / opens PRs when a trusted actor mentions @claude in an issue / PR / review / comment, or applies the agent label to an issue.
  • Dependabot auto-merge (dependabot-automerge.yml) — auto-approves and auto-merges patch / minor bumps once CI passes. Major bumps get a comment and stay held for review. Workflow-path bumps still need a human codeowner per CODEOWNERS.

OSS governance

  • CODEOWNERS routes governance paths (LICENSE, SECURITY, AGENTS, workflows, release config) to admin review. No catch-all — routine code changes pick reviewers manually.
  • CLAUDE.md and .gemini/styleguide.md as thin pointers to AGENTS.md (single source of truth).
  • SECURITY.md updated to reflect JWKS auth, RBAC, raw-vs-structured SQL permission split, and supply-chain posture.
  • Conventional Commits PR-title linter (pr-title.yml) as an inline bash regex — no third-party action.
  • ISSUE_TEMPLATE/config.yml disables blank issues and routes security reports to the Security Policy.
  • PR template trimmed to Summary / Test plan / Related Issues; since the ruleset now makes the PR body the squash commit message, keeping it tight avoids polluting git log.
  • AGENTS.md extended with sections on the three automation tiers, governance files, and the rule that a new internal/ package requires a matching area/* label + a triage.yml area-list update.

Supply chain

  • All third-party GitHub Actions SHA-pinned with version comments (actions/checkout, actions/setup-go, golangci/golangci-lint-action, vladopajic/go-test-coverage, docker/login-action, goreleaser/goreleaser-action, plus the new AI-automation actions).
  • Dependabot extended to clients/ts (SDK) and tests/sdk (E2E) npm roots; previously only /site was covered.

Repository configuration (already applied directly, not part of this diff)

  • Ruleset main branch protection active: require PR + 1 approval + CODEOWNERS + 6 required status checks (Check, Lint, Test, Build, Integration Tests, Validate) + linear history + squash-only + restrict deletion/force-push.
  • Merge settings flipped: squash-only, auto-merge enabled, delete-branch-on-merge on, PR title→commit subject, PR body→commit message.
  • Label cleanup: renamed Observabilityarea/observability (preserves 17 closed issues), added 10 new area/* + agent + security + breaking-change, removed 3 unused hardware-org leftovers.
  • Repo description (was "BeachHouse"), topics, and homepage updated.

Test plan

  • CI passes: Check, Lint, Test, Build, Integration Tests, Validate
  • Status-check names in the ruleset actually match what CI reports — if any required check stays "pending", the name in the ruleset needs to be updated (likely the bare job name vs. CI / <name>)
  • claude-review.yml posts a review comment on this PR (sticky)
  • Gemini posts a review comment on this PR (if app is installed)
  • Admin reviewer (Taite) approves — needed because CODEOWNERS gates governance paths and author can't self-approve

Related Issues

Closes #43

EricAndrechek and others added 6 commits April 21, 2026 10:22
Prepares WaveHouse for open source: pointer files for Claude Code
(CLAUDE.md) and Gemini Code Assist (.gemini/styleguide.md) both deferring
to AGENTS.md; CODEOWNERS routing governance paths (LICENSE, AGENTS,
workflows, release config) to admin reviewers without a catch-all; and a
Conventional Commits PR-title linter implemented as an inline bash regex
so squash-merge commit messages on main stay parseable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pins actions/checkout, actions/setup-go, golangci/golangci-lint-action,
vladopajic/go-test-coverage, docker/login-action, and goreleaser-action
to full commit SHAs with version comments. Protects against
tag-retargeting supply-chain attacks. Dependabot tracks github-actions
and will open PRs bumping both the SHA and comment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the remaining two tiers of the AI automation stack:

- triage.yml: GitHub Models (gpt-4o-mini) classifies new/edited issues
  and applies area/*, security, breaking-change labels. Optional step
  writes the Priority field on Task Board #7 when PROJECT_BOARD_TOKEN
  is configured; soft-fails otherwise so label triage works out of the
  box.
- claude-agent.yml: anthropics/claude-code-action gated to
  OWNER/MEMBER/COLLABORATOR on @claude mention or `agent` label.
  Requires CLAUDE_CODE_OAUTH_TOKEN secret (see AGENTS.md).

OSS governance polish:

- ISSUE_TEMPLATE/config.yml disables blank issues and points security
  reports at the Security Policy.
- SECURITY.md updated to reflect JWKS support, role-based access
  control, structured-vs-raw SQL permissions, and supply-chain
  posture.
- AGENTS.md gains sections on the three automation tiers, governance
  files, and the rule that adding an internal/ package requires a
  matching area/* label and a triage.yml area-list update.

Both workflows use SHA-pinned actions per the supply-chain policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds claude-review.yml — anthropics/claude-code-action running in
PR-review mode on open/push/ready-for-review, gated to OWNER / MEMBER /
COLLABORATOR authors and skipping drafts and Dependabot PRs. Uses
sticky comments + progress tracking so repeat pushes update one
comment instead of spamming. Fork PRs from first-time contributors
aren't auto-reviewed here — a maintainer can invoke Claude on them via
`@claude` in claude-agent.yml.

Gemini Code Assist stays installed as a parallel reviewer. Both are
advisory; the ruleset + CODEOWNERS are the actual merge-gate.

AGENTS.md Tier 2 section updated to describe both reviewers and their
gating.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR template trimmed to Summary / Test plan / Related Issues. The
ruleset now sets squash_merge_commit_message=PR_BODY, so the body
becomes the commit message on main — keeping it tight avoids polluting
`git log` with unchecked checklist boxes.

Dependabot gains npm groups for clients/ts (TypeScript SDK) and
tests/sdk (E2E harness); previously only /site was covered. Weekly
grouped bumps prefixed `deps(sdk):` and `deps(tests):` keep PR titles
Conventional-Commits-compatible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dependabot-automerge.yml uses dependabot/fetch-metadata (SHA-pinned)
to classify the update, then auto-approves and enables auto-merge on
patch and minor bumps so they ship once CI passes with no human
touch. Major bumps get a comment and stay open for manual review
because they're most likely to break.

The ruleset still enforces required status checks and, for paths
under .github/workflows/, human codeowner approval — so
action-ecosystem bumps wait on a maintainer. gomod and npm bumps go
end-to-end without intervention.

AGENTS.md and CHANGELOG updated to document the flow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 14:53
EricAndrechek and others added 2 commits April 21, 2026 10:56
The multiline `if: |` form with `!github.event...` was evaluating to
false even when the PR met all criteria (author_association=MEMBER,
non-draft, non-dependabot). Switching to `>-` folded style with
explicit `== false` and `contains(fromJSON(...))` for the membership
check — semantically identical, less fragile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prepares WaveHouse for an open-source launch by adding repository governance files and multiple GitHub Actions workflows for AI-assisted triage/review, Dependabot auto-merge, PR-title linting, and supply-chain hardening (SHA-pinned actions).

Changes:

  • Added OSS governance scaffolding (CODEOWNERS, templates, security/contact routing, agent pointers) and updated core docs (AGENTS/CHANGELOG/SECURITY/CONTRIBUTING).
  • Introduced automation workflows: issue triage via GitHub Models, Claude PR review + Claude agent execution, Dependabot auto-merge, and PR-title Conventional Commits linting.
  • Pinned third-party Actions in CI/release to full commit SHAs and expanded Dependabot coverage to additional npm roots.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
SECURITY.md Updates security posture documentation (JWKS/RBAC/raw-vs-structured query + supply chain notes).
LICENSE Adjusts copyright holder formatting.
CONTRIBUTING.md Expands Conventional Commits type list and documents PR-title enforcement.
CLAUDE.md Adds pointer file to AGENTS.md as source of truth.
CHANGELOG.md Records governance + automation additions and supply-chain changes.
AGENTS.md Documents automation tiers, governance intent, and action pinning expectations.
.github/workflows/triage.yml Adds LLM-based issue triage + optional project Priority field update.
.github/workflows/release.yml Pins actions to SHAs; sets Go version for releases.
.github/workflows/pr-title.yml Adds Conventional Commits PR-title lint workflow.
.github/workflows/dependabot-automerge.yml Auto-approves/enables auto-merge for patch/minor Dependabot PRs.
.github/workflows/claude-review.yml Adds Claude-based automated PR review for trusted authors.
.github/workflows/claude-agent.yml Adds Claude agent workflow triggered by @claude / agent label.
.github/workflows/ci.yml Pins CI workflow actions to SHAs.
.github/dependabot.yml Extends Dependabot to /clients/ts and /tests/sdk npm directories.
.github/PULL_REQUEST_TEMPLATE.md Trims PR template; adds hidden author checklist aligned with squash-merge behavior.
.github/ISSUE_TEMPLATE/config.yml Disables blank issues and routes security reports to Security Policy.
.github/CODEOWNERS Adds governance-focused CODEOWNERS routing (no catch-all).
.gemini/styleguide.md Adds Gemini Code Assist styleguide pointing to AGENTS.md.

Comment thread .github/workflows/claude-agent.yml Outdated
Comment thread .github/workflows/claude-agent.yml Outdated
Comment thread .github/workflows/claude-review.yml
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/pr-title.yml Outdated
Comment thread .github/workflows/pr-title.yml

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request establishes a robust governance and automation framework for the repository. It introduces a CODEOWNERS file, standardized PR and issue templates, and a three-tiered automation system covering issue triage, automated code reviews, and agentic execution. Security is enhanced through SHA-pinned GitHub Actions and detailed documentation on JWT and RBAC policies. Review feedback highlights a documentation inconsistency regarding PR title enforcement and suggests improving the maintainability of the issue triage workflow by automating area label detection.

Comment thread CONTRIBUTING.md
Comment thread AGENTS.md
EricAndrechek and others added 4 commits April 21, 2026 10:59
Webhook payloads report users with *private* org membership as
CONTRIBUTOR, not MEMBER — even when the REST API reports MEMBER. This
was causing claude-review.yml to skip PRs opened by org members with
private Wave-RF membership visibility. Adding CONTRIBUTOR to the
allowlist across claude-review.yml and claude-agent.yml makes the
gate match the intended "trusted actor" set.

Tradeoff: CONTRIBUTOR applies to anyone who has previously had a
commit accepted, so the gate is slightly wider than MEMBER. For a
small OSS project this is acceptable; tighten by setting org
membership visibility to public if stricter MEMBER-only gating is
needed.

Also removes the temporary debug job that surfaced the mismatch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude-code-action needs an OIDC token to authenticate against the
Claude Code OAuth exchange; without id-token: write the action bails
with 'Could not fetch an OIDC token.' Matches the permission already
set in claude-agent.yml.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rsion from go.mod

Two small fixes flagged in PR review:

- pr-title.yml: regex now accepts the optional `!` breaking-change
  marker per Conventional Commits 1.0.0 (feat!: ..., feat(api)!: ...).
  Previously these valid titles would fail the Validate check.
- release.yml: actions/setup-go now reads go-version-file: go.mod
  instead of hard-coded 1.25, matching how ci.yml does it. Prevents
  release binaries diverging from CI builds when go.mod bumps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AGENTS.md gains a Review Response (MANDATORY) section mirroring the
Documentation & Consistency Sync pattern. Rule: every review comment
(human or AI) gets a substantive reply, threads are resolved before
merge, and cross-reviewer disagreements are argued with references.
The ruleset already enforces thread resolution as a required check,
so this just makes the expectation explicit in docs.

Addresses PR-55 review feedback:

- triage.yml: area list is now built dynamically from `area/*`
  repo labels (Gemini's suggestion). Adding a new `area/foo` label
  no longer requires a workflow edit — the classifier picks it up
  automatically. Backfilled all eleven `area/*` labels with
  meaningful descriptions that feed the classifier's per-area hint.
- claude-agent.yml: the `agent` label trigger now also gates on
  `github.event.sender.author_association` (Copilot's suggestion).
  Defense-in-depth on top of GitHub's existing label-write
  permission restriction.
- CHANGELOG.md: pr-title enforcement status corrected — it's a
  required ruleset check now, not advisory (Gemini's inconsistency
  catch against CONTRIBUTING.md).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@EricAndrechek EricAndrechek requested a review from taitelee April 21, 2026 15:58
EricAndrechek and others added 2 commits April 21, 2026 12:19
Addresses the "make the bots grumpy and thorough" ask across all three
surfaces. Sourced from industry-standard templates rather than invented
locally — Anthropic's pr-review-comprehensive for Claude, Google
Cloud Platform + AgentScope patterns for Gemini.

Claude (claude-review.yml):
- Prompt restructured to Anthropic's 5-area canonical template (Code
  Quality / Security / Performance / Testing / Documentation) with
  OWASP Top 10 severity rubric (CRITICAL/HIGH/MEDIUM/LOW/NONE), the
  noise-reduction filter from Anthropic's /review-pr slash command
  ("post only the feedback you also deem noteworthy"), and an
  explicit staff-engineer tone directive since Anthropic ships no
  upstream grumpy baseline.
- Review ends with Ship it / Iterate / Block verdict — Block reserved
  for CRITICAL/HIGH security, data-loss risk, or broken invariant.

Gemini (.gemini/):
- New config.yaml flips comment_severity_threshold from the default
  MEDIUM to LOW, unlocks unlimited comments, enables PR summary on
  open. Same pattern GoogleCloudPlatform/generative-ai ships.
- Rewritten styleguide.md follows the AgentScope [MUST]/[SHOULD]/
  [MAY] classification pattern with Correct/Incorrect code pairs, a
  WaveHouse-specific security walkthrough (ClickHouse SQL-injection,
  JWT/RBAC, secrets hygiene), and documentation-sync enforcement.
- Dialog: authors reply with @gemini-code-assist or /gemini to invite
  counter-replies; documented in the styleguide.

File-path auto-labeling:
- labeler.yml maps directories to area/* + dependencies / go /
  github_actions / documentation labels; label.yml runs actions/
  labeler on pull_request_target with sync-labels: true so PR labels
  follow the current diff.

PR-title sticky comment:
- pr-title.yml moved from pull_request to pull_request_target (safe:
  never checks out PR code, only reads event.pull_request.title) so
  fork PRs also get the helpful fix-it comment.
- On failure, posts or updates a sticky explanation of the format
  with examples; on pass, removes any prior sticky. Check still
  fails fast via exit 1 so the Validate required-check gates merge.

AGENTS.md:
- Review Response rule adds the mention-to-invite-counter-reply
  pattern: @claude / @gemini-code-assist when pushing back on a bot,
  so the dialog actually loops instead of going silent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switching to `pull_request_target` created a chicken-and-egg: GitHub
only fires `pull_request_target` for workflow files that already exist
on the default branch (security: base-repo permissions require a
trusted workflow definition). Since this PR is the one introducing
these workflows, they never fired — leaving the ruleset's required
`Validate` check stuck at "waiting for status to be reported" and
blocking merge.

Reverting to `pull_request`:
- pr-title.yml: check runs and reports correctly on this PR. Internal
  PRs still get the sticky comment. Fork PRs see the check's red X
  but don't get the comment (GITHUB_TOKEN is read-only on fork PRs).
  Comment steps now have `continue-on-error: true` so the check's
  exit code isn't masked by comment-write failures; a dedicated
  trailing step owns the `exit 1`.
- label.yml: same rationale — labels apply on internal PRs via
  pull_request; fork PRs silently skip.

Post-merge follow-up can switch back to `pull_request_target` for
fork-PR coverage, once these files exist on main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation github_actions Pull requests that update GitHub Actions code area/docs Documentation, site/, README area/infra CI, build, deploy, Docker, release labels Apr 21, 2026
@EricAndrechek EricAndrechek enabled auto-merge (squash) April 21, 2026 16:50
Adds a "CI & review automation" section to docs/development.md
covering everything a new contributor would bump into on their first
PR: the Conventional Commits title check, required status checks /
ruleset / squash-merge behavior, the three AI reviewers and how to
invoke each, the review-response discipline, issue triage, PR auto-
labeling, and the checklist for adding a new internal/<pkg>/ package
alongside its matching area/* label. Updates the Dependabot
subsection with the new clients/ts and tests/sdk ecosystems plus the
patch/minor auto-merge workflow behavior.

Most detail lives in AGENTS.md; the new section in development.md is
the contributor-facing pointer so people don't have to read the full
AGENTS.md to get going.

Closes the docs-sync gap noted in the review of #55.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@taitelee taitelee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR includes changes involving tiered automation and governance frameworks, formalizing contributor workflow. We are moving away from manual labeling and review to an agentic model where AI handles initial triage, style enforcement, and domain-specific code review.

Some key changes:

  1. Automation Infrastructure
  • Tier 1 (Triage): Configured .github/workflows/triage.yml using gpt-4o-mini to classify issues with area/* labels and security flags.
  • Tier 2 (Reviewers): Integrated Claude (via GitHub Action) and Gemini Code Assist (via Styleguide) to provide advisory concurrency and SQL injection checks.
  • Tier 3 (Execution): Initialized @claude agentic capabilities via .github/workflows/claude-agent.yml for manual invocation.
  1. Governance and Process
  • AGENTS.md: Authored the single source of truth for repository automation, including the Mandatory Review Response protocol.
  • Thread Resolution: Enabled required_review_thread_resolution: true in branch protection logic to ensure no comment (human or AI) is ignored.
  • Labeling Engine: Implemented .github/labeler.yml for automated, file-path-based PR categorization.
  1. Security and CI
  • Supply Chain Security: Pinned all third-party GitHub Actions to full commit SHAs to prevent upstream tampering.
  • Conventional Commits: Enforced PR title linting via pr-title.yml to maintain a clean, squash-ready git history.

@EricAndrechek EricAndrechek merged commit 274dba0 into main Apr 21, 2026
7 of 9 checks passed
@EricAndrechek EricAndrechek deleted the feat/43-ai-code-review branch April 21, 2026 18:46
@claude

claude Bot commented Apr 21, 2026

Copy link
Copy Markdown

Claude finished @taitelee's task in 4m 1s —— View job


PR #55 Review

  • Gathering context (AGENTS.md, CLAUDE.md, changed files)
  • Review governance files (CODEOWNERS, templates, SECURITY.md, AGENTS.md)
  • Review automation workflows (triage, claude-review, claude-agent, dependabot-automerge, pr-title)
  • Review supply chain changes (SHA-pinned actions, dependabot.yml)
  • Compile and post final review

Overall: a well-constructed open-source launch. The three-tier automation design is clean, supply-chain pinning is consistent, governance structure is sensible. Most of the Copilot/Gemini threads were addressed cleanly. A few things worth a follow-up:


MEDIUM — agent label trigger likely never fires

File: .github/workflows/claude-agent.yml, lines 88–94

The labeled trigger branch gates on github.event.sender.author_association, but author_association is not a field on the sender (User) object in GitHub webhook payloads for issues:labeled events. It only exists on content objects like comment, issue, review. In GitHub Actions expressions, accessing a missing property returns an empty string — so every association check (== 'OWNER', == 'MEMBER', etc.) evaluates to false. The labeled branch of the if: is permanently unreachable.

This is a regression from the pre-7c13eae state where the label trigger had no association gate at all. The original Copilot concern was valid, but the fix doesn't work as intended.

The simplest correct fix is to drop the association check on the labeled path and rely on GitHub's built-in enforcement: only users with Triage+ role can apply labels, which already provides the authorization boundary. Alternatively, you can call the collaborator permissions API (gh api repos/$REPO/collaborators/$SENDER/permission) in a setup step.

Fix this →


LOW — GoReleaser CLI version floats at latest

File: .github/workflows/release.yml, line 35

The action is correctly SHA-pinned, but version: latest for the GoReleaser CLI tool itself means the binary installed by the action can change silently between releases. A GoReleaser major bump could break the release pipeline without any diff in this repo. Consider pinning to a specific version (e.g., version: v2.x.y).

Fix this →


LOW — contents: write in dependabot-automerge.yml is over-scoped

File: .github/workflows/dependabot-automerge.yml, line 22

The workflow only calls gh pr review and gh pr merge — both of which require pull-requests: write. The contents: write permission grants write access to the repository tree and isn't used. Dropping it follows least-privilege.


LOW — Project board item lookup capped at 200

File: .github/workflows/triage.yml, line 156

gh project item-list 7 --owner Wave-RF --format json --limit 200

Once the board exceeds 200 items, priority won't be written for new issues that aren't in the first 200 results. Since it's a soft-fail step (continue-on-error: true), this won't surface as an error — it'll just silently skip board writes for affected issues. Not urgent now, but worth increasing to 1000 or paginating before the board grows.


INFO — Three labeler label names need to exist as repo labels

File: .github/labeler.yml, lines 85–113

The entries github_actions, dependencies, and go are not area/*-prefixed and aren't mentioned in the PR's label-setup section. If these labels don't exist in the repo, actions/labeler will either error or silently skip them depending on the action version. Confirm these labels were created during the label-cleanup pass, or remove the entries to keep the labeler in sync with what actually exists.


INFO — Minor doc inconsistency: gofmt vs gofumpt

File: CONTRIBUTING.md, line 90

"Code must be formatted with gofmt."

AGENTS.md is authoritative and says gofumpt (enforced by CI). This line in CONTRIBUTING.md was not updated in the PR. gofmt-formatted code would fail the make fmt-check step on CI since gofumpt is a strict superset. Worth fixing so contributors aren't misled.

Fix this →


What works well

  • Dynamic area label fetching in triage.yml — the gh label list --jq setup step is a clean solve for the Gemini comment. New area/* labels with descriptions auto-populate the classifier's system prompt.
  • PR-title regex — correctly handles the optional ! breaking-change marker, lowercase-first enforcement, and no-trailing-period rule. The inline bash approach avoids a third-party dependency.
  • Supply-chain hygiene — all third-party actions SHA-pinned with version comments. dependabot.yml now covers the two npm roots that were previously absent.
  • CODEOWNERS no-catch-all — intentional design that avoids auto-pinging maintainers on every routine PR. Governance paths gated, code paths manual.
  • Dependabot automerge — the CODEOWNERS carve-out for workflow-path bumps is correctly documented and the major-version hold is the right default.
  • Author-association gate on issues:labeled — the intent was right (Copilot's concern was valid). Needs the implementation fix above, but the design thinking is correct.

@EricAndrechek

Copy link
Copy Markdown
Member Author

Thanks for the post-merge review — three of these are real and I'll fix them in the follow-up PR alongside #56.

Addressing in the follow-up PR:

  • MEDIUM agent label gate — confirmed. sender.author_association isn't a field on the User object in issues:labeled payloads, so the gate silently evaluates false and the branch was unreachable. Dropping the association check entirely and relying on GitHub's built-in Triage+ permission boundary for label writes.
  • LOW contents: write over-scope — dropping. pull-requests: write is sufficient for gh pr review + gh pr merge.
  • LOW goreleaser version: latest — pinning to a specific version; agreed the floating CLI binary is a silent-break risk even with the action SHA-pinned.
  • INFO CONTRIBUTING.md gofmt/gofumpt — updating to gofumpt to match AGENTS.md and what CI actually enforces.

Tracked for later, not urgent:

No action needed:

  • INFO labeler labels — dependencies, github_actions, go all exist in the repo (verified against gh label list); the labeler config is in sync.

Nice catch on the author_association regression specifically — a real bug introduced when addressing Copilot's earlier concern about the labeled trigger. Intent was right, implementation was wrong.


— Posted by Claude Code on behalf of @EricAndrechek

EricAndrechek added a commit that referenced this pull request Apr 21, 2026
Combines the #56 follow-up (switching pr-title.yml + label.yml back
to pull_request_target now that they exist on main) with fixes for
four issues Claude flagged in its post-merge review of #55.

Fixes (real bugs):

- claude-agent.yml: the agent-label trigger gated on
  `github.event.sender.author_association`, but `sender` is a plain
  User object on issues.labeled webhooks — it has no
  author_association field. The check silently evaluated false and
  made the labeled branch unreachable. Dropping the association
  check; GitHub's built-in Triage+ permission on label writes is the
  authorization boundary.
- CONTRIBUTING.md: code-style section said gofmt; CI enforces gofumpt
  (a strict superset). gofmt-formatted code would fail `make
  fmt-check`. Corrected.

Hardening:

- pr-title.yml + label.yml: now use pull_request_target so fork PRs
  get the Validate check + sticky comment + auto-labels. Safe — both
  workflows read only event metadata and never check out PR code.
  Closes #56.
- release.yml: pin goreleaser CLI to `~> v2` (was `latest`). Picks
  up patch/minor bumps via goreleaser-action's resolver, breaks
  loudly on v3 instead of silently changing release behavior.
- dependabot-automerge.yml: drop `contents: write` permission. The
  workflow only calls `gh pr review` + `gh pr merge`, both of which
  need only `pull-requests: write`. Least-privilege.

All six items Claude flagged in the post-merge review of #55 are
either applied here or acknowledged in the reply (the 200-item board
lookup cap is tracked in #58; the labeler label names were verified
to exist).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EricAndrechek added a commit that referenced this pull request Apr 21, 2026
Combines the #56 follow-up (switching pr-title.yml + label.yml back
to pull_request_target now that they exist on main) with fixes for
four issues Claude flagged in its post-merge review of #55.

Fixes (real bugs):

- claude-agent.yml: the agent-label trigger gated on
  `github.event.sender.author_association`, but `sender` is a plain
  User object on issues.labeled webhooks — it has no
  author_association field. The check silently evaluated false and
  made the labeled branch unreachable. Dropping the association
  check; GitHub's built-in Triage+ permission on label writes is the
  authorization boundary.
- CONTRIBUTING.md: code-style section said gofmt; CI enforces gofumpt
  (a strict superset). gofmt-formatted code would fail `make
  fmt-check`. Corrected.

Hardening:

- pr-title.yml + label.yml: now use pull_request_target so fork PRs
  get the Validate check + sticky comment + auto-labels. Safe — both
  workflows read only event metadata and never check out PR code.
  Closes #56.
- release.yml: pin goreleaser CLI to `~> v2` (was `latest`). Picks
  up patch/minor bumps via goreleaser-action's resolver, breaks
  loudly on v3 instead of silently changing release behavior.
- dependabot-automerge.yml: drop `contents: write` permission. The
  workflow only calls `gh pr review` + `gh pr merge`, both of which
  need only `pull-requests: write`. Least-privilege.

All six items Claude flagged in the post-merge review of #55 are
either applied here or acknowledged in the reply (the 200-item board
lookup cap is tracked in #58; the labeler label names were verified
to exist).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EricAndrechek added a commit that referenced this pull request Apr 21, 2026
…#64)

## Summary

Follow-up to #55 — applies four fixes from Claude's post-merge review
plus the tracked #56 follow-up.

### Fixes (real bugs)

- **`claude-agent.yml` labeled trigger was unreachable.** Gated on
`github.event.sender.author_association`, but `sender` is a plain User
object on `issues.labeled` webhooks — no `author_association` field.
Silently evaluated false. Dropped the association check; GitHub's
built-in Triage+ permission on label writes is the authorization
boundary.
- **`CONTRIBUTING.md` said `gofmt`** where CI actually enforces
`gofumpt`. Corrected so `gofmt`-formatted contributions don't fail `make
fmt-check`.

### Hardening

- **`pr-title.yml` + `label.yml` switched to `pull_request_target`** now
that these workflow files exist on `main` (the chicken-and-egg from #55
has cleared). Fork PRs now get the Validate check + sticky comment +
auto-labels. Safe — both workflows only read event metadata, never check
out PR code. **Closes #56.**
- **`release.yml`** pins the GoReleaser CLI to `~> v2` (was `latest`) so
release binaries don't silently change on a v3 major bump.
- **`dependabot-automerge.yml`** drops `contents: write` — `gh pr
review` + `gh pr merge` only need `pull-requests: write`.
Least-privilege.

## Test plan

- [ ] Validate check runs via `pull_request_target` and passes (title is
conforming).
- [ ] `Apply labels` (labeler) runs via `pull_request_target` and tags
this PR appropriately (`area/infra`, `github_actions`, `documentation`).
- [ ] `Review` (claude-review.yml) runs from main and posts an actual
review (no more "workflow validation failed" skip).
- [ ] Gemini reviews with the aggressive `LOW`-threshold config.
- [ ] No other side-effects on CI (`Check` + `Build` pass).

## Related Issues

Closes #56

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EricAndrechek added a commit that referenced this pull request Apr 22, 2026
)

## Summary

Replaces GitHub's CODEOWNERS-based reviewer auto-request + merge-gate
with two workflows that together give stronger control over when human
reviewers are notified, and orchestrate the Task Board as the single
signal for who's holding the baton.

### Why

You wanted human reviewers pinged **only once the PR is actually ready
for review** (bots clean, required checks green, threads resolved) —
regardless of draft state. CODEOWNERS' one-ping-on-PR-open behavior
conflicted with that goal and couldn't express per-author exceptions
(Dependabot). The workflow approach also lets us drive the Task Board
card state as the real coordination channel — GitHub review-request
notifications become noise we can ignore.

### What changes

- **`admin-approval.yml`** (new required status check): fails the `Admin
approval` check unless at least one approving review is from an admin
(Eric or Taite). Dependabot PRs bypass (matches both `dependabot[bot]`
and `app/dependabot` logins). Evaluates the *latest* review state per
user via jq so a subsequent CHANGES_REQUESTED / dismissal invalidates a
stale APPROVED.
- **`project-orchestrator.yml`** (new): drives project #7 as the single
signal for review state.
- PR bot-clean → add to board, Status=Ready (only if current Status is
empty / Backlog — won't yank a reviewer's "In progress"), assign
non-author admin via **PR `assignees` field** (not a review request —
one signal channel only).
- Review `CHANGES_REQUESTED` → PR card "In review", linked issue card
"Ready".
- Author re-requests review → PR card "Ready", linked issue card "In
review".
- Review dismissed → re-eval (dismissal can invalidate admin approval).
- APPROVED / merge → no-op; admin-approval + auto-merge + project's
merge automation close the loop.
- O(1) board-item lookup via GraphQL `resource(url).projectItems` (no
full-board scans).
- Graceful fallback if `PROJECT_BOARD_TOKEN` is missing (fresh forks,
contributor env).
- Manual step preserved: reviewer moves card Ready → In progress when
starting review.
- **`.github/CODEOWNERS` deleted** — one-ping-on-open is gone; admin
approval is now enforced by the required status check instead.
- **Ruleset updated** — `require_code_owner_review: false` (no
CODEOWNERS), `Admin approval` added to `required_status_checks`.

### Behavior change

- Reviewers get **exactly one notification** (GitHub assignment
notification), at the moment their attention helps, regardless of draft
/ non-draft, regardless of which files the PR touches.
- No churn across pushes. No premature ping at open.
- Admin approval is merge-blocking — enforced by workflow rather than
CODEOWNERS.
- Task Board becomes the source-of-truth view of "what's on my plate
right now."

## Test plan

- [ ] `Admin approval` fails on this PR until Taite (or Eric) approves
it.
- [ ] `project-orchestrator` runs without `PROJECT_BOARD_TOKEN` errors;
board ops skip cleanly if token missing (not applicable on this repo
since it's set, but the guard is tested by an empty-secret scenario).
- [ ] On a fresh PR post-merge: orchestrator adds PR to board, sets
Status=Ready, assigns non-author admin. All without a premature ping
during bot iteration.
- [ ] CHANGES_REQUESTED review moves PR card → In review and linked
issue → Ready.
- [ ] Author re-requesting review moves PR card → Ready and linked issue
→ In review.
- [ ] Dependabot PR still auto-merges (bypasses both admin-approval and
project-orchestrator).

## Related Issues

Closes #43 *(originally)*; this PR replaces the initial CODEOWNERS-based
approach from #55 with a workflow-driven one after deciding Dependabot
hands-off auto-merge was non-negotiable (requires the admin-approval
bypass that native CODEOWNERS can't express).

## Notes

PR body originally described `auto-assign-reviewer.yml` and
GitHub-review-request-based signaling. That design pivoted to
`project-orchestrator.yml` with assignee-based signaling mid-PR —
Copilot flagged the body as stale and this revision reflects the current
implementation.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EricAndrechek added a commit that referenced this pull request Apr 23, 2026
…acklog

Copilot R6 flagged that my round-4 `promote`-based gate on the
reeval Assign step had an inverse gap: if a PR card was already
on the board with Status = In progress / In review / Done
(e.g., someone manually moved it before the first bot-clean
re-eval), then promote=false, and the Assign step would silently
skip reviewer assignment AND review request — even though those
should happen on first bot-clean regardless of the board state.

Fix: remove the board-status gate from the orchestrator entirely
and push idempotency into the composite action instead. The
composite now:

- queries current PR assignees + requested-reviewers
- computes the subset of desired reviewers that are missing from
  BOTH lists
- exits early with a log message if everyone's already present
- otherwise adds/requests only the missing users

That handles both directions cleanly:
- PR already In progress with reviewer set → composite no-ops
  (no re-spam, same behavior as before)
- PR already In progress without reviewer (the gap) → composite
  sets the missing reviewer

No-op behavior on SKIP_BOARD also works — assignment doesn't
depend on the board token at all.

Didn't consolidate the CHANGELOG Unreleased section (Copilot R6
#1) — the duplicate ### Fixed / ### Changed headers are
pre-existing from #55/#65/#71 accumulating, and full
consolidation is release-cut scope. Replied to that thread
deferring.
EricAndrechek added a commit that referenced this pull request Apr 28, 2026
…acklog

Copilot R6 flagged that my round-4 `promote`-based gate on the
reeval Assign step had an inverse gap: if a PR card was already
on the board with Status = In progress / In review / Done
(e.g., someone manually moved it before the first bot-clean
re-eval), then promote=false, and the Assign step would silently
skip reviewer assignment AND review request — even though those
should happen on first bot-clean regardless of the board state.

Fix: remove the board-status gate from the orchestrator entirely
and push idempotency into the composite action instead. The
composite now:

- queries current PR assignees + requested-reviewers
- computes the subset of desired reviewers that are missing from
  BOTH lists
- exits early with a log message if everyone's already present
- otherwise adds/requests only the missing users

That handles both directions cleanly:
- PR already In progress with reviewer set → composite no-ops
  (no re-spam, same behavior as before)
- PR already In progress without reviewer (the gap) → composite
  sets the missing reviewer

No-op behavior on SKIP_BOARD also works — assignment doesn't
depend on the board token at all.

Didn't consolidate the CHANGELOG Unreleased section (Copilot R6
#1) — the duplicate ### Fixed / ### Changed headers are
pre-existing from #55/#65/#71 accumulating, and full
consolidation is release-cut scope. Replied to that thread
deferring.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation, site/, README area/infra CI, build, deploy, Docker, release documentation Improvements or additions to documentation github_actions Pull requests that update GitHub Actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gemini AI Code Review in CI

3 participants