From 11919ac13fd4594487f901988d4fecc48df9422a Mon Sep 17 00:00:00 2001 From: mrizzi Date: Wed, 1 Jul 2026 18:29:06 +0200 Subject: [PATCH] feat(plan-feature): add Epic creation and grouping strategies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend plan-feature Steps 5 and 6 to support Epic hierarchy between Features and Tasks. When a level-1 issue type (Epic) is discovered in Step 2.5, the skill groups tasks into Epics using one of three strategies: by-repository, by-sub-feature, or trivial. Epics are created with parent set to the Feature, and tasks are parented to their assigned Epic. Incorporates links go from Feature to Epics. When no level-1 type exists, the skill falls back to the existing Feature → Task hierarchy unchanged (graceful degradation). Adds three new constraints (1.79-1.81) and a new eval scenario (id 6) with a multi-repo fixture to exercise by-repository grouping. Implements TC-4869 Assisted-by: Claude Code --- docs/constraints.md | 5 +- evals/plan-feature/evals.json | 22 +++ .../files/feature-epic-hierarchy.md | 82 ++++++++++++ .../skills/plan-feature/SKILL.md | 125 ++++++++++++++++-- 4 files changed, 222 insertions(+), 12 deletions(-) create mode 100644 evals/plan-feature/files/feature-epic-hierarchy.md diff --git a/docs/constraints.md b/docs/constraints.md index b53a5c479..92f0a1ce2 100644 --- a/docs/constraints.md +++ b/docs/constraints.md @@ -88,6 +88,9 @@ existing instruction in a SKILL.md or CLAUDE.md file. | 1.76 | `plan-feature` MUST NOT set priority on created tasks when the parent Feature has priority "Undefined" or unset. | `plan-feature/SKILL.md` — Step 1, Step 6 | | 1.77 | `triage-security` MUST extract the Deployment Context column from the Source Repositories table in Security Configuration and use it to annotate remediation task descriptions with context-appropriate coordination guidance (internal, upstream, or customer-shipped). | `triage-security/SKILL.md` — Step 0, `triage-security/remediation-templates.md` — Coordination Guidance | | 1.78 | `triage-security` MUST default all repositories to `upstream` deployment context when the Deployment Context column is absent from the Source Repositories table (backward compatibility). | `triage-security/SKILL.md` — Step 0 | +| 1.79 | `plan-feature` MUST create Epics between Feature and Tasks when a level-1 issue type is discovered in Step 2.5. | `plan-feature/SKILL.md` — Step 6, sub-step 6a.0 | +| 1.80 | `plan-feature` MUST fall back to Feature → Task hierarchy when no level-1 type exists, without error or user prompting. | `plan-feature/SKILL.md` — Step 6, graceful degradation | +| 1.81 | `plan-feature` Epic grouping strategy MUST be configurable via interactive prompt or CLAUDE.md Hierarchy Configuration. | `plan-feature/SKILL.md` — Step 5 | ### Prior Art — Cross-phase integrity (§1.33–1.35) @@ -168,7 +171,7 @@ existing instruction in a SKILL.md or CLAUDE.md file. Each constraint above references its source. The full source files are: -- `plugins/sdlc-workflow/skills/plan-feature/SKILL.md` — Guardrails (§1.1–1.3), Step 1 Priority/fixVersion extraction (§1.74, §1.76), Step 2.5 Discover Project Issue Types (§1.62–1.64), Step 4.5 Determine Workflow Mode (§1.27), Step 5 Convention-aware task enrichment (§4.11, §4.13), Step 5 Target Branch assignment (§4.12), Step 5 Bookend task generation (§3.4), Step 6 Priority/fixVersion inheritance (§1.74, §1.75, §1.76), Step 6a Digest posting (§1.33), Task Description Template (§4.1–4.10) +- `plugins/sdlc-workflow/skills/plan-feature/SKILL.md` — Guardrails (§1.1–1.3), Step 1 Priority/fixVersion extraction (§1.74, §1.76), Step 2.5 Discover Project Issue Types (§1.62–1.64), Step 4.5 Determine Workflow Mode (§1.27), Step 5 Epic grouping (§1.79, §1.81), Step 5 Convention-aware task enrichment (§4.11, §4.13), Step 5 Target Branch assignment (§4.12), Step 5 Bookend task generation (§3.4), Step 6 sub-step 6a.0 Epic creation (§1.79), Step 6 graceful degradation (§1.80), Step 6 Priority/fixVersion inheritance (§1.74, §1.75, §1.76), Step 6a Digest posting (§1.33), Task Description Template (§4.1–4.10) - `plugins/sdlc-workflow/skills/implement-task/SKILL.md` — Important Rules (§1.4–1.6, §5.1–5.3), Step 1 (§1.6), Step 1.5 Digest verification (§1.34, §1.35), Step 4/6/9 (§5.4), Step 5 (§1.15, §3.1, §3.4), Step 7 (§5.9–5.13), Step 9 (§2.1–2.3, §5.6–5.8), Step 10 (§3.2, §3.3) - `plugins/sdlc-workflow/shared/task-description-template.md` — Rules (§4.12) - `plugins/sdlc-workflow/shared/description-digest-protocol.md` — Digest format and verification procedure (§1.33, §1.34, §1.35) diff --git a/evals/plan-feature/evals.json b/evals/plan-feature/evals.json index 94290c325..f17fed816 100644 --- a/evals/plan-feature/evals.json +++ b/evals/plan-feature/evals.json @@ -111,6 +111,28 @@ "When the Feature issue has a non-empty fixVersions array and the fixVersion scope config (from ### Jira Field Defaults in CLAUDE.md) is 'task' or 'both' (or absent, defaulting to 'both'), every created task's additional_fields includes 'fixVersions' with the inherited version(s). When fixVersion scope is 'feature' or the Feature has no fixVersions, the fixVersions key is omitted entirely from additional_fields", "The summary comment on the feature issue (Step 6c) includes the inherited priority and fixVersion values that were propagated to tasks, or states they were omitted and why" ] + }, + { + "id": 6, + "prompt": "Plan the implementation for feature TC-9006. The feature description is in feature-epic-hierarchy.md, the backend repository structure is in repo-backend.md, and the frontend repository structure is in repo-frontend.md. The project has a level-1 issue type named 'Epic' available (hierarchyLevel 1). The default Epic grouping strategy in CLAUDE.md Hierarchy Configuration is 'by-repository'. Write all outputs to the workspace outputs/ directory. For each task you would create, write a markdown file named task-N-slug.md with the full task description. Write the impact map to impact-map.md.", + "expected_output": "A structured implementation plan that creates Epics between the Feature and Tasks, grouped by repository (one Epic for trustify-backend, one for trustify-ui). Each task specifies its parent Epic. The hierarchy is Feature → Epic(s) → Tasks with Incorporates links from Feature to Epics.", + "files": ["files/feature-epic-hierarchy.md", "files/repo-backend.md", "files/repo-frontend.md"], + "assertions": [ + "Epics are generated between Feature and Tasks — at least 2 Epics are created (one per repository) when by-repository grouping is used", + "Each Epic summary follows the format ': ' (e.g., 'TC-9006: trustify-backend', 'TC-9006: trustify-ui')", + "Each task specifies its parent Epic key in the output — tasks targeting trustify-backend are assigned to the backend Epic, tasks targeting trustify-ui are assigned to the frontend Epic", + "Incorporates links are created from the Feature to each Epic (not from Feature to individual Tasks)", + "Task dependency ordering is preserved within and across Epics — backend tasks have lower task numbers than dependent frontend tasks", + "Each task file contains all required template sections: Repository, Target Branch, Description, at least one of Files to Modify or Files to Create, Implementation Notes, Acceptance Criteria, Test Requirements", + "Epics are created with the level-1 issue type name ('Epic') and parent set to the feature issue key", + "Every generated task description contains a Repository section with a single repository name (not multiple repos per task)", + "Every generated task description contains Target Branch, Description, Acceptance Criteria, and Test Requirements sections as required by the handoff contract in task-description-template.md", + "After each task is created, a description digest comment is posted with a format-tagged SHA-256 hash — exactly 64 lowercase hex characters prefixed by 'sha256-md:' or 'sha256-adf:', not a placeholder, abbreviated value, or example string. Marker format: '[sdlc-workflow] Description digest: sha256-md:<64-char-hex>' (or sha256-adf). The digest is computed by re-fetching the description from the API and running scripts/sha256-digest.py", + "Convention-aware enrichment validates file-type applicability per shared/convention-applicability-rules.md before including a convention — inapplicable conventions are excluded entirely (not listed with 'Not applicable' annotations), and applicable ones include a rationale in the prescribed format ('Applies: task modifies matching the convention's '), not free-form prose", + "When the Feature issue has a priority set (not 'Undefined'), every created task's additional_fields includes 'priority' with the inherited priority name. When the Feature's priority is 'Undefined', the priority key is omitted entirely from additional_fields (not set to null or 'Undefined')", + "When the Feature issue has a non-empty fixVersions array and the fixVersion scope config (from ### Jira Field Defaults in CLAUDE.md) is 'task' or 'both' (or absent, defaulting to 'both'), every created task's additional_fields includes 'fixVersions' with the inherited version(s). When fixVersion scope is 'feature' or the Feature has no fixVersions, the fixVersions key is omitted entirely from additional_fields", + "The summary comment on the feature issue (Step 6c) includes the inherited priority and fixVersion values that were propagated to tasks, or states they were omitted and why" + ] } ] } diff --git a/evals/plan-feature/files/feature-epic-hierarchy.md b/evals/plan-feature/files/feature-epic-hierarchy.md new file mode 100644 index 000000000..2b3f30e43 --- /dev/null +++ b/evals/plan-feature/files/feature-epic-hierarchy.md @@ -0,0 +1,82 @@ + + +# Mock Jira Feature Issue + +**Key**: TC-9006 +**Summary**: Add vulnerability remediation tracking dashboard +**Status**: New +**Priority**: Major +**Fix Versions**: RHTPA 1.5.0 +**Labels**: ai-generated-jira +**Linked Issues**: None + +--- + +## Feature Overview + +Add a vulnerability remediation tracking dashboard that shows the progress of fixing known vulnerabilities across all ingested SBOMs. The backend provides aggregation endpoints for remediation status by severity and by product, while the frontend renders a dashboard page with summary cards, a progress chart, and a filterable table of outstanding vulnerabilities. + +## Background and Strategic Fit + +Security teams need visibility into remediation progress across the entire portfolio. Currently, users must navigate individual SBOM detail pages and manually tally vulnerability statuses. A centralized dashboard with backend aggregation reduces time-to-insight and supports management reporting on remediation SLAs. + +## Goals + +- **Who benefits**: Security managers tracking remediation SLAs, engineering leads prioritizing fix work +- **Current state**: No aggregated remediation view — users manually check individual SBOMs +- **Target state**: A dashboard page showing remediation progress with drill-down to individual vulnerabilities +- **Goal statements**: + - Provide portfolio-wide remediation visibility in a single page + - Enable filtering by severity, product, and remediation status + +## Requirements + +| Requirement | Notes | Is MVP? | +|---|---|---| +| `GET /api/v2/remediation/summary` returns aggregated counts by severity and status | Groups by: severity (Critical/High/Medium/Low) × status (Open/In Progress/Resolved) | Yes | +| `GET /api/v2/remediation/by-product` returns per-product remediation breakdown | Each product entry includes total, open, resolved counts | Yes | +| Dashboard page at `/remediation` with summary cards and progress chart | Cards show total open, in-progress, resolved; chart shows trend over time | Yes | +| Filterable vulnerability table on the dashboard | Filter by severity, product, status | Yes | +| Export remediation report as CSV | For management reporting | No | + +## Non-Functional Requirements + +- Summary endpoint response time: p95 < 500ms +- Dashboard must handle up to 10,000 tracked vulnerabilities without performance degradation +- No new database tables — compute aggregations from existing vulnerability and SBOM relationship data + +## Use Cases (User Experience & Workflow) + +### UC-1: View remediation summary + +**Persona**: Security manager checking weekly remediation progress +**Pre-conditions**: Vulnerabilities have been correlated with ingested SBOMs +**Steps**: +1. User navigates to `/remediation` +2. Dashboard loads summary cards showing total Open, In Progress, and Resolved counts +3. Progress chart shows remediation trend over the past 30 days +4. User reviews the filterable table below for outstanding Critical vulnerabilities + +**Expected outcome**: Full remediation status visible on a single page + +### UC-2: Filter by product + +**Persona**: Engineering lead prioritizing fix work for a specific product +**Pre-conditions**: Multiple products have ingested SBOMs with correlated vulnerabilities +**Steps**: +1. User navigates to `/remediation` +2. User selects a product from the product filter dropdown +3. Dashboard updates to show only vulnerabilities affecting that product +4. User sorts by severity to identify critical items first + +**Expected outcome**: Product-specific remediation view for prioritization + +## Customer Considerations + +- Remediation status depends on advisory correlation being up to date +- Large portfolios (>50 products) may require pagination in the product breakdown + +## Documentation Considerations + +- **Doc Impact**: New Content — document the remediation dashboard and aggregation endpoints +- **User purpose**: Security teams need a guide for using the dashboard; API consumers need endpoint reference diff --git a/plugins/sdlc-workflow/skills/plan-feature/SKILL.md b/plugins/sdlc-workflow/skills/plan-feature/SKILL.md index 2fd1c91d4..11727d5f2 100644 --- a/plugins/sdlc-workflow/skills/plan-feature/SKILL.md +++ b/plugins/sdlc-workflow/skills/plan-feature/SKILL.md @@ -552,6 +552,49 @@ Before generating task descriptions, read `docs/constraints.md` from the project Create implementation tasks for each unit of work. Each task description MUST follow the template defined in [`shared/task-description-template.md`](../shared/task-description-template.md) exactly — read the template and rules from that file before generating tasks. +### Epic grouping (when available) + +If Step 2.5 discovered a level-1 type (Epic role), group tasks into Epics before +generating individual task descriptions. If no level-1 type was found, skip this +section entirely — generate tasks as before (Feature → Task hierarchy). + +#### Determine grouping strategy + +Check if CLAUDE.md `## Hierarchy Configuration` has a `Default epic grouping strategy` +setting: + +- If set to a valid strategy (`by-repository`, `by-sub-feature`, or `trivial`), use it. +- If set to `none`, or if the setting is absent, present an interactive prompt: + + ``` + How should tasks be grouped into Epics? + + 1. by-repository — one Epic per repository in the impact map + 2. by-sub-feature — group by logical sub-features (I'll suggest groupings) + 3. trivial — single Epic wrapping all tasks (1:1 with Feature) + + Choose (1/2/3): + ``` + +#### Generate Epic descriptions + +For each Epic group, generate: + +- **Summary**: `: ` (e.g., "TC-4866: sdlc-plugins" for + by-repository, "TC-4866: Dynamic issue type discovery" for by-sub-feature, + "TC-4866: Implementation" for trivial) +- **Description**: brief plain-text summary of the tasks in this group. Epics use + plain text, not the structured task template. + +#### Assign tasks to Epics + +Annotate each task with its Epic group assignment: + +- **by-repository**: group by the task's Repository section. +- **by-sub-feature**: present suggested groupings to the user for approval before + finalizing. +- **trivial**: all tasks belong to the single Epic. + ### Documentation task guidance When a feature introduces significant new behavior (new user-facing capabilities, new APIs, or major architectural changes), consider generating a **dedicated documentation-only task** to cover cross-cutting documentation updates that span multiple implementation tasks. Use this when the documentation work is substantial enough to warrant its own task rather than being spread across individual implementation tasks. @@ -769,6 +812,50 @@ that already has bookend tasks from a previous run. ## Step 6 – Create Tasks in Jira +### 6a.0 – Create Epics (when available) + +When Step 2.5 discovered a level-1 type and Epic grouping was performed in Step 5, +create the Epic issues before creating tasks. If no level-1 type was found (the +no-Epic flag was set), skip this sub-step entirely. + +For each Epic group defined in Step 5: + +1. **Create the Epic issue:** + + ``` + jira.create_issue( + projectKey=, + issueTypeName=, + summary=": ", + description=, + parent=, + additional_fields={ + "labels": ["ai-generated-jira"], + "priority": {"name": ""}, + "fixVersions": [{"name": ""}] + } + ) + ``` + + Apply the same conditional inclusion rules for `priority` and `fixVersions` as + defined in sub-step 6a (include only when set on the Feature; respect `fixVersion + scope` from Jira Field Defaults). + +2. **Record the Epic key:** map each Epic group label to its created Jira key (e.g., + "sdlc-plugins" → PROJ-240). This mapping is used in sub-step 6a to set task + parents. + +#### Graceful degradation + +When no level-1 type is available (Step 2.5 set the no-Epic flag): + +- Skip sub-step 6a.0 entirely. +- Tasks are created with no `parent` field (or with Feature as parent if the project + supports it). +- "Incorporates" links go from Feature to Tasks as before. +- This ensures backward compatibility: projects without hierarchy configuration + continue to work with the current Feature → Task behavior. + ### 6a – Create the tasks Use: @@ -802,6 +889,12 @@ additional_fields: { **On MCP failure, if REST API chosen (Step 0.5):** use the `--priority` and `--fix-versions` flags on `create_issue` (see REST API equivalents in Step 0.5). Omit the flag entirely when the value should not be propagated. +**Epic-aware parent field:** when Epics were created in sub-step 6a.0, set each task's +`parent` field to its assigned Epic key (from the Epic group mapping built in 6a.0). +This establishes the Task → Epic hierarchy. When no Epics are available, omit the +`parent` field (or set it to the Feature key if the project supports it) — preserving +the existing behavior. + As each task is created, record a mapping of **task number/title → Jira key** (e.g. "Task 1 — Add CSV endpoint" → PROJ-231). This mapping is needed for link creation below. When the workflow mode is `feature-branch`, add the `workflow:feature-branch` label to @@ -874,21 +967,31 @@ including consumer verification behavior and common mistakes to avoid. ### 6b – Create issue links -After **all** tasks are created (so all Jira keys are known), create two kinds of links: +After **all** tasks (and Epics, if applicable) are created, create the following links: -**Feature "incorporates" each task:** +**Feature "incorporates" links:** -For every created task, call: +- **When Epics are available:** create "Incorporates" links from the Feature to each + **Epic** (not to individual Tasks). Tasks inherit hierarchy through their Epic parent. -``` -jira.create_issue_link( - link_type="Incorporates", - inward_issue_key=, - outward_issue_key= -) -``` + ``` + jira.create_issue_link( + link_type="Incorporates", + inward_issue_key=, + outward_issue_key= + ) + ``` + +- **When no Epics are available (graceful degradation):** create "Incorporates" links + from the Feature to each **Task** as before: -This makes the feature show "incorporates TASK-X" and the task show "is incorporated by FEATURE-Y". + ``` + jira.create_issue_link( + link_type="Incorporates", + inward_issue_key=, + outward_issue_key= + ) + ``` **Task "depends on" other tasks:**