gaia-framework 1.66.0 → 1.83.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/gaia-create-stakeholder.md +20 -0
- package/.claude/commands/gaia-test-gap-analysis.md +17 -0
- package/CLAUDE.md +87 -1
- package/README.md +2 -2
- package/_gaia/_config/global.yaml +5 -1
- package/_gaia/_config/lifecycle-sequence.yaml +20 -0
- package/_gaia/_config/skill-manifest.csv +2 -0
- package/_gaia/_config/workflow-manifest.csv +3 -1
- package/_gaia/core/engine/workflow.xml +5 -1
- package/_gaia/core/workflows/party-mode/steps/step-01-agent-loading.md +60 -9
- package/_gaia/creative/workflows/problem-solving/checklist.md +64 -14
- package/_gaia/creative/workflows/problem-solving/instructions.xml +367 -22
- package/_gaia/creative/workflows/problem-solving/workflow.yaml +31 -1
- package/_gaia/dev/agents/_base-dev.md +7 -1
- package/_gaia/dev/skills/_skill-index.yaml +9 -0
- package/_gaia/dev/skills/figma-integration.md +296 -0
- package/_gaia/lifecycle/templates/brownfield-scan-security-prompt.md +228 -0
- package/_gaia/lifecycle/templates/gap-entry-schema.md +39 -4
- package/_gaia/lifecycle/templates/story-template.md +22 -1
- package/_gaia/lifecycle/workflows/2-planning/create-ux-design/instructions.xml +52 -3
- package/_gaia/lifecycle/workflows/4-implementation/create-stakeholder/checklist.md +25 -0
- package/_gaia/lifecycle/workflows/4-implementation/create-stakeholder/instructions.xml +79 -0
- package/_gaia/lifecycle/workflows/4-implementation/create-stakeholder/workflow.yaml +22 -0
- package/_gaia/lifecycle/workflows/4-implementation/create-story/instructions.xml +10 -0
- package/_gaia/lifecycle/workflows/4-implementation/retrospective/instructions.xml +3 -3
- package/_gaia/lifecycle/workflows/4-implementation/validate-story/instructions.xml +11 -0
- package/_gaia/lifecycle/workflows/anytime/brownfield-onboarding/instructions.xml +11 -7
- package/_gaia/testing/workflows/test-gap-analysis/checklist.md +8 -0
- package/_gaia/testing/workflows/test-gap-analysis/instructions.xml +53 -0
- package/_gaia/testing/workflows/test-gap-analysis/workflow.yaml +38 -0
- package/bin/gaia-framework.js +36 -2
- package/bin/helpers/derive-bump-label.js +41 -0
- package/bin/helpers/validate-bump-labels.js +38 -0
- package/gaia-install.sh +71 -4
- package/package.json +1 -1
- package/_gaia/_memory/tier2-results/.gitkeep +0 -0
- package/_gaia/_memory/tier2-results/checkpoint-resume-2026-03-24.yaml +0 -6
- package/_gaia/_memory/tier2-results/engine-scenarios-2026-03-22.yaml +0 -14
|
@@ -12,6 +12,8 @@ points: "{story_points}"
|
|
|
12
12
|
risk: "{high/medium/low}"
|
|
13
13
|
sprint_id: null
|
|
14
14
|
priority_flag: null
|
|
15
|
+
origin: null
|
|
16
|
+
origin_ref: null
|
|
15
17
|
depends_on: []
|
|
16
18
|
blocks: []
|
|
17
19
|
traces_to: []
|
|
@@ -116,4 +118,23 @@ As a {role}, I want to {action}, so that {benefit}.
|
|
|
116
118
|
|
|
117
119
|
## Definition of Done
|
|
118
120
|
|
|
119
|
-
|
|
121
|
+
### Acceptance
|
|
122
|
+
|
|
123
|
+
- [ ] All acceptance criteria verified and checked off
|
|
124
|
+
- [ ] All subtasks marked complete
|
|
125
|
+
|
|
126
|
+
### Testing
|
|
127
|
+
|
|
128
|
+
- [ ] All tests pass (unit, integration, e2e as applicable)
|
|
129
|
+
- [ ] No linting or formatting errors
|
|
130
|
+
|
|
131
|
+
### Code Quality & CI
|
|
132
|
+
|
|
133
|
+
- [ ] Code compiles / builds without errors
|
|
134
|
+
- [ ] Code follows project conventions
|
|
135
|
+
- [ ] No hardcoded secrets or credentials
|
|
136
|
+
- [ ] PR merged to staging with all CI checks passing
|
|
137
|
+
|
|
138
|
+
### Documentation
|
|
139
|
+
|
|
140
|
+
- [ ] Documentation updated (if applicable)
|
|
@@ -32,12 +32,61 @@
|
|
|
32
32
|
<action>Plan keyboard navigation, screen reader support</action>
|
|
33
33
|
<action>Define color contrast and text sizing standards</action>
|
|
34
34
|
</step>
|
|
35
|
-
<step n="7" title="
|
|
35
|
+
<step n="7" title="Figma MCP Detection and Mode Selection">
|
|
36
|
+
<action>Probe for available Figma MCP server. Load figma-integration.md detection section JIT to determine if a design tool adapter is available.</action>
|
|
37
|
+
<action if="figma_mcp_available">Present mode selection to user: [Generate] Create Figma frames alongside ux-design.md | [Import] Import existing Figma designs (read-only) | [Skip] Text-only UX spec, no Figma integration</action>
|
|
38
|
+
<action if="not figma_mcp_available">Skip Figma integration — proceed with text-only UX design output. Log: "No Figma MCP server detected. Generating markdown-only ux-design.md."</action>
|
|
39
|
+
</step>
|
|
40
|
+
<step n="8" title="Generate Mode — UI Kit Page Creation" if="figma_mcp_available AND user_selected_generate">
|
|
41
|
+
<critical>
|
|
42
|
+
<mandate>Generate mode is the ONLY mode that performs write operations to Figma (FR-140). All other modes are read-only. Write operations: create pages, create frames, create component instances. Minimum required Figma API scopes: files:read + file_content:read + files:write.</mandate>
|
|
43
|
+
</critical>
|
|
44
|
+
<action>Load figma-integration.md frames section JIT from _gaia/dev/skills/figma-integration.md</action>
|
|
45
|
+
<action>Create a UI Kit page named "UI Kit — Generated" in the Figma design file via MCP</action>
|
|
46
|
+
<action>Extract design tokens from {planning_artifacts}/design-system/design-tokens.json (W3C DTCG format)</action>
|
|
47
|
+
<action>Create color styles with semantic aliases from token definitions (e.g., color.surface.primary, color.text.primary)</action>
|
|
48
|
+
<action>Create typography styles from composite token specs (heading-1, heading-2, body, caption)</action>
|
|
49
|
+
<action>Create spacing grid tokens and base components with state variants (default, hover, active, disabled, focus)</action>
|
|
50
|
+
<action>Error handling: on HTTP 429 rate limit, perform a single retry after backoff. If 429 persists, graceful fallback to markdown-only flow — log warning and skip remaining Figma operations.</action>
|
|
51
|
+
</step>
|
|
52
|
+
<step n="9" title="Generate Mode — Per-Screen Frame Generation" if="figma_mcp_available AND user_selected_generate">
|
|
53
|
+
<action>Parse PRD user journeys to determine screens needing frames</action>
|
|
54
|
+
<action>For each screen, generate frames at 6 viewports: 280px (foldable inner, FR-174), 375px (mobile), 600px (foldable outer, FR-174), 768px (tablet portrait), 1024px (tablet landscape, FR-174), 1280px (desktop)</action>
|
|
55
|
+
<action>Compose frames using UI Kit components from the previous step — apply auto-layout with responsive constraints from component specs</action>
|
|
56
|
+
<action>Label frames using naming convention: {ScreenName}/{Viewport} (e.g., Dashboard/Desktop, Login/Mobile)</action>
|
|
57
|
+
<action>Collect all generated Figma node IDs for downstream recording in ux-design.md</action>
|
|
58
|
+
</step>
|
|
59
|
+
<step n="10" title="Generate Mode — Prototype Flow Setup" if="figma_mcp_available AND user_selected_generate">
|
|
60
|
+
<action>Map PRD user journey steps to the generated screen frames</action>
|
|
61
|
+
<action>Create prototype flow connections between frames via Figma MCP, linking screens in the order defined by each user journey</action>
|
|
62
|
+
<action>Validate flow completeness: every user journey step must map to a generated frame. Flag any unmapped journey steps as warnings.</action>
|
|
63
|
+
</step>
|
|
64
|
+
<step n="11" title="Generate Mode — Asset Export Configuration" if="figma_mcp_available AND user_selected_generate">
|
|
65
|
+
<action>Configure PNG export at 1x, 2x, 3x densities for raster assets (images, illustrations)</action>
|
|
66
|
+
<action>Configure SVG export for icon components</action>
|
|
67
|
+
<action>Generate platform-specific asset catalogs per FR-175: iOS .xcassets catalog structure with Contents.json manifests, Android drawable-mdpi/drawable-hdpi/drawable-xhdpi/drawable-xxhdpi/drawable-xxxhdpi directories</action>
|
|
68
|
+
<action>Write export configuration and asset manifest to {planning_artifacts}/design-system/assets/ directory</action>
|
|
69
|
+
<action>Check {project-path}/.figma-cache/ for cached responses (1h TTL) before making MCP read calls — use cached data if fresh, fetch and cache if stale or missing</action>
|
|
70
|
+
</step>
|
|
71
|
+
<step n="12" title="Generate Mode — Record Figma Node IDs and Enhance ux-design.md" if="figma_mcp_available AND user_selected_generate">
|
|
72
|
+
<action>Build Screen-to-Frame mapping table from all generated Figma node IDs: columns Screen Name | Viewport | Figma Node ID | Page</action>
|
|
73
|
+
<action>Add figma: YAML frontmatter block to ux-design.md containing: file_key, pages array with node IDs for each generated page, and last_synced ISO 8601 timestamp</action>
|
|
74
|
+
<action>Add Design Tokens reference section linking to {planning_artifacts}/design-system/design-tokens.json with token category summary</action>
|
|
75
|
+
<action>Add Component Inventory section listing all generated UI Kit components with their Figma node IDs, variant counts, and state definitions</action>
|
|
76
|
+
<action>Add Screen-to-Frame mapping table with all generated frames across all viewports</action>
|
|
77
|
+
<action>Ensure backward compatibility: existing text-only ux-design.md content is preserved. Figma sections are additive — they appear after the standard UX design sections.</action>
|
|
78
|
+
</step>
|
|
79
|
+
<step n="13" title="Generate Output">
|
|
36
80
|
<template-output file="{planning_artifacts}/ux-design.md">
|
|
37
|
-
Generate UX design document with: personas, information architecture, wireframe descriptions, interaction patterns, component specifications, accessibility plan,
|
|
81
|
+
Generate UX design document with: personas, information architecture, wireframe descriptions, interaction patterns, component specifications, accessibility plan, FR-to-Screen Mapping table (FR ID | Screen/Page | Wireframe Section). If Generate mode was active: include figma: frontmatter block, Design Tokens section, Component Inventory with Figma node IDs, and Screen-to-Frame mapping table.
|
|
38
82
|
</template-output>
|
|
39
83
|
</step>
|
|
40
|
-
<step n="
|
|
84
|
+
<step n="14" title="FR-140 Compliance Check" if="figma_mcp_available AND user_selected_generate">
|
|
85
|
+
<action>Audit all MCP calls executed during Generate mode: classify each as READ (get_file, get_styles, get_components, get_images, get_frames) or WRITE (create_frame, create_component_instance, create_page)</action>
|
|
86
|
+
<action>Verify FR-140 constraint: write operations only occurred during Generate mode steps (8–12). Import mode and Skip mode must have zero write calls.</action>
|
|
87
|
+
<action>Document minimum required Figma API scopes: files:read + file_content:read (default for all modes), files:write (Generate mode only)</action>
|
|
88
|
+
</step>
|
|
89
|
+
<step n="15" title="Optional: Accessibility Review">
|
|
41
90
|
<ask>Would you like to review the UX design for WCAG 2.1 accessibility compliance? This spawns a subagent in a separate context. Recommended for user-facing applications. (yes / skip)</ask>
|
|
42
91
|
<action>If yes: spawn a subagent using the Agent tool: "Load {project-root}/_gaia/core/tasks/review-accessibility.xml. Read its entire contents. Target: {planning_artifacts}/ux-design.md. Follow the flow steps EXACTLY. Generate accessibility findings report."</action>
|
|
43
92
|
<action>If skip: accessibility review can be run anytime later with /gaia-review-a11y</action>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Create Stakeholder Validation'
|
|
3
|
+
validation-target: 'Stakeholder file'
|
|
4
|
+
---
|
|
5
|
+
## Structure
|
|
6
|
+
- [ ] workflow.yaml present with agent: orchestrator
|
|
7
|
+
- [ ] instructions.xml present with sequential steps
|
|
8
|
+
- [ ] checklist.md present
|
|
9
|
+
- [ ] Registered in workflow-manifest.csv
|
|
10
|
+
- [ ] Slash command file exists at .claude/commands/gaia-create-stakeholder.md
|
|
11
|
+
## Input Collection
|
|
12
|
+
- [ ] Required fields prompted: name, role, expertise, personality
|
|
13
|
+
- [ ] Optional fields prompted: perspective, tags
|
|
14
|
+
- [ ] Required field validation (non-empty check)
|
|
15
|
+
## Validation Guards
|
|
16
|
+
- [ ] 50-file cap enforced before file creation
|
|
17
|
+
- [ ] Case-insensitive duplicate name detection against existing stakeholder name frontmatter
|
|
18
|
+
- [ ] custom/stakeholders/ directory auto-created if missing
|
|
19
|
+
## Output
|
|
20
|
+
- [ ] Filename is kebab-case slug of name with .md extension
|
|
21
|
+
- [ ] File written to custom/stakeholders/{slug}.md
|
|
22
|
+
- [ ] YAML frontmatter includes all required fields
|
|
23
|
+
- [ ] Optional fields included only when provided
|
|
24
|
+
- [ ] Markdown body with ## Background section
|
|
25
|
+
- [ ] File does not exceed 100 lines
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<workflow name="create-stakeholder">
|
|
2
|
+
<critical>
|
|
3
|
+
<mandate>Stakeholder files are written to custom/stakeholders/ — never to _gaia/</mandate>
|
|
4
|
+
<mandate>The 50-file cap and 100-line limit are hard gates (FR-164)</mandate>
|
|
5
|
+
<mandate>Duplicate name detection is case-insensitive against the name frontmatter field (FR-157)</mandate>
|
|
6
|
+
</critical>
|
|
7
|
+
|
|
8
|
+
<step n="1" title="Ensure Directory Exists">
|
|
9
|
+
<action>Check if {project-root}/custom/stakeholders/ directory exists</action>
|
|
10
|
+
<action if="directory does not exist">Create {project-root}/custom/stakeholders/ directory (and {project-root}/custom/ if needed)</action>
|
|
11
|
+
<action>Confirm directory is ready for writing</action>
|
|
12
|
+
</step>
|
|
13
|
+
|
|
14
|
+
<step n="2" title="Collect Required Inputs">
|
|
15
|
+
<ask>Provide the following required fields for the new stakeholder:
|
|
16
|
+
|
|
17
|
+
**Name** (display name, e.g., "Maria Santos"):
|
|
18
|
+
**Role** (title/function, e.g., "Housekeeper Manager"):
|
|
19
|
+
**Expertise** (domain skills, e.g., "Room turnover logistics"):
|
|
20
|
+
**Personality** (traits, e.g., "Pragmatic, detail-oriented"):
|
|
21
|
+
</ask>
|
|
22
|
+
<check if="any required field is empty">HALT: All four fields (name, role, expertise, personality) are required. Please provide all values.</check>
|
|
23
|
+
</step>
|
|
24
|
+
|
|
25
|
+
<step n="3" title="Collect Optional Inputs">
|
|
26
|
+
<ask>Optionally provide these additional fields (press Enter to skip):
|
|
27
|
+
|
|
28
|
+
**Perspective** (viewpoint/biases, e.g., "Focuses on operational efficiency"):
|
|
29
|
+
**Tags** (comma-separated, e.g., "operations, hospitality"):
|
|
30
|
+
</ask>
|
|
31
|
+
</step>
|
|
32
|
+
|
|
33
|
+
<step n="4" title="Validate Against Cap and Duplicates">
|
|
34
|
+
<action>Count existing .md files in {project-root}/custom/stakeholders/ directory</action>
|
|
35
|
+
<check if="count >= 50">HALT: The 50-file cap has been reached in custom/stakeholders/ (FR-164). There are already {count} stakeholder files. Remove unused stakeholders before creating new ones.</check>
|
|
36
|
+
<action>Scan all existing stakeholder files in custom/stakeholders/*.md — read the name field from each file's YAML frontmatter</action>
|
|
37
|
+
<action>Compare each existing name against the new stakeholder name using case-insensitive comparison</action>
|
|
38
|
+
<check if="duplicate name found (case-insensitive match)">HALT: A stakeholder with the name "{existing_name}" already exists at custom/stakeholders/{existing_file}. Name collision detected (case-insensitive). Choose a different name.</check>
|
|
39
|
+
</step>
|
|
40
|
+
|
|
41
|
+
<step n="5" title="Generate Filename Slug">
|
|
42
|
+
<action>Convert the stakeholder name to a kebab-case slug:
|
|
43
|
+
1. Convert to lowercase
|
|
44
|
+
2. Replace spaces with hyphens
|
|
45
|
+
3. Strip all characters that are not alphanumeric or hyphens
|
|
46
|
+
4. Collapse multiple consecutive hyphens into a single hyphen
|
|
47
|
+
5. Trim leading/trailing hyphens
|
|
48
|
+
6. Append .md extension
|
|
49
|
+
</action>
|
|
50
|
+
<action>Example: "Maria Santos" → "maria-santos.md", "Jean-Pierre O'Brien III" → "jean-pierre-obrien-iii.md"</action>
|
|
51
|
+
<action>Set output path: {project-root}/custom/stakeholders/{slug}.md</action>
|
|
52
|
+
<check if="file already exists at output path">HALT: File custom/stakeholders/{slug}.md already exists. This may indicate a slug collision from a different display name. Choose a different name or remove the existing file.</check>
|
|
53
|
+
</step>
|
|
54
|
+
|
|
55
|
+
<step n="6" title="Generate and Write Stakeholder File">
|
|
56
|
+
<action>Generate the stakeholder file with YAML frontmatter and Markdown body:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
---
|
|
60
|
+
name: "{name}"
|
|
61
|
+
role: "{role}"
|
|
62
|
+
expertise: "{expertise}"
|
|
63
|
+
personality: "{personality}"
|
|
64
|
+
perspective: "{perspective}" # Only include if provided
|
|
65
|
+
tags: [{tags_as_yaml_array}] # Only include if provided
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Background
|
|
69
|
+
|
|
70
|
+
{A 2-3 sentence description synthesized from the provided fields, describing this stakeholder's viewpoint and discussion style.}
|
|
71
|
+
```
|
|
72
|
+
</action>
|
|
73
|
+
<action>Verify the generated file does not exceed 100 lines. If it does, trim the Background section to fit within the limit.</action>
|
|
74
|
+
<action>Write the file to {project-root}/custom/stakeholders/{slug}.md</action>
|
|
75
|
+
<template-output file="{project-root}/custom/stakeholders/{slug}.md">
|
|
76
|
+
Stakeholder file with YAML frontmatter (name, role, expertise, personality, and optionally perspective and tags) plus a Markdown Background section.
|
|
77
|
+
</template-output>
|
|
78
|
+
</step>
|
|
79
|
+
</workflow>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: create-stakeholder
|
|
2
|
+
description: 'Scaffold a new stakeholder file for Party Mode discussions'
|
|
3
|
+
module: lifecycle
|
|
4
|
+
agent: orchestrator
|
|
5
|
+
config_resolved: "{installed_path}/.resolved/create-stakeholder.yaml"
|
|
6
|
+
config_source: "{project-root}/_gaia/lifecycle/config.yaml"
|
|
7
|
+
installed_path: "{project-root}/_gaia/lifecycle/workflows/4-implementation/create-stakeholder"
|
|
8
|
+
instructions: "{installed_path}/instructions.xml"
|
|
9
|
+
validation: "{installed_path}/checklist.md"
|
|
10
|
+
quality_gates:
|
|
11
|
+
pre_start: []
|
|
12
|
+
post_complete:
|
|
13
|
+
- check: "stakeholder_file_line_count_valid == true"
|
|
14
|
+
on_fail: "HALT: Stakeholder file exceeds 100-line limit (FR-164). Edit {project-root}/custom/stakeholders/{slug}.md to reduce content or re-run /gaia-create-stakeholder."
|
|
15
|
+
- check: "stakeholder_count_in_directory_valid == true"
|
|
16
|
+
on_fail: "HALT: custom/stakeholders/ has more than 50 files (FR-164). Remove unused stakeholders from {project-root}/custom/stakeholders/ first."
|
|
17
|
+
on_error:
|
|
18
|
+
missing_file: "ask_user"
|
|
19
|
+
unresolved_variable: "halt"
|
|
20
|
+
|
|
21
|
+
output:
|
|
22
|
+
primary: "{project-root}/custom/stakeholders/{slug}.md"
|
|
@@ -94,6 +94,14 @@
|
|
|
94
94
|
<step n="6" title="Generate Output">
|
|
95
95
|
<action>Read the story template from the engine-resolved template path. The engine resolves this in Step 1 (Load and Resolve Config): if {project-root}/custom/templates/story-template.md exists and is non-empty, the custom template is used; otherwise it falls back to {project-root}/_gaia/lifecycle/templates/story-template.md. Use whichever path the engine resolved.</action>
|
|
96
96
|
<action>Read sizing_map from {project-root}/_gaia/_config/global.yaml to resolve T-shirt size to story points (S→2, M→5, L→8, XL→13).</action>
|
|
97
|
+
<action>Detect invocation context to determine origin fields:
|
|
98
|
+
If invoked from problem-solving routing (E16-S3): set origin="problem-solving" and origin_ref to the path of the Problem Brief or problem-solving checkpoint artifact (e.g., docs/creative-artifacts/problem-solving-YYYY-MM-DD.md).
|
|
99
|
+
If invoked from triage routing: set origin="triage" and origin_ref to the triage artifact path.
|
|
100
|
+
If invoked from add-feature routing: set origin="add-feature" and origin_ref to the source artifact path.
|
|
101
|
+
If invoked from sprint-planning: set origin="sprint-planning" and origin_ref to the sprint plan artifact path.
|
|
102
|
+
If invoked with explicit origin parameters from caller: use the provided origin and origin_ref values.
|
|
103
|
+
If invoked normally (no routing context): set origin=null and origin_ref=null (planned work default).
|
|
104
|
+
</action>
|
|
97
105
|
<action>Populate ALL YAML frontmatter fields from epics-and-stories.md data:
|
|
98
106
|
- key: story key from epics (e.g., E1-S1)
|
|
99
107
|
- title: story title
|
|
@@ -110,6 +118,8 @@
|
|
|
110
118
|
- date: current date
|
|
111
119
|
- author: agent name (e.g., "Nate (Scrum Master)")
|
|
112
120
|
- priority_flag: null (default — set to "next-sprint" by add-feature for high-urgency stories)
|
|
121
|
+
- origin: workflow origin (null for planned work, "problem-solving" from problem-solving routing, "triage" from triage, "add-feature" from add-feature routing, "sprint-planning" from sprint planning, "manual" for explicit manual creation)
|
|
122
|
+
- origin_ref: path to source artifact that triggered story creation (null when origin is null)
|
|
113
123
|
</action>
|
|
114
124
|
<template-output file="{implementation_artifacts}/{story_key}-{story_title_slug}.md">
|
|
115
125
|
Generate the story file following the story-template.md structure. The filename must use the story key and slugified title (e.g., E1-S1-user-login.md). Include complete YAML frontmatter with ALL 15 fields populated. Fill all template sections: User Story, Acceptance Criteria, Tasks/Subtasks (linked to AC numbers), Dev Notes, Technical Notes, Dependencies, Test Scenarios, Project Structure Notes, References, Dev Agent Record, and Estimate. IMPORTANT: The body "**Status:**" line MUST match the frontmatter status field exactly. Both must say the same status value.
|
|
@@ -108,14 +108,14 @@
|
|
|
108
108
|
|
|
109
109
|
3. Apply the improvement: append to or modify the relevant section in custom/skills/{skill-name}.md with comment "<!-- Added from retro-{sprint_id}: {reason} -->".
|
|
110
110
|
|
|
111
|
-
4. Register in .customize.yaml: after writing the custom skill file, register it in {project-root}/
|
|
112
|
-
- If all-dev.customize.yaml does not exist: create it with proper YAML structure:
|
|
111
|
+
4. Register in .customize.yaml: after writing the custom skill file, register it in {project-root}/custom/skills/all-dev.customize.yaml so the engine loads from the custom path on subsequent runs (ADR-020 — customization registries live alongside custom skills in custom/skills/).
|
|
112
|
+
- If custom/skills/all-dev.customize.yaml does not exist: create it with proper YAML structure:
|
|
113
113
|
```yaml
|
|
114
114
|
skill_overrides:
|
|
115
115
|
{skill-name}:
|
|
116
116
|
source: "custom/skills/{skill-name}.md"
|
|
117
117
|
```
|
|
118
|
-
- If all-dev.customize.yaml already exists: read current content, check if a skill_overrides entry for this skill already exists. If it does not exist, append the new entry under skill_overrides. Preserve all existing entries — only add the new one. If it already exists (duplicate), skip registration to prevent duplicate entries.
|
|
118
|
+
- If custom/skills/all-dev.customize.yaml already exists: read current content, check if a skill_overrides entry for this skill already exists. If it does not exist, append the new entry under skill_overrides. Preserve all existing entries — only add the new one. If it already exists (duplicate), skip registration to prevent duplicate entries.
|
|
119
119
|
</action>
|
|
120
120
|
<action>If no skill improvements identified, state: "No skill improvements identified this sprint."</action>
|
|
121
121
|
</step>
|
|
@@ -45,6 +45,17 @@
|
|
|
45
45
|
(file paths, component references, API endpoints, dependency versions).
|
|
46
46
|
Verify against filesystem and ground truth (if available).
|
|
47
47
|
Classify findings as CRITICAL (broken reference), WARNING (outdated), INFO (style).
|
|
48
|
+
|
|
49
|
+
(g) Origin Field Validation (optional fields — backward compatible):
|
|
50
|
+
The origin and origin_ref fields are OPTIONAL — stories without these fields
|
|
51
|
+
are valid (backward compatibility). Missing origin/origin_ref fields do NOT
|
|
52
|
+
cause errors and are accepted without warnings.
|
|
53
|
+
If the origin field IS present, validate:
|
|
54
|
+
- origin must be one of: "manual", "problem-solving", "triage", "add-feature",
|
|
55
|
+
"sprint-planning", or null. An invalid origin enum value is a CRITICAL finding.
|
|
56
|
+
- If origin is non-null, origin_ref must be non-empty (not null, not empty string).
|
|
57
|
+
A non-null origin with empty or null origin_ref is a WARNING finding.
|
|
58
|
+
If origin is null or absent, origin_ref is not validated (orphaned refs are acceptable).
|
|
48
59
|
</action>
|
|
49
60
|
</step>
|
|
50
61
|
<step n="3" title="Validation Fix Loop">
|
|
@@ -124,23 +124,26 @@
|
|
|
124
124
|
**Step 1 — Load all scan outputs:**
|
|
125
125
|
Load gap entries from ALL of the following sources. For each file, if it exists, parse YAML gap entries matching the schema from gap-entry-schema.md. If a file is empty or missing, log a warning noting which scanner produced no results and continue processing the remaining files without error.
|
|
126
126
|
|
|
127
|
-
Deep analysis scan outputs (7 files):
|
|
127
|
+
Deep analysis scan outputs (7 files — Step 2.5):
|
|
128
128
|
- {planning_artifacts}/brownfield-scan-config-contradiction.md
|
|
129
129
|
- {planning_artifacts}/brownfield-scan-dead-code.md
|
|
130
|
-
- {planning_artifacts}/brownfield-scan-
|
|
131
|
-
- {planning_artifacts}/brownfield-scan-security
|
|
130
|
+
- {planning_artifacts}/brownfield-scan-hardcoded.md
|
|
131
|
+
- {planning_artifacts}/brownfield-scan-security.md
|
|
132
132
|
- {planning_artifacts}/brownfield-scan-runtime-behavior.md
|
|
133
|
-
- {planning_artifacts}/brownfield-scan-doc-code
|
|
133
|
+
- {planning_artifacts}/brownfield-scan-doc-code.md
|
|
134
134
|
- {planning_artifacts}/brownfield-scan-integration-seam.md
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
Test execution scan output (1 file — Step 2.75):
|
|
137
|
+
- {planning_artifacts}/brownfield-scan-test-execution.md (failing tests as gap entries)
|
|
138
|
+
|
|
139
|
+
Step 2 documentation subagent outputs (4 files):
|
|
137
140
|
- {planning_artifacts}/api-documentation.md (API gaps)
|
|
138
141
|
- {planning_artifacts}/event-catalog.md (event/messaging gaps)
|
|
139
142
|
- {planning_artifacts}/ux-design.md (frontend/UX gaps)
|
|
140
143
|
- {planning_artifacts}/dependency-map.md (dependency gaps)
|
|
141
144
|
|
|
142
|
-
Step 3
|
|
143
|
-
- {test_artifacts}/nfr-assessment.md (
|
|
145
|
+
Step 3 NFR assessment:
|
|
146
|
+
- {test_artifacts}/nfr-assessment.md (NFR gap findings)
|
|
144
147
|
|
|
145
148
|
**Step 2 — Validate entries against schema:**
|
|
146
149
|
For each parsed gap entry, validate that all required fields are present: id, category, severity, title, description (or evidence), evidence_file, evidence_line, recommendation. Entries missing any required field are logged as warnings (noting the source file and which field is missing) and skipped from consolidation rather than causing a failure.
|
|
@@ -197,6 +200,7 @@
|
|
|
197
200
|
— If infrastructure: use IR-### for infrastructure requirements, OR-### for operational requirements, and SR-### for security requirements exclusively. Do NOT use FR/NFR prefixes.
|
|
198
201
|
— If platform: use BOTH ID scheme families — FR-###/NFR-### for application-layer requirements and IR-###/OR-###/SR-### for infrastructure-layer requirements. All requirement IDs are globally unique within the project — the prefix disambiguates (e.g., FR-001 and IR-001 are distinct, no collision).</action>
|
|
199
202
|
<action>Read upstream artifacts to inform gap analysis:</action>
|
|
203
|
+
<action>— project-documentation.md → project context: tech stack, architecture patterns, conventions, detected capability flags, CI/CD summary. Use for PRD Overview section (existing project summary) and to ground gap requirements in the actual project structure.</action>
|
|
200
204
|
<action>— consolidated-gaps.md → primary input: deduplicated, ranked, and code-verified gap list from Steps 3.5 and 5.5. If a '## Verification Corrections for PRD' section exists, use it to correct factual errors from contradicted claims.</action>
|
|
201
205
|
<action>— nfr-assessment.md → NFR section gets real "Current Baseline" and "Target" columns</action>
|
|
202
206
|
<action>— api-documentation.md (if exists) → extract API gaps (undocumented endpoints, missing validation)</action>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Test Gap Analysis Checklist
|
|
2
|
+
- [ ] Execution mode determined (coverage or verification)
|
|
3
|
+
- [ ] Test plan scanned for test case IDs and story links
|
|
4
|
+
- [ ] Story files scanned for acceptance criteria
|
|
5
|
+
- [ ] Cross-reference completed — gaps identified
|
|
6
|
+
- [ ] Output follows FR-223 schema (summary count, per-story table, coverage %)
|
|
7
|
+
- [ ] Zero-gap case handled with "No coverage gaps detected" message
|
|
8
|
+
- [ ] Workflow completed within NFR-040 performance constraint (< 60 seconds)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<workflow name="test-gap-analysis">
|
|
2
|
+
<critical>
|
|
3
|
+
<mandate>Scan test-plan.md and story files to identify acceptance criteria gaps — NFR-040 requires completion in under 60 seconds</mandate>
|
|
4
|
+
<mandate>Output must follow the FR-223 schema: summary count, per-story gap table, coverage percentage</mandate>
|
|
5
|
+
<mandate>When no gaps are detected, output must state "No coverage gaps detected" with a summary count of zero</mandate>
|
|
6
|
+
</critical>
|
|
7
|
+
|
|
8
|
+
<step n="1" title="Determine Mode">
|
|
9
|
+
<action>Check the --mode argument: coverage or verification</action>
|
|
10
|
+
<action>If no mode specified, default to coverage mode</action>
|
|
11
|
+
<action>If mode is 'verification', skip to verification-mode steps (E19-S2 scope — not implemented yet)</action>
|
|
12
|
+
</step>
|
|
13
|
+
|
|
14
|
+
<step n="2" title="Scan Test Plan">
|
|
15
|
+
<action>Read {test_artifacts}/test-plan.md</action>
|
|
16
|
+
<action>Extract all test case IDs and their linked story keys from the test plan</action>
|
|
17
|
+
<action>Build a map of test_case_id -> [story_keys] for cross-referencing</action>
|
|
18
|
+
<action>If test-plan.md is missing, log warning: "test-plan.md not found — partial coverage analysis only" and continue with empty test case map</action>
|
|
19
|
+
</step>
|
|
20
|
+
|
|
21
|
+
<step n="3" title="Scan Story Files">
|
|
22
|
+
<action>Scan all story files in docs/implementation-artifacts/ matching pattern {story_key}-*.md</action>
|
|
23
|
+
<action>For each story file, extract all acceptance criteria (AC items) from the "Acceptance Criteria" section</action>
|
|
24
|
+
<action>Build a map of story_key -> [AC items] with their identifiers (AC1, AC2, etc.)</action>
|
|
25
|
+
<action>Track untested acceptance criteria — ACs that have no matching test case in the test plan map</action>
|
|
26
|
+
</step>
|
|
27
|
+
|
|
28
|
+
<step n="4" title="Cross-Reference and Identify Gaps">
|
|
29
|
+
<action>For each story's acceptance criteria, check if a corresponding test case exists in the test plan</action>
|
|
30
|
+
<action>Flag each AC as covered (has test case) or uncovered-ac (no test case found)</action>
|
|
31
|
+
<action>Calculate coverage rate per story: covered_ACs / total_ACs</action>
|
|
32
|
+
<action>Calculate overall coverage percentage across all stories</action>
|
|
33
|
+
</step>
|
|
34
|
+
|
|
35
|
+
<step n="5" title="Generate Output (FR-223 Schema)">
|
|
36
|
+
<action>Generate the output artifact at {test_artifacts}/test-gap-analysis-{date}.md</action>
|
|
37
|
+
<action>Output must include the following FR-223 schema sections:
|
|
38
|
+
- Summary section with total count of stories analyzed, ACs scanned, gaps found, and overall coverage percentage
|
|
39
|
+
- Per-story gap table listing each story, its ACs, and their coverage status
|
|
40
|
+
- Coverage rate breakdown showing covered vs uncovered acceptance criteria
|
|
41
|
+
</action>
|
|
42
|
+
<action>If zero gaps are detected (all ACs have corresponding test cases):
|
|
43
|
+
Output "No coverage gaps detected" in the summary section with a gap count of 0 and coverage rate of 100%</action>
|
|
44
|
+
<template-output file="{test_artifacts}/test-gap-analysis-{date}.md">
|
|
45
|
+
Gap analysis report following FR-223 schema with summary count, per-story gap table, and coverage percentage.
|
|
46
|
+
</template-output>
|
|
47
|
+
</step>
|
|
48
|
+
|
|
49
|
+
<step n="6" title="Performance Validation">
|
|
50
|
+
<action>Verify workflow completed within the NFR-040 constraint of under 60 seconds</action>
|
|
51
|
+
<action>Log total execution time in the output footer</action>
|
|
52
|
+
</step>
|
|
53
|
+
</workflow>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: test-gap-analysis
|
|
2
|
+
description: 'Scan test suite against requirements to identify untested or under-tested areas'
|
|
3
|
+
module: testing
|
|
4
|
+
agent: test-architect
|
|
5
|
+
execution_mode: planning
|
|
6
|
+
modes:
|
|
7
|
+
- coverage
|
|
8
|
+
- verification
|
|
9
|
+
default_mode: coverage
|
|
10
|
+
config_resolved: "{installed_path}/.resolved/test-gap-analysis.yaml"
|
|
11
|
+
config_source: "{project-root}/_gaia/testing/config.yaml"
|
|
12
|
+
installed_path: "{project-root}/_gaia/testing/workflows/test-gap-analysis"
|
|
13
|
+
instructions: "{installed_path}/instructions.xml"
|
|
14
|
+
validation: "{installed_path}/checklist.md"
|
|
15
|
+
traces_to:
|
|
16
|
+
- FR-221
|
|
17
|
+
- FR-223
|
|
18
|
+
- NFR-040
|
|
19
|
+
performance_constraints:
|
|
20
|
+
max_duration_seconds: 60 # NFR-040 — workflow must complete in under 60 seconds
|
|
21
|
+
input_file_patterns:
|
|
22
|
+
test_plan:
|
|
23
|
+
whole: "{test_artifacts}/test-plan.md"
|
|
24
|
+
load_strategy: "FULL_LOAD"
|
|
25
|
+
story_files:
|
|
26
|
+
whole: "{implementation_artifacts}/*.md"
|
|
27
|
+
load_strategy: "INDEX_GUIDED"
|
|
28
|
+
architecture:
|
|
29
|
+
whole: "{planning_artifacts}/architecture.md"
|
|
30
|
+
load_strategy: "INDEX_GUIDED"
|
|
31
|
+
sprint_status:
|
|
32
|
+
whole: "{implementation_artifacts}/sprint-status.yaml"
|
|
33
|
+
load_strategy: "FULL_LOAD"
|
|
34
|
+
output:
|
|
35
|
+
primary: "{test_artifacts}/test-gap-analysis-{date}.md"
|
|
36
|
+
on_error:
|
|
37
|
+
missing_file: "warn_and_continue"
|
|
38
|
+
unresolved_variable: "halt"
|
package/bin/gaia-framework.js
CHANGED
|
@@ -158,6 +158,8 @@ Commands:
|
|
|
158
158
|
status Show installation info
|
|
159
159
|
|
|
160
160
|
Options:
|
|
161
|
+
--branch <name> Clone from a specific branch
|
|
162
|
+
--staging Shorthand for --branch staging
|
|
161
163
|
--yes Skip confirmation prompts
|
|
162
164
|
--dry-run Show what would be done without making changes
|
|
163
165
|
--verbose Show detailed progress
|
|
@@ -207,6 +209,32 @@ function main(deps) {
|
|
|
207
209
|
fail(`Unknown command: ${command}\n Run 'npx gaia-framework --help' for usage.`);
|
|
208
210
|
}
|
|
209
211
|
|
|
212
|
+
// ─── Branch flag parsing (E14-S1) ─────────────────────────────────────────
|
|
213
|
+
// Extract --branch / --staging before building the passthrough array.
|
|
214
|
+
// These flags control which git branch is cloned — they are consumed by the
|
|
215
|
+
// JS CLI and forwarded as --branch <name> to gaia-install.sh.
|
|
216
|
+
let branchValue = null;
|
|
217
|
+
const remaining = args.slice(0);
|
|
218
|
+
|
|
219
|
+
const branchIdx = remaining.indexOf("--branch");
|
|
220
|
+
const hasStaging = remaining.includes("--staging");
|
|
221
|
+
|
|
222
|
+
if (branchIdx >= 0 && hasStaging) {
|
|
223
|
+
fail("Cannot use --branch and --staging together. Use --branch staging instead.");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (branchIdx >= 0) {
|
|
227
|
+
const valueIdx = branchIdx + 1;
|
|
228
|
+
if (valueIdx >= remaining.length || remaining[valueIdx].startsWith("--")) {
|
|
229
|
+
fail("Missing value for --branch flag. Usage: --branch <name>");
|
|
230
|
+
}
|
|
231
|
+
branchValue = remaining[valueIdx];
|
|
232
|
+
remaining.splice(branchIdx, 2);
|
|
233
|
+
} else if (hasStaging) {
|
|
234
|
+
branchValue = "staging";
|
|
235
|
+
remaining.splice(remaining.indexOf("--staging"), 1);
|
|
236
|
+
}
|
|
237
|
+
|
|
210
238
|
// Ensure git is available
|
|
211
239
|
ensureGit();
|
|
212
240
|
|
|
@@ -237,8 +265,9 @@ function main(deps) {
|
|
|
237
265
|
|
|
238
266
|
info("Cloning GAIA framework from GitHub...");
|
|
239
267
|
|
|
268
|
+
const branchCloneFlag = branchValue ? ` --branch ${branchValue}` : "";
|
|
240
269
|
try {
|
|
241
|
-
_exec(`git clone --depth 1 ${REPO_URL} "${tempDir}"`, {
|
|
270
|
+
_exec(`git clone --depth 1${branchCloneFlag} ${REPO_URL} "${tempDir}"`, {
|
|
242
271
|
stdio: ["ignore", "ignore", "pipe"],
|
|
243
272
|
});
|
|
244
273
|
} catch (err) {
|
|
@@ -256,10 +285,15 @@ function main(deps) {
|
|
|
256
285
|
|
|
257
286
|
// Build the shell command: inject --source pointing to the temp clone
|
|
258
287
|
// so the shell script doesn't need to clone again
|
|
259
|
-
const passthrough =
|
|
288
|
+
const passthrough = remaining.slice(0);
|
|
260
289
|
// Insert --source right after the command (convert to POSIX for bash on Windows)
|
|
261
290
|
passthrough.splice(1, 0, "--source", toPosixPath(tempDir));
|
|
262
291
|
|
|
292
|
+
// Inject --branch flag for installer passthrough (E14-S1)
|
|
293
|
+
if (branchValue) {
|
|
294
|
+
passthrough.push("--branch", branchValue);
|
|
295
|
+
}
|
|
296
|
+
|
|
263
297
|
// Locate bash (critical for Windows support)
|
|
264
298
|
const bashPath = _findBash();
|
|
265
299
|
if (!bashPath) {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive bump label from PR title conventional commit prefix.
|
|
3
|
+
* Used by .github/workflows/pr-title-label.yml (E14-S11, ADR-025).
|
|
4
|
+
*
|
|
5
|
+
* @param {string} title - PR title
|
|
6
|
+
* @param {string} body - PR body
|
|
7
|
+
* @returns {{ label: string, type: string, breaking: boolean } | null}
|
|
8
|
+
* Returns the derived bump label info, or null if title doesn't match.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const TITLE_REGEX = /^(feat|fix|refactor|perf|test|docs|chore|ci|style)(\(.+\))?(!)?: .+$/;
|
|
12
|
+
|
|
13
|
+
const TYPE_TO_LABEL = Object.freeze({
|
|
14
|
+
feat: "bump:minor",
|
|
15
|
+
fix: "bump:patch",
|
|
16
|
+
perf: "bump:patch",
|
|
17
|
+
refactor: "bump:none",
|
|
18
|
+
test: "bump:none",
|
|
19
|
+
docs: "bump:none",
|
|
20
|
+
chore: "bump:none",
|
|
21
|
+
ci: "bump:none",
|
|
22
|
+
style: "bump:none",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function deriveBumpLabel(title, body) {
|
|
26
|
+
const match = title.match(TITLE_REGEX);
|
|
27
|
+
if (!match) return null;
|
|
28
|
+
|
|
29
|
+
const type = match[1];
|
|
30
|
+
const bang = match[3] === "!";
|
|
31
|
+
const bodyBreaking = typeof body === "string" && body.includes("BREAKING CHANGE");
|
|
32
|
+
const breaking = bang || bodyBreaking;
|
|
33
|
+
|
|
34
|
+
const label = breaking ? "bump:major" : TYPE_TO_LABEL[type];
|
|
35
|
+
|
|
36
|
+
return { label, type, breaking };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = deriveBumpLabel;
|
|
40
|
+
module.exports.TITLE_REGEX = TITLE_REGEX;
|
|
41
|
+
module.exports.TYPE_TO_LABEL = TYPE_TO_LABEL;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR bump label validation for staging merge enforcement.
|
|
3
|
+
* Used by .github/workflows/label-check.yml (E14-S6, ADR-025).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const VALID_BUMP_LABELS = Object.freeze(["bump:major", "bump:minor", "bump:patch", "bump:none"]);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validate that exactly one bump:* label is present on a PR.
|
|
10
|
+
*
|
|
11
|
+
* @param {string[]} labels - Array of label names from the PR
|
|
12
|
+
* @returns {{ pass: boolean, message: string }} Validation result
|
|
13
|
+
*/
|
|
14
|
+
function validateBumpLabels(labels) {
|
|
15
|
+
const bumpLabels = labels.filter((label) => VALID_BUMP_LABELS.includes(label));
|
|
16
|
+
|
|
17
|
+
if (bumpLabels.length === 0) {
|
|
18
|
+
return {
|
|
19
|
+
pass: false,
|
|
20
|
+
message: `No bump label found. Add one of: ${VALID_BUMP_LABELS.join(", ")}`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (bumpLabels.length > 1) {
|
|
25
|
+
return {
|
|
26
|
+
pass: false,
|
|
27
|
+
message: `Multiple bump labels found: ${bumpLabels.join(", ")}. Exactly one required.`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
pass: true,
|
|
33
|
+
message: `Valid bump label: ${bumpLabels[0]}`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = validateBumpLabels;
|
|
38
|
+
module.exports.VALID_BUMP_LABELS = VALID_BUMP_LABELS;
|