Skip to content

Commit 6934a82

Browse files
don-petryclaudedonpetry-bot
authored
feat(add-to-project): track all issues + retire Discussion drafts + ContentTwin/BMAD (#616)
* feat(add-to-project): track all issues + retire Discussion drafts + ContentTwin/BMAD Follow-up to #608, which squash-merged mid-work and captured only the classifier + triage tuning. These two changes landed on the branch after that merge and were stranded: 1. Un-gate Issues (keep PRs gated): empty REQUIRED_LABEL now means "no required label"; reusable passes '' for issues / dev-lead for PRs; reconcile-backlog gates per item via the /issues payload's `.pull_request`. Excluded-label noise filter still applies. 2. Retire Discussion drafting: removed the `discussion:` trigger (stub + template), the reconcile-discussion job (reusable), the Ideas backlog scan, ideas_category/IDEAS_CATEGORY, and reconcile-discussion.sh + its bats. Ideas live in GitHub Discussions; an Epic is a parent Issue with sub-issues. 3. ContentTwin + BMAD initiatives (full org coverage); bare `bmad` moved off the dev-lead rule so it doesn't swallow the repo path. Board is now the org-wide issue portfolio. The 25 Initiative / 10 Theme options already exist on the board (created footgun-safe). 66 bats green; shellcheck -S warning clean; 4 workflows parse. Docs updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com> Co-authored-by: Don Petry Bot <donpetry+bot@gmail.com>
1 parent f0e01b5 commit 6934a82

14 files changed

Lines changed: 199 additions & 752 deletions

‎.github/scripts/add-to-project/add-issue-or-pr.sh‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
# add-issue-or-pr.sh — reconcile a single issue or PR with the org
33
# Initiatives project. An item belongs on the board iff it passes the
44
# noise gate:
5-
# - carries the required label (REQUIRED_LABEL, default `dev-lead`)
5+
# - carries the required label (REQUIRED_LABEL) — but an EMPTY
6+
# REQUIRED_LABEL means "no required label", which is how issues are
7+
# un-gated (every issue tracked) while PRs keep the `dev-lead` gate;
68
# - carries NONE of the excluded labels (EXCLUDED_LABELS, default
7-
# compliance-audit,health-check,fleet-tracker,daily-report) — the gate
8-
# that keeps strategic work distinct from automation-generated work.
9+
# compliance-audit,health-check,fleet-tracker,daily-report) — the noise
10+
# filter that keeps automation-generated churn off the board.
911
#
1012
# Reconcile, not just add (petry-projects/.github#415 §2): if an item that
11-
# was on the board stops qualifying — `dev-lead` removed, or an excluded
12-
# label added — its project item is removed. This is the issue/PR analogue
13-
# of reconcile-discussion.sh's state machine, built on the shared
13+
# was on the board stops qualifying — required label removed, or an excluded
14+
# label added — its project item is removed, built on the shared
1415
# find_project_item / delete_project_item helpers in lib.sh.
1516
#
1617
# Required env:
@@ -54,7 +55,11 @@ evaluate_noise_gate() {
5455
labels_json='[]'
5556
fi
5657

57-
local required="${REQUIRED_LABEL:-dev-lead}"
58+
# ${VAR-default} (no colon): an unset REQUIRED_LABEL falls back to dev-lead,
59+
# but an explicitly EMPTY value means "no required label" — every item
60+
# qualifies (subject only to the excluded-labels filter). This is how issues
61+
# are un-gated while PRs keep the dev-lead requirement.
62+
local required="${REQUIRED_LABEL-dev-lead}"
5863
# Use ${VAR-default} (no colon): an unset EXCLUDED_LABELS falls back to the
5964
# default set, but an explicitly empty value means "no exclusions" so a repo
6065
# can opt out entirely.
@@ -74,7 +79,7 @@ evaluate_noise_gate() {
7479
--argjson excluded "${excluded_json}" \
7580
'
7681
[.[].name] as $names
77-
| if ($names | index($required) | not) then
82+
| if ($required != "" and ($names | index($required) | not)) then
7883
"missing:" + $required
7984
else
8085
([$excluded[] | select(. as $e | $names | index($e))]) as $hits

‎.github/scripts/add-to-project/initiative-rules.tsv‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,26 @@
1515
# product-feature keywords.
1616
# Unmatched items are left BLANK and reported for triage — never guessed.
1717
Auto-rebase auto.?rebase|update.?branch|rebase (bot|loop|collision)|conflict.?comment|dismiss.?stale|last.?push.?approval|stale.?base
18-
pr-review agent pr.?review|(code|bot|single|advisory) review|review.?(one.?pr|decision|enumeration|loop|comments?|bot|gate|findings|annotation|enhancement|dismissal|tier|cycles?|retry)|single.?review|max_review|rubber duck|cascade|advisory.?bot|coderabbit|(gemini|copilot|sonarcloud|codex) review|fix.?request|extract_verdict|verdict|mention.?(ack|trigger)|changes_requested|@petry-review|@donpetry-bot|review-one-pr|list-prs|copilot suggest|github models|churn breaker|self.?trigger|downstream.?impact|pr_diff|mcp.*(review|tiers?|knob|config|server)|lsp (index|pilot|tool)|reviewer|awaiting review|#860
19-
Business Analyst feature.?ideation|idea.?enhanc|idea.?triage|idea-enhancer|business analyst|enhance .*ideas?|single-idea enhancement|idea..?initiative pipeline
18+
pr-review agent pr.?review|(code|bot|single|advisory) review|review.?(one.?pr|decision|enumeration|loop|comments?|bot|gate|findings|annotation|enhancement|dismissal|tier|cycles?|retry)|single.?review|max_review|rubber duck|cascade|advisory.?bot|coderabbit|(gemini|copilot|sonarcloud|codex) review|fix.?request|extract_verdict|verdict|mention.?(ack|trigger)|changes_requested|@petry-review|@donpetry-bot|review-one-pr|list-prs|copilot suggest|github models|churn breaker|self.?trigger|downstream.?impact|pr_diff|mcp.*(review|tiers?|knob|config|server)|lsp (index|pilot|tool)|reviewer|awaiting review|#860|rate-limit detector|triage tier|triage inline|review.?engine|copilot engine|engine (toggle|support)|fallback to copilot|small-pr|prioriti.e .*pr|automated feedback|lsp[_ ]pilot|poll-loop|addpullrequestreview|pr approvals
19+
Business Analyst feature.?ideation|idea.?enhanc|idea.?triage|idea-enhancer|business analyst|enhance .*ideas?|single-idea enhancement|idea..?initiative pipeline|market research|epic checklist|open-questions|ready-for-dev|consumer manifest|plan\.json|grounding check|untracked .*prerequisite|strict-improvement|target_surface
2020
Model Selection model.?(selection|fallback|tier|switch)|fallback model|opus.?fallback|retire .*(opus|gpt|claude-|model)|update to opus|opus 4|cross.?provider|provider.?switch|additional providers|providers,? .*model|engine.?(availability|model|upgrade)|multi-model chain|rate.?limit resilience
2121
Agent Shield agent.?shield|prompt.?injection|input sanitiz|sanitiz|agent.?(security|hardening|governance)|jailbreak|secret.?redact|mcp.*(governance|allowlist|registry)|credential isolation|owasp|posture scoring|egress (firewall|policy|filter|rule)|firewall policy|trust escalation|agent autonomy
2222
Self-healing self.?heal|auto.?remediat|auto.?fix|self.?repair|stall detect|pipeline stall|recovery escalation|kill switch|circuit breaker|runaway (protection|agent|pr)
23-
dev-lead agent dev.?lead|deep.?impl|bmad|engine.?(timeout|error)|story churn|phantom.?spec|thin.?caller|inlined (claude|workflow)|claude\.yml|claude-fix|claude-?issue|claude code workflow|claude workflow|issue automation|prompting framework|devops agent persona|duplicate .*(pr|agent)|dedup|umbrella issue|in-progress label
24-
GH-AW gh-?aw|agentic.?workflow|(^|[^[:alnum:]])aw([^[:alnum:]]|$)|ci.?failure|failure.?analyst|ci-?analyst|failure-to-agent|lock\.?file|lock\.yml|eval scorer|held-out|rubric|proposer|skill.?eval|skillopt|skill.?candidate|plan_json|artifact (type|contract)|self-improving|eval-case|evals/|agents\.md (spec|align)
23+
dev-lead agent dev.?lead|deep.?impl|engine.?(timeout|error)|story churn|phantom.?spec|thin.?caller|inlined (claude|workflow)|claude\.yml|claude-fix|claude-?issue|claude code workflow|claude workflow|issue automation|prompting framework|devops agent persona|duplicate .*(pr|agent)|dedup|umbrella issue|in-progress label|claude-ci-fix|@claude|claude code|terminal coding agent|pi as org|pi harness|check_run|auto-merge
24+
GH-AW gh-?aw|agentic.?workflow|(^|[^[:alnum:]])aw([^[:alnum:]]|$)|ci.?failure|failure.?analyst|ci-?analyst|failure-to-agent|lock\.?file|lock\.yml|eval scorer|held-out|rubric|proposer|skill.?eval|skillopt|skill.?candidate|plan_json|artifact (type|contract)|self-improving|eval-case|evals/|agents\.md (spec|align)|frameworks directory|frameworks/
2525
Copilot Instructions copilot.*instruction|copilot coding agent|copilot governance|copilot custom|\.github/copilot|copilot-instructions
2626
Cost Observability cost (attribution|observ|meter|arbitrage|report|api)|token.?(cost|savings|report|metric|observ)|budget (enforcement|circuit breaker|guardrail|tracking|aware)|credit budget|observability dashboard|opentelemetry|otel|effective token|\bet\b .*anomaly|usage & cost|billing-aware|batch api cost
2727
Fleet Monitor fleet.?(monitor|tracker|view|health)|health.?check|hourly runs?|cron entr|scheduled .*(runs?|actions)
2828
Daily Reports daily.?report|nightly.?report|status.?digest|org.?status
2929
Compliance Blitz compliance.?blitz|compliance.?day|compliance backlog
30-
Org Standards sonarcloud|sonar[ ._-]|s7[0-9]{3}|s86[0-9]{2}|s59[0-9]{2}|s3776|s5906|scorecard|ruleset|codeowners|branch.?(protection|ruleset)|push.?protection|ci.?standard|baseline|standards.?(sync|deploy|reconcile)|nosonar|secret.?scan|gitleaks|dependency.?(harden|pinning)|pin.*(sha|ref|reusable|version|action)|actionlint|yamllint|lint check|dependabot|org.?standard|org-wide .*(standard|instruction|reusable)|code.?quality|zizmor|oidc|access control|standards drift|drift.?(guard|detection)|integrity verification|execution protection|security linting|pull.?request.?limits|pr.?limits|admission gate|agents\.md|claude\.md|codeql|reusable workflow|apply-repo-settings|repo settings|profile readme|coding standard|ci pipeline|markdown lint|concurrency group|check-suite|slsa|attestation|bootstrap.?new.?repo|repo.?template|non-file policy|require .*discussions|has_discussions|structured logging|cqrs|stacked pr|worktree|convention|merge queue|noise reduction|cognitive complexity|jest assertion
30+
Org Standards sonarcloud|sonar[ ._-]|s7[0-9]{3}|s86[0-9]{2}|s59[0-9]{2}|s3776|s5906|scorecard|ruleset|codeowners|branch.?(protection|ruleset)|push.?protection|ci.?standard|baseline|standards.?(sync|deploy|reconcile)|nosonar|secret.?scan|gitleaks|dependency.?(harden|pinning)|pin.*(sha|ref|reusable|version|action)|actionlint|yamllint|lint check|dependabot|org.?standard|org-wide .*(standard|instruction|reusable)|code.?quality|zizmor|oidc|access control|standards drift|drift.?(guard|detection)|integrity verification|execution protection|security linting|pull.?request.?limits|pr.?limits|admission gate|agents\.md|claude\.md|codeql|reusable workflow|apply-repo-settings|repo settings|profile readme|coding standard|ci pipeline|markdown lint|concurrency group|check-suite|slsa|attestation|bootstrap.?new.?repo|repo.?template|non-file policy|require .*discussions|has_discussions|structured logging|cqrs|stacked pr|worktree|convention|merge queue|noise reduction|cognitive complexity|jest assertion|ci\.yml|gh_pat|pat auth|machine user|repository settings|ci/cd standard|new-repo|pr.?limit|fail loud|never fake|orchestration guidance
3131
Compliance program compliance|audit|remediat
3232
Release Strategy release.?(strategy|train|notes|channel|cadence|automation|cut|soak|ring)|cut.?release|autocut|soak.?(promote|and-promote)|ring.?(rollout|promote|enrol|stag)|channel.?(promote|cut|soak|pin)|canary|version(ing)? (scheme|standard)|semantic versioning|tag protection|rollback|promote .*(channel|ring|stable)
33-
Initiatives Project initiative|add.?to.?project|projects? v2|project board|roadmap view|initiatives project|issue.?fields|github projects
33+
Initiatives Project initiative|add.?to.?project|projects? v2|project board|roadmap view|initiatives project|issue.?fields|github projects|updateprojectv2field|option.?wipe
3434
Tooling tooling|scratchpad|dev.?tool|utility script|template gallery
3535
Broodly /broodly|broodminder|\bhive\b|honey|nectar|bloom|colony|\bmite|apiary|beekeep|hornet|treatment efficacy|nfc and qr|acoustic colony|zero-tap|off-season engagement
3636
Markets /markets|snap/ebt|produce recognition|app-averse|failed-trip|vendor catalog|north-star|discover filter|sms check-in
3737
Google App Scripts /google-app-scripts|apps? script|script_catalog|gmail|deployed-script
38-
TalkTerm /talkterm|avatar|elevenlabs|lip-sync|screen companion|companion mode|3d avatar|spatial audio|byok|effort modes|voice (assistant|agent|interface|provider|transcription)|conversational (voice|oauth|permission|mcp|onboarding)|screenshot context|deliberation mode|emotion-aware|multi-language voice|infinite conversation|on-device (voice|ai)|vision-native
38+
TalkTerm /talkterm|avatar|elevenlabs|lip-sync|screen companion|companion mode|3d avatar|spatial audio|byok|effort modes|voice (assistant|agent|interface|provider|transcription)|conversational (voice|oauth|permission|mcp|onboarding)|screenshot context|deliberation mode|emotion-aware|multi-language voice|infinite conversation|on-device (voice|ai)|vision-native|natural language automation|shareable session|workspace intelligence|contextual workspace|conversational recurring|visual workflow replay
39+
ContentTwin /contenttwin|content.?twin
40+
BMAD /bmad-bgreat|bmad-bgreat|bmad suite|bmad method|bmad-method|\bbmad\b|bmad

‎.github/scripts/add-to-project/initiative-taxonomy.tsv‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ Tooling Tooling
1919
Ad hoc Ad hoc
2020
Business Analyst Agentic Framework
2121
Cost Observability Fleet Operations
22-
TalkTerm Products
23-
Broodly Products
24-
Markets Products
25-
Google App Scripts Products
22+
TalkTerm TalkTerm
23+
Broodly Broodly
24+
Markets Markets
25+
Google App Scripts Google App Scripts
26+
ContentTwin ContentTwin
27+
BMAD Agentic Framework

‎.github/scripts/add-to-project/reconcile-backlog.sh‎

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@
77
# GitHub does not fire workflows from default-token events, so
88
# `issues: opened` never triggers the add; and
99
# 2. runs dropped under runner congestion (no retry).
10-
# This scans each repo's OPEN issues/PRs + Ideas discussions and reconciles each
11-
# with the board using the SAME gate + helpers as the event path
12-
# (evaluate_noise_gate / reconcile_content_with_project / reconcile_discussion),
13-
# so a missed item lands within one reconcile cycle regardless of author/token.
10+
# This scans each repo's OPEN issues/PRs and reconciles each with the board
11+
# using the SAME gate + helpers as the event path (evaluate_noise_gate /
12+
# reconcile_content_with_project), so a missed item lands within one reconcile
13+
# cycle regardless of author/token. Issues are un-gated (every issue tracked);
14+
# PRs keep the required-label gate. Discussions are not tracked.
1415
# Idempotent; honours DRY_RUN=1 (logs intended actions, mutates nothing).
1516
#
1617
# Env:
1718
# PROJECT_ID ProjectV2 node ID of the Initiatives project (required)
1819
# PROJECT_URL human-readable URL (logging only)
19-
# REQUIRED_LABEL gate's required label (default: dev-lead)
20+
# REQUIRED_LABEL PR gate's required label (default: dev-lead); issues are
21+
# un-gated regardless
2022
# EXCLUDED_LABELS gate's excluded labels (default in add-issue-or-pr.sh)
21-
# IDEAS_CATEGORY discussion category tracked as drafts (default: Ideas)
2223
# RECON_REPOS space-separated owner/repo list to scan
2324
# (default: the planner App installation's repositories)
2425
# DRY_RUN "1" → log only
@@ -28,15 +29,12 @@ set -euo pipefail
2829
_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
2930
# shellcheck source=.github/scripts/add-to-project/add-issue-or-pr.sh
3031
source "${_dir}/add-issue-or-pr.sh" # reconcile_content_with_project (+ lib.sh)
31-
# shellcheck source=.github/scripts/add-to-project/reconcile-discussion.sh
32-
source "${_dir}/reconcile-discussion.sh" # reconcile_discussion
3332

3433
: "${PROJECT_ID:?PROJECT_ID is required}"
35-
ideas_category="${IDEAS_CATEGORY:-Ideas}"
36-
# Exported (with default applied) so the discussions --jq filter can read it via
37-
# `env.RECON_IDEAS_CATEGORY` instead of shell-interpolating it — avoids jq syntax
38-
# breakage / injection if the category name contains quotes or backslashes.
39-
export RECON_IDEAS_CATEGORY="${ideas_category}"
34+
# Issues are un-gated; PRs keep the required-label gate. Capture the PR gate
35+
# from the incoming REQUIRED_LABEL (default dev-lead) before the loop overrides
36+
# it per item.
37+
pr_required="${REQUIRED_LABEL-dev-lead}"
4038

4139
# Resolve target repos: explicit RECON_REPOS, else the App installation's repos.
4240
declare -a repos
@@ -56,45 +54,28 @@ for repo in "${repos[@]}"; do
5654
[ -z "$repo" ] && continue
5755
echo "::group::${repo}"
5856

59-
# Open issues AND PRs (the issues endpoint returns both; the gate applies to
60-
# both identically). Pass labels as the objects array the gate expects.
61-
# Fetch into a variable so an API failure is surfaced (not silenced) and
62-
# `set -e`'s check isn't bypassed by a subshell; feed the loop via here-string
63-
# so it stays in the parent shell and `scanned` is updated correctly.
57+
# Open issues AND PRs (the issues endpoint returns both). A PR carries a
58+
# `.pull_request` object; emit that so the loop can apply the required-label
59+
# gate to PRs only — issues are un-gated. Pass labels as the objects array
60+
# the gate expects. Fetch into a variable so an API failure is surfaced (not
61+
# silenced) and `set -e`'s check isn't bypassed by a subshell; feed the loop
62+
# via here-string so it stays in the parent shell and `scanned` updates.
6463
issues_tsv=$(gh api --paginate "repos/${repo}/issues?state=open&per_page=100" \
65-
--jq '.[] | [.node_id, .html_url, ([.labels[] | {name}] | @json)] | @tsv') || {
64+
--jq '.[] | [.node_id, .html_url, ([.labels?[]? | {name}] | @json), (if .pull_request then "pr" else "issue" end)] | @tsv') || {
6665
echo "::error::failed to fetch issues for ${repo}" >&2
6766
echo "::endgroup::"
6867
continue
6968
}
70-
while IFS=$'\t' read -r nid url labels; do
69+
while IFS=$'\t' read -r nid url labels kind || [ -n "$kind" ]; do
70+
kind="${kind%$'\r'}"
7171
[ -z "$nid" ] && continue
7272
scanned=$((scanned + 1))
73-
reconcile_content_with_project "$nid" "$url" "$labels" || true
73+
# Un-gate issues (empty required label); PRs keep the gate.
74+
if [ "$kind" = "pr" ]; then REQUIRED_LABEL="$pr_required"; else REQUIRED_LABEL=""; fi
75+
export REQUIRED_LABEL
76+
reconcile_content_with_project "$nid" "$url" "$labels"
7477
done <<< "$issues_tsv"
7578

76-
# Open Ideas-category discussions → draft items. Same robustness as above; the
77-
# category is read inside jq via `env.RECON_IDEAS_CATEGORY` (set earlier) rather
78-
# than shell-interpolated, so special characters can't break or inject into it.
79-
discussions_tsv=$(gh api graphql --paginate -f owner="${repo%%/*}" -f name="${repo##*/}" -f query='
80-
query($owner:String!,$name:String!,$endCursor:String){
81-
repository(owner:$owner,name:$name){
82-
discussions(first:100,after:$endCursor,states:OPEN){
83-
pageInfo{hasNextPage endCursor}
84-
nodes{number title url category{name}}
85-
}
86-
}
87-
}' --jq '.data.repository.discussions.nodes[] | select(.category.name==env.RECON_IDEAS_CATEGORY) | [(.number|tostring), .title, .url] | @tsv') || {
88-
echo "::error::failed to fetch discussions for ${repo}" >&2
89-
echo "::endgroup::"
90-
continue
91-
}
92-
while IFS=$'\t' read -r number title url; do
93-
[ -z "$number" ] && continue
94-
scanned=$((scanned + 1))
95-
reconcile_discussion "$number" "$title" "$url" "$ideas_category" || true
96-
done <<< "$discussions_tsv"
97-
9879
echo "::endgroup::"
9980
done
10081

0 commit comments

Comments
 (0)