feat(add-to-project): classify + track all issues + retire Discussion drafts - #608
Conversation
The add-to-project automation only ever placed items ON the board (addProjectV2ItemById); nothing set the Initiative field, so ~651 of 652 board items sat on the board unassociated with any initiative. This adds the continuous, deterministic classifier that fills that gap — and whose first run back-fills the existing blanks. This is the "classification signal" follow-on framed in #415. Mechanism - classify-initiative.sh: flattens each item to a lowercase `title | labels | repo` signature and matches ordered regex rules (initiative-rules.tsv, first match wins); co-assigns the Theme each Initiative rolls up to (initiative-taxonomy.tsv). Unmatched items are left BLANK and reported for triage — never force-bucketed to "Ad hoc". - Strips routing-label families (dev-lead*, initiative*, incl. colon-variants like dev-lead:needs-human / initiative:auto) from the signature: they are work-assignment / pipeline signals, not classification signals, and would otherwise make every item match dev-lead-agent / Initiatives-Project. - Writes only per-item field VALUES (updateProjectV2ItemFieldValue), never the field SCHEMA, so it cannot trip the single-select option-wipe footgun documented in standards/initiatives-project.md. Fills only blank Initiatives by default (RECLASSIFY=all to re-evaluate); resolves live option ids by name. - lib.sh: add set_item_single_select_value helper (DRY_RUN-aware). Wiring & tests - Runs as the 2nd step of add-to-project-reconcile.yml, after the backlog reconcile; manual dispatch defaults to dry-run, adds a reclassify_all input. - 24 new bats tests (72 total green); shellcheck -S warning clean. - Documented in standards/initiatives-project.md; synced the stale Theme→Initiative table to the live options (Model Selection, Release Strategy). Coverage (dry-run over the live 653-item board): 441 matched / 212 left blank (67%), 0 option-missing. Remainder is product work with no matching Initiative + genuinely ambiguous items, correctly left for human triage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
Next review available in: 19 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (5)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Dev-Lead — review-changes (no-changes)No changes were needed for this PR. |
Dev-Lead — fix-bot-comment (no-changes)Agent reasoning |
There was a problem hiding this comment.
Pull request overview
Adds a deterministic, rule-driven Initiative/Theme classifier to the org “Initiatives Project” automation so board items are continuously categorized (and existing blanks can be back-filled) without touching project field schema.
Changes:
- Introduces
classify-initiative.shto compute a normalized item signature and apply ordered regex rules + taxonomy rollup. - Wires the classifier into
add-to-project-reconcile.ymlas a second phase withdry_runand optionalreclassify_all. - Adds rules/taxonomy TSV sources plus bats coverage for both pure classification and end-to-end sweep behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/workflows/add-to-project/classify-initiative.bats | New bats coverage for signature normalization, rule ordering, taxonomy roll-up, and sweep behavior (dry-run + apply). |
| standards/initiatives-project.md | Documents how Initiative/Theme classification works and updates taxonomy references. |
| .github/workflows/add-to-project-reconcile.yml | Adds a “Classify Initiative on board items” step after reconcile, with dry-run + reclassify gating. |
| .github/scripts/add-to-project/lib.sh | Adds a DRY_RUN-aware helper to set single-select field values via updateProjectV2ItemFieldValue. |
| .github/scripts/add-to-project/initiative-taxonomy.tsv | Defines the Initiative → Theme roll-up mapping used by the classifier. |
| .github/scripts/add-to-project/initiative-rules.tsv | Defines ordered Initiative classification rules matched against the normalized signature. |
| .github/scripts/add-to-project/classify-initiative.sh | Implements rule matching, field/option resolution, pagination sweep, and reporting. |
There was a problem hiding this comment.
Code Review
This pull request introduces a new script classify-initiative.sh along with rules and taxonomy TSV files to automate the classification of initiatives and themes on project items, supported by a comprehensive suite of BATS tests. The review feedback focuses on critical robustness improvements, specifically recommending the use of the jq optional operator ? to prevent fatal errors when parsing potentially null GraphQL fields (especially for Draft Issues), ensuring robust TSV parsing of CRLF line endings and missing trailing newlines, and simplifying test assertions by avoiding unnecessary subshells.
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: MEDIUM
Reviewed commit: ea995134e9a1d2bc1d8e539326fb09d7b398d3f8
Review mode: triage-approved (single reviewer)
Summary
Adds a deterministic, rule-driven Initiative/Theme classifier (classify-initiative.sh + rules/taxonomy TSVs) as the 2nd phase of the daily add-to-project reconcile, back-filling ~651 blank board items on first live run. Safe by construction (per-item value writes only, never field schema; blank-fill by default; DRY_RUN-aware), well tested (24 new bats tests, 71 total green), and validated end-to-end against the live board in dry-run (441/653 matched, 0 option-missing). All substantive CI checks green. Bot review comments assessed: gemini's 'high' jq null-indexing findings are false positives (jq returns null when indexing null; code already uses []? and // defaults, proven by the DraftIssue test fixture); Copilot's \b / grep -P comments are portability nits irrelevant on the ubuntu GNU-grep runtime.
Linked issue analysis
No closing issue references. PR cites #415 (classification-signal follow-on, open umbrella for the Initiatives-Project rollout) and #387 (pilot) as refs, not closes — correct, since #415's broader multi-repo scope remains open. The PR substantively delivers the classification gap identified there: the add path only ever set board membership, never the Initiative field.
Findings
- Secret scan: run_secret_scanning MCP tool unavailable in this run — noted per protocol; gitleaks CI check is green, no secrets in the diff.
- Security: GraphQL mutations use -F variables (no string interpolation); regex patterns come from repo-controlled TSVs and item titles are matched as stdin data, not patterns — no injection surface. Writes only updateProjectV2ItemFieldValue, never updateProjectV2Field, so the documented option-wipe footgun is structurally unreachable. Workflow step reuses the existing app token; no new permissions. CodeQL actions analysis green.
- gemini-code-assist flagged 5 'high' jq null-indexing issues: all false positives. jq yields null (not an error) when indexing null with a string; iteration sites already use [] ? guards and // "" / // [] defaults. The bats DraftIssue fixture (PVTI_C, no labels/repository) exercises the exact flagged path and passes in CI.
- gemini 'medium' CRLF/trailing-newline TSV parsing and Copilot's \baw\b (ERE word boundary) + grep -P portability comments: valid only on non-GNU grep or Windows-edited files; workflow and tests run on ubuntu-latest GNU grep and the TSVs are LF, repo-controlled. Non-blocking nits; the dev-lead agent already dispositioned all comments as no-changes.
- Note for operator: merging arms the daily scheduled live run (DRY_RUN=0) whose first pass back-fills 651 items — intentional and clearly flagged in the PR's activation note, with a documented dry-run preview path.
CI status
All substantive checks green: Shellcheck and bats ✓, CI Lint/ShellCheck/Agent Security Scan/Secret scan (gitleaks) ✓, CodeQL (incl. actions analysis) ✓, SonarCloud quality gate ✓ (0 new issues, 0 hotspots), AgentShield ✓, Dependency audit ✓, CodeRabbit status SUCCESS. Only the PR-review pipeline's own dispatch checks were pending at review time.
Reviewed automatically by the PR-review agent (single-reviewer mode: fable 5). Reply if you need a human review.
Dev-Lead — fix-reviews (applied)Changes committed and pushed. |
e383188
Dev-Lead — review-changes (no-changes)No changes were needed for this PR. |
Second tuning pass, driven by triage of the 212-item unmatched tail with the board owner's guidance on groupings: - New product initiatives (repo-scoped, matched last so cross-cutting infra work in those repos still wins): TalkTerm, Broodly, Markets, Google App Scripts (Theme: Products). - New agentic/ops initiatives: Business Analyst (feature-ideation / Mary+Bob, Agentic Framework), Cost Observability (token/cost/budget, Fleet Operations). - Skill-Eval pipeline folded into GH-AW per guidance. - Reordered rules into two tiers — cross-cutting infra/agentic FIRST, product repos LAST — so a SonarCloud/Scorecard sweep or auto-rebase fix inside a product repo classifies as Org Standards / Auto-rebase, not product work (matches standards doc: Org Standards owns scorecard/sonarcloud org-wide). - Expanded infra rules to close the tail (claude-issue→dev-lead, cut-release/ soak→Release Strategy, AGENTS.md/codeql/repo-template→Org Standards, review cascade/#860→pr-review, skill-eval→GH-AW). Dry-run coverage over the live board: 609/653 matched (93.3%), 0 option-missing for existing options. The 6 new options don't exist on the board yet, so the classifier safely skips those matches until they're created. +6 bats tests incl. the infra-wins-over-product-repo ordering guard (77 green). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dev-Lead — review-changes (no-changes)No changes were needed for this PR. |
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: MEDIUM
Reviewed commit: 98ce6484686e8dac53ce481245ae6f5d3252082b
Review mode: triage-approved (single reviewer)
Summary
Confirms the triage-approved assessment. Adds a deterministic, rule-driven Initiative/Theme classifier (classify-initiative.sh + two TSV data files), a set_item_single_select_value helper in lib.sh, a second step in add-to-project-reconcile.yml, docs, and 27 bats tests. The classifier writes only per-item field values (updateProjectV2ItemFieldValue) via GraphQL variables — it never mutates the field schema, so the documented option-wipe footgun is structurally avoided. Default behavior fills only blank Initiatives (non-destructive); manual dispatch defaults to dry-run. Risk is MEDIUM rather than LOW (new automation logic + workflow change), but all approval gates pass.
Linked issue analysis
No formally linked closing issue. The PR body and code reference #415 (add-to-project never set the Initiative field; 651/652 items unassociated). The change substantively addresses that gap with a continuous classifier whose first run back-fills blanks; remaining deferred work stays tracked in #415.
Findings
- No blocking findings.
- Security: GraphQL mutations use typed variables (-F), regexes come from checked-in TSVs, item titles are matched as grep input (not patterns) — no injection paths. Workflow adds no new permissions; boolean dispatch inputs are used only inside ${{ }} env expressions, never interpolated into run: blocks. No secrets in the diff (project node ID is public and already in-repo; test fixtures use dummy tokens).
- Secret scan: run_secret_scanning MCP tool unavailable in this run; gitleaks CI check passed.
- Prior bot feedback: all 10 review threads (copilot, gemini) are resolved; gemini's final low-priority bats suggestion (run grep -c instead of bash -c … || true) was applied.
- Non-blocking nit: the ::warning:: workflow command in sweep_project is printed to stderr; Actions parses workflow commands from stdout, so it may render as a plain log line instead of an annotation. Cosmetic only.
- Note: branch is BEHIND main (mergeable); auto-rebase automation should handle before merge.
CI status
All required checks green: Shellcheck and bats ✓, ShellCheck ✓, Lint ✓, CodeQL (actions) ✓, Agent Security Scan ✓, agent-shield ✓, Secret scan (gitleaks) ✓, SonarCloud quality gate ✓ (0 new issues), CodeRabbit ✓, npm audit ✓. Remaining checks skipped (not applicable ecosystems).
Reviewed automatically by the PR-review agent (single-reviewer mode: fable 5). Reply if you need a human review.
|
Dev-Lead — fix-bot-comment (no-changes)Agent reasoning |
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: MEDIUM
Reviewed commit: 603f7059d3800f6faac4cb6b8277ea2e60f544b1
Review mode: triage-approved (single reviewer)
Summary
Confirms the triage-approved assessment. This PR adds a deterministic, rule-driven Initiative/Theme classifier (classify-initiative.sh, 309 lines) with two TSV data files (ordered regex rules + Initiative→Theme taxonomy), a set_item_single_select_value helper in lib.sh, a second step in add-to-project-reconcile.yml, standards docs, and 27 bats tests that exercise the real rule files. Since the prior approved review at 98ce648, the only change is a merge of main into the branch (unrelated files: pr-review-mention-reusable.yml, rulesets); no new PR-specific code.
Linked issue analysis
No closing issue reference, by design: #415 is the umbrella issue and explicitly tracks remaining deferred work (see standards/initiatives-project.md → Deferred work). The PR substantively addresses the core #415 gap — items landed on the board but the Initiative field was never set (651/652 unassociated). The classifier back-fills and continuously maintains it, reaching 93.3% dry-run coverage with unmatched items deliberately left blank for human triage.
Findings
No blocking findings.
- Injection-safe shell:
set -euo pipefail; all GraphQL uses-Fvariables (no string interpolation into queries); untrusted item titles/labels flow only throughjq,printf '%s', andgrepstdin — noeval, no format-string interpolation. Regex rules come from repo-committed TSVs, not item content. - Schema-wipe footgun structurally avoided: only
updateProjectV2ItemFieldValue(per-item value) is used, neverupdateProjectV2Field; rule-named options missing from the live schema are skipped with a warning rather than created or failed on. - Non-destructive default: only blank Initiatives are filled;
RECLASSIFY=allis an explicit opt-in workflow input; manual dispatch defaults to dry-run, matching the existing reconcile step's gating. - Workflow change is minimal: reuses the already-minted planner App token in the same job; hardcoded PROJECT_ID matches the documented value.
- Prior advisory-bot threads: all 10 review threads (Copilot
\bportability, Gemini null-guards/CRLF, etc.) are resolved; the current code contains the fixes (e.g.,.options?[]?null-tolerant jq paths,%$'\r'CRLF stripping, data.node null check → exit 75). - Secret-scanning MCP tool not available in this run (noted per protocol); the gitleaks CI check passed.
CI status
All required checks green at 603f7059d3800f6faac4cb6b8277ea2e60f544b1: Shellcheck and bats ✓, ShellCheck ✓, Lint ✓, CodeQL ✓, Agent Security Scan ✓, agent-shield ✓, Secret scan (gitleaks) ✓, SonarCloud quality gate passed (0 new issues, 0 hotspots), npm audit ✓. Ecosystem-conditional checks (pnpm/cargo/pip audit, govulncheck) skipped as expected.
Reviewed automatically by the PR-review agent (single-reviewer mode: fable 5). Reply if you need a human review.
…ontentTwin/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>
…te reliably (#635) * fix(add-to-project): make un-gated reconcile+classify pipeline complete reliably Un-gating issues (#608) put ~450 open issues in scope for the daily reconcile+classify pipeline, which surfaced three defects that together left the Initiatives board almost entirely unclassified (1 of ~840 items had an Initiative set): 1. Reconcile timeout. reconcile-backlog.sh issued one idempotent GraphQL add per qualifying item AND one find-to-remove per disqualified item, every cycle — ~450+ sequential round-trips that overran the 20-min job timeout, so the classify step (step 2) was cancelled every run. Fix: prefetch board membership once (declare -gA _ATP_ON_BOARD) and let both hot paths answer "already on the board?" from memory — only genuine adds/removes touch the API. Gated on _atp_membership_ready so the event path is unchanged. Job timeout raised 20->30 for cold catch-up cycles. 2. All-numeric option id rejected. set_item_single_select_value passed the single-select option id with `gh api -F`, which type-infers: an all-digit id (e.g. GH-AW's "91479014") became a JSON number and the String! param rejected it ("provided invalid value"), aborting the whole sweep on the first such item. Dry-run never calls the API, so it was invisible. Fix: send optionId with `-f` (raw string). 3. No per-item resilience. A single transient API error (network blip, secondary rate limit) aborted the entire ~800-item classify sweep under set -e, losing all progress. Fix: per-item error isolation — log a warning, count it, continue; the fill-blanks-only next sweep is idempotent and refills anything left blank. Mirrors reconcile-backlog's model. Tests: +4 reconcile fast-path (prefetch skip add / skip find), +1 regression that an all-numeric option id is sent as a string (-f, not -F). 71 bats green, shellcheck clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] * fix(reviews): address review comments [skip ci-relay] * chore: dev-lead update (review-changes) [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>
…ontentTwin/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>



What this does
Overhauls the Initiatives board population + classification.
1. Classify (Initiative + Theme).
classify-initiative.sh— deterministic, ordered-regex classifier over atitle | labels | reposignature. Cross-cutting infra rules first, product initiatives last (so a SonarCloud sweep inside a product repo → Org Standards, not product work). Writes only per-item field values (never the schema — no option-wipe footgun). Leaves genuinely-unmatched items blank.2. Track all issues (portfolio model). Issues are un-gated — every issue across all installed repos is tracked (minus the excluded-label noise filter). PRs keep the
dev-leadgate (they're transient). An emptyREQUIRED_LABELnow means "no required label".3. Retire Discussion drafting. Discussions are no longer drafted onto the board — Ideas live in GitHub Discussions; an Epic is a parent Issue with sub-issues (a board can't hold a Discussion as real content anyway). Removed the
discussion:trigger, thereconcile-discussionjob, the Ideas backlog scan, andreconcile-discussion.sh+ its tests.Taxonomy
25 Initiative options / 10 Themes (created on the board via the safe read-then-round-trip-all-ids pattern — verified zero orphaning). New this PR: Business Analyst, Cost Observability + per-product initiatives/Themes TalkTerm, Broodly, Markets, Google App Scripts, ContentTwin, and BMAD (Agentic Framework).
broodminder-export→Broodly andrepo-template→Org Standards via existing tokens.Tests
66 bats green (un-gate + PR-gate + issue/PR-kind + product/infra ordering + BMAD/ContentTwin guards);
shellcheck -S warningclean; 4 workflows parse.Activation (two-step, nothing auto-mutates on merge)
Refs #415, #387.
🤖 Generated with Claude Code