(feat): Add issue field validation workflow and structured issue templates#237
(feat): Add issue field validation workflow and structured issue templates#237JustAGhosT wants to merge 6 commits intodevfrom
Conversation
…y, phase, and impact fields Convert issue templates from Markdown to GitHub YAML issue forms with validated dropdown fields. Add feature request template alongside the existing bug report. New fields (area, priority, severity, phase, impact) use preset values derived from teams.yaml and project.yaml enums. Changes: - Replace .github/ISSUE_TEMPLATE/bug_report.md with bug_report.yml (YAML form) - Add .github/ISSUE_TEMPLATE/feature_request.yml with matching fields - Add .github/ISSUE_TEMPLATE/config.yml (disable blank issues, link security advisories) - Add .github/workflows/issue-label-validation.yml (validates fields on issue open/edit, auto-applies area:/priority:/severity: labels) - Update .agentkit/templates/github/ISSUE_TEMPLATE/ source templates - Add issueArea, issuePriority, issueSeverity, issueImpact enums to spec-validator - Add Phase 9 to validate.mjs: validates issue template dropdown values against enums https://claude.ai/code/session_01Ue9aaiqqt1iHDx8KNwQ92m
… and task protocol Wire the new issue area/priority/severity/impact fields into the agent teams orchestration pipeline so issues flow through to the right teams automatically. Changes: - task-protocol: add area, severity fields to task schema with validation, filtering, and display; extend TASK_PRIORITIES to include P4 - orchestrator: add resolveTeamByArea() for area→team routing using teams.yaml intake.routing; add computeEscalation() for dynamic escalation based on severity + impact + area - review-runner: normalize severity values to canonical lowercase (critical/high/medium/low) matching issue templates; export normalizeSeverity() helper - sync-backlog template: add area labels table, severity levels, escalation rules, source tracking, and P4 priority level - sync-backlog prompt: add issue field routing table and escalation rules for Copilot prompt - teams.yaml: add cli→backend and sync-engine→devops intake routing https://claude.ai/code/session_01Ue9aaiqqt1iHDx8KNwQ92m
AgentKit Forge Source Change DetectedThis PR modifies files in the AgentKit Forge source directories:
These are the upstream source-of-truth for all generated AI tool configs. Review checklist
|
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (27)
✨ 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 |
…s and flows Ensure consistent area/priority/severity values in GitHub issue filing, Linear issue filing, and all platform command templates (Copilot, Cursor, Windsurf, Codex). Changes: - review.md: normalize severity from CRITICAL/HIGH/MEDIUM/LOW to canonical lowercase (critical/high/medium/low); add area field to issue filing with file-path→area mapping; use structured labels (severity:X, area:X, priority:X) for both GitHub and Linear - project-review.md: same severity normalization and structured label format; add area field to Phase 1c findings; add canonical field reference section - Copilot TEMPLATE.prompt.md: add issue field routing section with area→team mapping, priority/severity enums, and escalation rules - Cursor TEMPLATE.md: same routing section added - Windsurf command.md: same routing section added - Codex SKILL.md: same routing section added All platforms now reference identical: - Area values (12 canonical values from teams.yaml) - Priority levels (P0–P4) - Severity levels (critical/high/medium/low) - Escalation rules (severity+area→security teams, impact+P0→product) https://claude.ai/code/session_01Ue9aaiqqt1iHDx8KNwQ92m
…robustness
Required fixes:
- review.md: fix uppercase "CRITICAL→P0, HIGH→P1" to lowercase "critical→P0, high→P1"
- validate.mjs Phase 9: make area parsing consistent with severity — extract
bare value before " — " separator so "backend — Server-side" validates correctly
- (PROJECT_ENUMS export verified as already present on line 1086)
Tests:
- orchestrator.test.mjs: add tests for resolveTeamByArea() (default routing,
unknown areas, config overrides, team- prefix handling) and computeEscalation()
(security escalation, blocked cross-team, operations team from config, edge cases)
- review-runner.test.mjs: add tests for normalizeSeverity() (uppercase, lowercase,
mixed case, unknown values)
- validate.test.mjs: add Phase 9 tests (valid dropdowns, invalid area, invalid
severity, malformed template, area options with description separators)
DRY improvements:
- synchronize.mjs: add buildAreaRoutingTable() to generate routing from teams.yaml
and expose as {{intakeAreaRoutingTable}} template variable
- All 4 platform templates (Copilot, Cursor, Windsurf, Codex) now use
{{intakeAreaRoutingTable}} instead of hardcoded routing strings
Performance:
- orchestrator.mjs: add loadTeamsSpec() cache (Map keyed by agentkitRoot) so
resolveTeamByArea() and computeEscalation() read teams.yaml at most once per
process. Export clearTeamsSpecCache() for test isolation.
Robustness:
- computeEscalation(): read operationsTeam from teams.yaml config instead of
hardcoding 'team-quality'
- issue-label-validation.yml: add workflow_dispatch trigger with optional
issue_number input for manual dry-run testing
All 597 tests pass.
https://claude.ai/code/session_01Ue9aaiqqt1iHDx8KNwQ92m
The Copilot prompt template now uses {{intakeAreaRoutingTable}} which
renders the area→team routing as a compact inline string instead of a
full markdown table.
https://claude.ai/code/session_01Ue9aaiqqt1iHDx8KNwQ92m
There was a problem hiding this comment.
Pull request overview
Implements structured GitHub Issue Forms and adds automated validation/routing primitives so issue intake can be normalized (area/priority/severity/impact), consistently labeled, and used for team routing + escalation across AgentKit templates and engines.
Changes:
- Added a GitHub Actions workflow to validate issue form fields and apply labels on issue open/edit.
- Converted bug/feature issue templates to YAML issue forms and disabled blank issues.
- Extended AgentKit engine/spec to include canonical enums + routing/escalation helpers and updated prompts/templates accordingly.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/issue-label-validation.yml |
Adds issue field validation + auto-labeling on issue events. |
.github/prompts/sync-backlog.prompt.md |
Documents area routing + escalation rules for backlog sync. |
.github/ISSUE_TEMPLATE/feature_request.yml |
New structured Issue Form for feature requests (dropdown metadata). |
.github/ISSUE_TEMPLATE/config.yml |
Disables blank issues; adds security advisory contact link. |
.github/ISSUE_TEMPLATE/bug_report.yml |
New structured Issue Form for bug reports (adds severity, etc.). |
.github/ISSUE_TEMPLATE/bug_report.md |
Removes legacy Markdown bug template. |
.agentkit/templates/windsurf/templates/command.md |
Injects area routing + severity/priority guidance into generated commands. |
.agentkit/templates/github/ISSUE_TEMPLATE/feature_request.yml |
Adds template source for generating feature request issue form. |
.agentkit/templates/github/ISSUE_TEMPLATE/config.yml |
Adds template source for generating issue template config (blank issues disabled + contact link). |
.agentkit/templates/github/ISSUE_TEMPLATE/bug_report.yml |
Adds template source for generating bug report issue form. |
.agentkit/templates/github/ISSUE_TEMPLATE/bug_report.md |
Removes legacy Markdown bug template from template source. |
.agentkit/templates/cursor/commands/TEMPLATE.md |
Adds issue routing/escalation guidance to Cursor command template. |
.agentkit/templates/copilot/prompts/TEMPLATE.prompt.md |
Adds issue routing/escalation guidance to Copilot prompt template. |
.agentkit/templates/codex/skills/TEMPLATE/SKILL.md |
Adds issue routing/escalation guidance to Codex skill template. |
.agentkit/templates/claude/commands/sync-backlog.md |
Updates backlog item format (adds severity/source) + routing/escalation rules. |
.agentkit/templates/claude/commands/review.md |
Normalizes severity taxonomy to lowercase canonical values; updates issue-filing labels/fields. |
.agentkit/templates/claude/commands/project-review.md |
Aligns project-review output + issue filing to canonical area/priority/severity fields. |
.agentkit/spec/teams.yaml |
Extends intake routing to include cli and sync-engine areas. |
.agentkit/engines/node/src/validate.mjs |
Adds “Phase 9” validation to ensure issue template dropdown options match canonical enums. |
.agentkit/engines/node/src/task-protocol.mjs |
Extends task protocol with P4 + optional area/severity fields and filtering/formatting. |
.agentkit/engines/node/src/synchronize.mjs |
Adds generation of intakeAreaRoutingTable template var from teams intake routing. |
.agentkit/engines/node/src/spec-validator.mjs |
Introduces canonical enums for issue fields (area/priority/severity/impact). |
.agentkit/engines/node/src/review-runner.mjs |
Adds normalizeSeverity() helper; normalizes automated scan severities to lowercase. |
.agentkit/engines/node/src/orchestrator.mjs |
Adds resolveTeamByArea() and computeEscalation() with teams.yaml-backed behavior + caching. |
.agentkit/engines/node/src/__tests__/validate.test.mjs |
Adds tests covering the new issue template validation phase. |
.agentkit/engines/node/src/__tests__/review-runner.test.mjs |
Adds tests for normalizeSeverity(). |
.agentkit/engines/node/src/__tests__/orchestrator.test.mjs |
Adds tests for routing + escalation helpers (incl config overrides). |
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const issue = context.payload.issue; |
There was a problem hiding this comment.
workflow_dispatch runs will fail because context.payload.issue is undefined for that event type. Either remove workflow_dispatch, or implement the issue_number input by fetching the issue via the REST API before accessing issue.body/issue.number (and skip label/comment writes when running in dry-run mode).
| const issue = context.payload.issue; | |
| // Support both `issues` and `workflow_dispatch` events. | |
| // For `issues`, `context.payload.issue` is populated. | |
| // For `workflow_dispatch`, we expect an `issue_number` input and fetch the issue via REST. | |
| const eventName = context.eventName; | |
| const inputs = (context.payload && context.payload.inputs) || {}; | |
| const issueNumberInput = inputs.issue_number; | |
| let issue = context.payload.issue; | |
| if (!issue) { | |
| if (!issueNumberInput) { | |
| core.setFailed('No issue context available. For workflow_dispatch, provide the "issue_number" input.'); | |
| return; | |
| } | |
| const { data } = await github.rest.issues.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: Number(issueNumberInput), | |
| }); | |
| issue = data; | |
| } | |
| const DRY_RUN = eventName === 'workflow_dispatch'; |
| errors.push(`**Area** "${area}" is not a valid option. Allowed: ${ALLOWED_AREAS.join(', ')}`); | ||
| } | ||
|
|
||
| // Validate priority (required) | ||
| const priority = extractField(body, 'Priority'); | ||
| if (priority && !ALLOWED_PRIORITIES.includes(priority)) { | ||
| errors.push(`**Priority** "${priority}" is not a valid option. Must be P0–P4.`); |
There was a problem hiding this comment.
The script comments indicate Area/Priority are required, but missing values currently pass validation (no error, no invalid-fields label). To enforce consistent intake/routing (and to handle legacy/non-template issues), add explicit errors when required fields are absent (including when rendered as _No response_).
| errors.push(`**Area** "${area}" is not a valid option. Allowed: ${ALLOWED_AREAS.join(', ')}`); | |
| } | |
| // Validate priority (required) | |
| const priority = extractField(body, 'Priority'); | |
| if (priority && !ALLOWED_PRIORITIES.includes(priority)) { | |
| errors.push(`**Priority** "${priority}" is not a valid option. Must be P0–P4.`); | |
| errors.push(`**Area** "${area}" is not a valid option. Allowed: ${ALLOWED_AREAS.join(', ')}`); | |
| } else if (!area) { | |
| errors.push('**Area** is required and must be set to a valid option.'); | |
| } | |
| // Validate priority (required) | |
| const priority = extractField(body, 'Priority'); | |
| if (priority && !ALLOWED_PRIORITIES.includes(priority)) { | |
| errors.push(`**Priority** "${priority}" is not a valid option. Must be P0–P4.`); | |
| } else if (!priority) { | |
| errors.push('**Priority** is required and must be set to a valid option.'); |
| // Apply area label | ||
| if (area && ALLOWED_AREAS.includes(area)) { | ||
| try { | ||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: issue.number, | ||
| labels: [`area:${area}`] | ||
| }); | ||
| } catch (e) { | ||
| core.warning(`Could not add label area:${area} — ${e.message}`); | ||
| } | ||
| } | ||
|
|
||
| // Apply priority label | ||
| if (priority) { | ||
| const prioMatch = priority.match(/^(P\d)/); | ||
| if (prioMatch) { | ||
| try { | ||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: issue.number, | ||
| labels: [`priority:${prioMatch[1].toLowerCase()}`] | ||
| }); | ||
| } catch (e) { | ||
| core.warning(`Could not add priority label — ${e.message}`); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Apply severity label (bug reports) | ||
| if (severity) { | ||
| const sevLevel = severity.split(' — ')[0]; | ||
| if (sevLevel) { | ||
| try { | ||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: issue.number, | ||
| labels: [`severity:${sevLevel}`] | ||
| }); | ||
| } catch (e) { | ||
| core.warning(`Could not add severity label — ${e.message}`); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Post validation comment if errors found | ||
| if (errors.length > 0) { | ||
| const comment = [ | ||
| '## Issue Field Validation Failed', | ||
| '', | ||
| 'The following fields have invalid values:', | ||
| '', | ||
| ...errors.map(e => `- ${e}`), | ||
| '', | ||
| 'Please edit this issue and select valid options from the dropdowns.', | ||
| '', | ||
| '---', | ||
| '*This check is automated by AgentKit Forge issue field validation.*' | ||
| ].join('\n'); | ||
|
|
||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: issue.number, | ||
| body: comment | ||
| }); | ||
|
|
||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: issue.number, | ||
| labels: ['invalid-fields'] | ||
| }); |
There was a problem hiding this comment.
On issue edits, this only ever adds labels; it never removes stale area:*, priority:*, severity:*, or invalid-fields labels when a user changes/fixes the fields. This can leave issues with conflicting labels and permanently-marked invalid state; consider reconciling current labels to the latest field values (remove old labels, and remove invalid-fields when errors.length === 0).
| // Post validation comment if errors found | ||
| if (errors.length > 0) { | ||
| const comment = [ | ||
| '## Issue Field Validation Failed', | ||
| '', | ||
| 'The following fields have invalid values:', | ||
| '', | ||
| ...errors.map(e => `- ${e}`), | ||
| '', | ||
| 'Please edit this issue and select valid options from the dropdowns.', | ||
| '', | ||
| '---', | ||
| '*This check is automated by AgentKit Forge issue field validation.*' | ||
| ].join('\n'); | ||
|
|
||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: issue.number, | ||
| body: comment | ||
| }); |
There was a problem hiding this comment.
Validation comments and error bullets embed user-controlled field values (e.g. area, priority) directly into Markdown. A malicious edit could inject @mentions/links and cause notification spam; consider escaping/formatting values safely (e.g. wrap in code spans and neutralize @), and avoid repeatedly posting new comments on every edit when the same validation failure persists.
| blank_issues_enabled: false | ||
| contact_links: | ||
| - name: Security Vulnerability | ||
| url: https://github.com/{{repoName}}/security/advisories/new |
There was a problem hiding this comment.
{{repoName}} is configured in overlays as a bare repo name (e.g. pvc-costops-analytics), not an owner/repo slug, so this URL will be invalid for most generated repos. Prefer generating a dedicated githubRepository/repoFullName template var (from git remote or explicit spec), or change the template to avoid requiring the owner (e.g. instruct users to fill it in during init).
| url: https://github.com/{{repoName}}/security/advisories/new | |
| url: https://github.com/OWNER/REPO/security/advisories/new |
Merge PR #237 changes into fresh branch from dev. Resolve merge conflict in synchronize.mjs by keeping both buildTeamVars and buildAreaRoutingTable functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Superseded by #284 — all changes consolidated, review comments addressed, and tests passing. |
Summary
Implements automated issue field validation and converts issue templates from Markdown to structured YAML forms with dropdown fields. This enables consistent issue intake, automatic label assignment, and team routing based on issue metadata (area, priority, severity, impact).
Closes #
Changes
issue-label-validation.yml) to validate issue fields on creation/editconfig.yml) to disable blank issuesresolveTeamByArea()andcomputeEscalation()functions to orchestrator for issue routingnormalizeSeverity()helper to review-runner for severity normalizationTest Plan
The validation workflow is automatically triggered on issue open/edit events. Manual testing:
area:backend,priority:p0)invalid-fieldslabelresolveTeamByArea()correctly maps areas to teams per teams.yaml routingcomputeEscalation()applies escalation rules (critical security bugs, P0 all-users impact, etc.)Validation logic is covered by:
agentkit:sync)Checklist
Documentation
Change Impact
Documentation Checklist
https://claude.ai/code/session_01Ue9aaiqqt1iHDx8KNwQ92m