gaia-framework 1.83.2 → 1.105.0
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-ci-edit.md +17 -0
- package/CLAUDE.md +10 -0
- package/_gaia/_config/environment-presets.yaml +140 -0
- package/_gaia/_config/global.yaml +1 -1
- package/_gaia/_config/lifecycle-sequence.yaml +9 -0
- package/_gaia/_config/workflow-manifest.csv +1 -0
- package/_gaia/core/engine/workflow.xml +2 -0
- package/_gaia/core/validators/ci-edit-audit.js +181 -0
- package/_gaia/core/validators/ci-edit-test-env-scan.js +89 -0
- package/_gaia/core/validators/dev-story-security-controls.js +264 -0
- package/_gaia/core/validators/promotion-chain-env-resolver.js +140 -0
- package/_gaia/core/validators/test-environment-validator.js +292 -0
- package/_gaia/dev/agents/_base-dev.md +6 -1
- package/_gaia/dev/skills/_skill-index.yaml +12 -6
- package/_gaia/dev/skills/figma-integration.md +203 -1
- package/_gaia/lifecycle/knowledge/brownfield/test-execution-scan.md +56 -9
- package/_gaia/lifecycle/templates/story-template.md +7 -0
- package/_gaia/lifecycle/workflows/2-planning/create-ux-design/instructions.xml +48 -4
- package/_gaia/lifecycle/workflows/4-implementation/code-review/instructions.xml +10 -0
- package/_gaia/lifecycle/workflows/4-implementation/create-story/instructions.xml +4 -0
- package/_gaia/lifecycle/workflows/4-implementation/dev-story/checklist.md +2 -0
- package/_gaia/lifecycle/workflows/4-implementation/dev-story/instructions.xml +104 -3
- package/_gaia/testing/workflows/ci-edit/checklist.md +41 -0
- package/_gaia/testing/workflows/ci-edit/instructions.xml +132 -0
- package/_gaia/testing/workflows/ci-edit/workflow.yaml +30 -0
- package/_gaia/testing/workflows/ci-setup/instructions.xml +75 -7
- package/_gaia/testing/workflows/test-gap-analysis/checklist.md +12 -0
- package/_gaia/testing/workflows/test-gap-analysis/instructions.xml +61 -2
- package/_gaia/testing/workflows/test-gap-analysis/workflow.yaml +2 -0
- package/gaia-install.sh +72 -76
- package/lib/copy-lib.sh +81 -0
- package/package.json +2 -1
|
@@ -48,6 +48,16 @@
|
|
|
48
48
|
</action>
|
|
49
49
|
<action if="mode == REWORK or mode == RESUME">Skip status change — story is already in-progress.</action>
|
|
50
50
|
</step>
|
|
51
|
+
<step n="4b" title="Figma Design Consumption">
|
|
52
|
+
<action>Check for figma: metadata block in story file YAML frontmatter. Expected fields: file_key (string — Figma file identifier), pages (list of page names to extract from), node_ids (list of specific node IDs), design_version (string — Figma lastModified hash for traceability). Also check ux-design.md for a figma: metadata block.</action>
|
|
53
|
+
<action if="no figma: metadata block found in story file or ux-design.md">No Figma metadata present — skip all Figma-related actions. Use ux-design.md text as-is with zero behavioral change. Proceed to Step 5.</action>
|
|
54
|
+
<action if="figma: metadata block is present">JIT-load figma-integration.md tokens and components sections for MCP extraction.</action>
|
|
55
|
+
<action if="figma: metadata block is present">Check for cached responses in {project-path}/.figma-cache/ using composite cache key {file_key}:{page_id}:{design_version_hash}. If cache hit with valid version hash, use cached data. If cache miss or design version changed since last implementation, proceed with MCP extraction.</action>
|
|
56
|
+
<action if="figma: metadata block is present and MCP available">Extract design tokens via MCP and write design-tokens.json to {planning_artifacts}/design-system/ in W3C DTCG format. Extract component specs via MCP and write component-specs.yaml to the same directory.</action>
|
|
57
|
+
<action if="figma: metadata block is present and MCP unreachable">If cached data exists in {project-path}/.figma-cache/ (even with expired TTL), continue with last-known-good files and display [OFFLINE] warning: "Design data loaded from cache — MCP unreachable. Token data may be stale." Do not halt — proceed with stale data.</action>
|
|
58
|
+
<action if="figma: metadata block is present">Compare design_version in story figma: metadata against the current Figma file version. If the design version has changed since the last implementation run, offer an incremental update: "Design has changed since last implementation (stored: {old_version}, current: {new_version}). Run incremental token update? [y/n]". Record the design_version consumed in the story figma: metadata for traceability.</action>
|
|
59
|
+
<action if="figma: metadata block is present">JIT-load figma-integration.md export section. Generate stack-specific scaffolded code from intermediate files (design-tokens.json and component-specs.yaml) using the active dev agent's resolution table. Output token files and component scaffolds to {project-path} design system directory.</action>
|
|
60
|
+
</step>
|
|
51
61
|
<step n="5" title="Plan Implementation">
|
|
52
62
|
<action if="mode == REWORK">REWORK MODE — Focus plan on fixing review feedback:
|
|
53
63
|
1. Read the story's Review Gate table — identify which reviews FAILED
|
|
@@ -222,6 +232,11 @@
|
|
|
222
232
|
<action>- [ ] **No hardcoded secrets or credentials** — scan new/modified files for API keys, passwords, tokens, connection strings. Mark [x] if clean.</action>
|
|
223
233
|
<action>- [ ] **All subtasks marked complete** — verify every subtask in the story file is checked off. Mark [x] if all done.</action>
|
|
224
234
|
<action>- [ ] **Documentation updated** — if the change affects APIs, configs, or user-facing behavior, verify that relevant docs are updated. Mark [x] if not applicable or if docs are updated.</action>
|
|
235
|
+
<action>PR MERGE DOD ITEM (E20-S9 / FR-251): Render a dedicated "PR merged to {promotion_chain[0].branch}" item under the Quality group of the Definition of Done. This is the ONLY DoD line where the branch name from ci_cd.promotion_chain[0].branch is interpolated at render time — the literal token string "{promotion_chain[0].branch}" MUST NEVER appear in the rendered story file. Resolution logic:
|
|
236
|
+
1. Read {project-root}/_gaia/_config/global.yaml and look up ci_cd.promotion_chain. Treat the chain as ABSENT when ANY of the following variants is encountered: (a) the ci_cd block is absent; (b) ci_cd is null; (c) ci_cd is an empty mapping; (d) ci_cd is present but has no promotion_chain key; (e) ci_cd.promotion_chain is null; (f) ci_cd.promotion_chain is an empty array. The chain is PRESENT only when ci_cd.promotion_chain is a non-null array with at least one entry. This matches the promotion-chain guard semantics used by Step 15 (Merge PR).
|
|
237
|
+
2. PRESENT branch: extract ci_cd.promotion_chain[0].branch (e.g., "develop", "staging") and render the DoD line as "- [ ] PR merged to {resolved_branch_name}". The item starts UNCHECKED and is auto-checked by Step 15 on successful merge. NFR-045 backward compatibility is preserved because this variant is only rendered when an opt-in ci_cd block exists.
|
|
238
|
+
3. ABSENT branch: render the DoD line as "- [x] PR merged — N/A (no promotion chain configured)". The item is pre-checked so it is non-blocking for legacy projects — no warning, no error, silently degrades to the pre-E20 behavior. This satisfies AC3 and AC6.
|
|
239
|
+
4. Write the resolved line into the story file's "Definition of Done" section under the Quality group — alongside "All tests pass", "No lint errors", "Code follows conventions". The resolution happens at render time (NEVER before); the literal "{promotion_chain[0].branch}" token MUST NEVER be written to the story markdown.</action>
|
|
225
240
|
<action>AUTO-FIX LOOP: After running all checks, if any item is marked [ ] (failing):
|
|
226
241
|
1. Identify each failing item and the specific issue causing it to fail
|
|
227
242
|
2. Auto-fix the issue (fix lint errors, fix failing tests, update docs, complete missed subtasks, remove hardcoded secrets, etc.)
|
|
@@ -239,7 +254,91 @@
|
|
|
239
254
|
<action>Stage all changes</action>
|
|
240
255
|
<action>Commit with conventional commit format: type(scope): description</action>
|
|
241
256
|
</step>
|
|
242
|
-
<step n="13" title="
|
|
257
|
+
<step n="13" title="Push Feature Branch">
|
|
258
|
+
<critical>
|
|
259
|
+
<mandate>This step implements FR-247 (dev-story push step, architecture §10.24.5). It is gated by the ci_cd.promotion_chain configuration in global.yaml for backward compatibility (NFR-045).</mandate>
|
|
260
|
+
</critical>
|
|
261
|
+
<action>PROMOTION CHAIN GUARD (NFR-045 / ADR-033 / E20-S11): Read {project-root}/_gaia/_config/global.yaml and check whether the ci_cd promotion chain has been opted into. When the chain is absent the engine MUST skip Steps 13, 14, 15, and 16 silently — no error, no warning, no output, no injected defaults. The chain is treated as ABSENT when ANY of the following variants is encountered: (a) the ci_cd block is absent (the top-level ci_cd key does not exist); (b) ci_cd is null; (c) ci_cd is an empty mapping ({}); (d) ci_cd is present with other fields but has no promotion_chain key; (e) ci_cd.promotion_chain is null; (f) ci_cd.promotion_chain is an empty array ([]). The chain is treated as PRESENT — and Steps 13-16 execute normally — only when ci_cd.promotion_chain is a non-null array with at least one entry. The canonical predicate lives in {project-path}/scripts/lib/promotion-chain-guard.js (chainPresent) and is the single source of truth for every workflow that gates on the promotion chain. When the chain is absent, proceed directly to Step 17 (Post-Complete Gate). This preserves existing behavior for projects that have not opted in to the promotion chain.</action>
|
|
262
|
+
<action>NO-REMOTE DETECTION (AC2): Run `git remote -v` in {project-path}. If the output is empty (no git remote is configured), display the warning "No git remote configured — skipping push/PR/CI steps. Complete these manually." and set a skip flag to bypass Steps 14, 15, and 16. Proceed directly to Step 17.</action>
|
|
263
|
+
<action>BRANCH NAME DERIVATION (AC4): JIT-load the branch-naming section of the git-workflow skill from {project-root}/_gaia/dev/skills/git-workflow.md. Read the current checked-out branch via `git branch --show-current` in {project-path}. Validate that the current branch name follows the git-workflow skill convention (e.g., feat/{story_key}-{slug}). If the branch name does not match the convention, warn the user but continue — the current branch is authoritative.</action>
|
|
264
|
+
<action>PUSH (AC1, FR-247): Execute `git push -u origin {branch_name}` in {project-path}, where {branch_name} is the current branch resolved above. The `-u` flag sets upstream tracking, which is required for subsequent `gh pr create` in Step 14.</action>
|
|
265
|
+
<action>RETRY LOGIC (AC3): If the first push attempt fails, capture the full git stderr output. Classify the error: authentication failure (exit 128 with "Authentication failed"), network failure ("Could not resolve host", connection timeout), or other. Wait 5 seconds, then retry the push exactly once.</action>
|
|
266
|
+
<check if="push_retry_also_fails">HALT with an actionable error message that includes the raw git error output (both attempts): "Failed to push feature branch after retry. Error classification: {auth|network|other}. Git output: {stderr}. Resolve the issue manually, then re-run /gaia-dev-story to resume from this step."</check>
|
|
267
|
+
<action>On success: report "Pushed {branch_name} to origin with upstream tracking. Ready for PR creation in Step 14."</action>
|
|
268
|
+
</step>
|
|
269
|
+
<step n="14" title="Create Pull Request">
|
|
270
|
+
<critical>
|
|
271
|
+
<mandate>This step implements FR-248 (dev-story PR creation, architecture §10.24.5). It is gated by the ci_cd.promotion_chain configuration in global.yaml for backward compatibility (NFR-045) and by the no-remote flag set by Step 13. Step 14 targets promotion_chain[0].branch — the first environment in the chain is always the PR target (architecture rule §10.24.1).</mandate>
|
|
272
|
+
</critical>
|
|
273
|
+
<action>PROMOTION CHAIN GUARD (NFR-045 / ADR-033 / E20-S11): Reuse the guard decision from Step 13 — if the ci_cd.promotion_chain was determined to be absent, skip this step silently (no error, no warning, no output) and proceed to Step 15. The canonical predicate lives in {project-path}/scripts/lib/promotion-chain-guard.js (chainPresent).</action>
|
|
274
|
+
<action>NO-REMOTE SKIP (AC4 of E20-S5): If Step 13 set the no-remote skip flag (because `git remote -v` returned empty), skip this step silently and proceed to Step 15 — PR creation requires a remote.</action>
|
|
275
|
+
<action>CI PROVIDER DETECTION (AC5, FR-248): Read the resolved global config and extract ci_cd.promotion_chain[0].ci_provider. Map the ci_provider value to the CLI tool name using the following table:
|
|
276
|
+
— github_actions → gh
|
|
277
|
+
— gitlab_ci → glab
|
|
278
|
+
— other providers → consult the extensible mapping table; HALT if no mapping is registered for the provider.
|
|
279
|
+
The first entry of promotion_chain is authoritative for PR target selection because the first environment in the chain is always the PR target (architecture §10.24.1).</action>
|
|
280
|
+
<action>TOOL AVAILABILITY CHECK (AC6): Verify the mapped CLI tool is installed by running `command -v {tool}` (or `which {tool}`) in {project-path}. If the tool is not found on PATH, HALT with the message: "Required tool {tool} not found. Install it or complete PR creation manually." Do not attempt PR creation without the tool.</action>
|
|
281
|
+
<action>EXISTING PR DETECTION (AC4, MPC-29): Before creating a new PR, query for an existing PR on the current branch targeting promotion_chain[0].branch. For github_actions: `gh pr list --head {branch_name} --base {promotion_chain[0].branch} --json number,url --jq '.[0]'` in {project-path}. For gitlab_ci: the equivalent `glab mr list` query. If a PR is found, capture its number and URL, emit the message "PR #{number} already exists — proceeding to CI check", set a pr_exists flag, and skip the creation command below.</action>
|
|
282
|
+
<action>PR TITLE CONSTRUCTION (AC2): Build the PR title using the convention `{story_key}: {story_title}` — for example, "E20-S6: Dev-Story Step 14 — Create PR". The story_key and story_title are already loaded from the story file frontmatter in Step 1.</action>
|
|
283
|
+
<action>PR BODY CONSTRUCTION (AC3): Build the PR body as a markdown block that includes (in order): (1) the story key as a heading; (2) an acceptance criteria summary — a bullet list of AC titles extracted from the story file's "## Acceptance Criteria" section; (3) a link to the story file path (relative to the repository root, e.g., `docs/implementation-artifacts/{story_key}-*.md`). The story file path provides reviewers with quick access to full context during review.</action>
|
|
284
|
+
<action>PR CREATION COMMAND (AC1, FR-248, MPC-28): If pr_exists is not set, execute the provider-specific PR creation command in {project-path}. For github_actions: `gh pr create --base {promotion_chain[0].branch} --title "{title}" --body "{body}"`. For gitlab_ci: `glab mr create --target-branch {promotion_chain[0].branch} --title "{title}" --description "{body}"`. Capture the created PR number and URL from the command output.</action>
|
|
285
|
+
<action>ERROR HANDLING: If the PR creation command fails (network failure, auth failure, permission denied, etc.), capture the full stderr output and HALT with an actionable error message that includes: (a) the exact command that failed, (b) the raw stderr, (c) a suggested retry step ("re-run /gaia-dev-story to resume from this step after resolving the issue").</action>
|
|
286
|
+
<action>On success: report "Created PR #{number} targeting {promotion_chain[0].branch}: {url}. Ready for CI check in Step 15."</action>
|
|
287
|
+
</step>
|
|
288
|
+
<step n="15" title="Wait for CI Checks">
|
|
289
|
+
<critical>
|
|
290
|
+
<mandate>This step implements FR-249 (dev-story CI polling) and NFR-043 (15-minute default timeout) per architecture §10.24.5. It is gated by the ci_cd.promotion_chain configuration in global.yaml for backward compatibility (NFR-045). It is the primary mitigation for threat T26 (merge without passing CI) — on any path other than "all required checks passed" or "no checks configured", the step MUST halt and MUST NOT fall through to Step 16 (Merge PR).</mandate>
|
|
291
|
+
</critical>
|
|
292
|
+
<action>PROMOTION CHAIN GUARD (NFR-045 / ADR-033 / E20-S11): Read {project-root}/_gaia/_config/global.yaml and check whether the ci_cd.promotion_chain has been opted into. When the chain is absent the engine MUST skip this step silently — no error, no warning, no output. The chain is treated as ABSENT when ANY of the following variants is encountered: (a) the ci_cd block is absent; (b) ci_cd is null; (c) ci_cd is an empty mapping; (d) ci_cd is present but has no promotion_chain key; (e) ci_cd.promotion_chain is null; (f) ci_cd.promotion_chain is an empty array. The chain is PRESENT only when ci_cd.promotion_chain is a non-null array with at least one entry. The canonical predicate lives in {project-path}/scripts/lib/promotion-chain-guard.js (chainPresent) and is the single source of truth — reuse the guard decision already computed by Step 13. When the chain is absent, proceed directly to Step 16.</action>
|
|
293
|
+
<action>NO-REMOTE SKIP (AC4 of E20-S5): If Step 13 set the no-remote skip flag (because `git remote -v` returned empty), skip this step silently and proceed to Step 16 — there is no PR to poll for without a remote.</action>
|
|
294
|
+
<action>NO-CHECKS AUTO-PASS (AC7): Read ci_cd.promotion_chain[0].ci_checks from the resolved global config. If the array is absent, null, or empty, emit the message "No CI checks configured — proceeding to merge" and advance directly to Step 16 without polling. This is the auto-pass fast path — no PR polling, no timeout enforcement.</action>
|
|
295
|
+
<action>TIMEOUT RESOLUTION (AC3, NFR-043) — MPC-35: Read ci_cd.ci_timeout_minutes from the resolved global.yaml. The default is 15 minutes when the field is absent. Validate that the value is a positive integer — reject non-positive or non-numeric values with a clear error: "Invalid ci_cd.ci_timeout_minutes value: {value}. Must be a positive integer (minutes)." Store the resolved timeout in minutes; conversions to seconds happen at the loop level.</action>
|
|
296
|
+
<action>PR NUMBER RECOVERY: Retrieve the {pr_number} captured by Step 14 (Create Pull Request). This is required for `gh pr checks {pr_number}`. If the PR number is missing from the workflow state (e.g., resume after context loss), re-query the remote with `gh pr list --head {branch_name} --base {promotion_chain[0].branch} --json number --jq '.[0].number'` and use the result. If no PR is found, HALT: "Cannot wait for CI — no PR number available. Re-run Step 14 or create the PR manually and resume with /gaia-resume."</action>
|
|
297
|
+
<action>CI PROVIDER → POLLING COMMAND MAPPING (AC1, FR-249): Read ci_cd.promotion_chain[0].ci_provider and map to a CLI polling command:
|
|
298
|
+
— github_actions → `gh pr checks {pr_number} --json name,status,conclusion,startedAt,completedAt`
|
|
299
|
+
— gitlab_ci → `glab ci status` equivalent (stub with a clear TODO if full GitLab support is out of scope for this story)
|
|
300
|
+
— any unsupported provider → HALT with the actionable error "CI provider {ci_provider} has no supported polling command. Implement a mapping or switch providers."
|
|
301
|
+
JSON output is preferred over `gh pr checks --watch` because --watch blocks indefinitely with no hook for progress reporting, timeouts, or termination — the workflow must control its own cadence.</action>
|
|
302
|
+
<action>POLLING LOOP — 30-SECOND CADENCE (AC1, AC2, FR-249) — MPC-25: Capture the start time using a monotonic clock (time.monotonic() in Python, process.hrtime.bigint() in Node) so elapsed-time math is immune to wall-clock skew. Enter a loop that:
|
|
303
|
+
1. Invokes the mapped polling command (e.g., `gh pr checks {pr_number}`) in {project-path}.
|
|
304
|
+
2. Parses the JSON output into a list of records: {check name, status, duration}. Status values map to pending / running / passed / failed per the state table below. Compute elapsed time as (monotonic_now - monotonic_start).
|
|
305
|
+
3. Renders a concise progress display containing: check name, status (pending / running / passed / failed), and elapsed time since the wait started. Use a single updating line (carriage return) in interactive TTY and line-per-poll in CI / non-interactive mode (detect via isatty(stdout)).
|
|
306
|
+
4. Checks terminal state (see AC5/AC6 below). If any check is in a terminal state, handle it and exit the loop.
|
|
307
|
+
5. Checks the elapsed timeout (see AC4 below). If exceeded, halt.
|
|
308
|
+
6. Sleeps 30 seconds before the next poll. At a 15-minute default timeout, the loop runs at most ~30 polls — well under the GitHub API 5000 req/hour token budget.</action>
|
|
309
|
+
<action>STATE MAPPING: GitHub Actions `conclusion` values map as follows — success / skipped / neutral → passed. failure / cancelled / timed_out / action_required → failed. Any check without a conclusion yet maps to its `status` field (queued / in_progress → pending or running). This is the authoritative terminal-state definition used by the success and failure paths below.</action>
|
|
310
|
+
<action>TRANSIENT ERROR HANDLING: A transient network error on a single poll (DNS resolution failure, connection timeout, 5xx from the CI API) MUST log a warning and retry on the next 30-second tick — do NOT halt the workflow. Only hard CLI errors (tool missing, authentication failure, 4xx auth/permission) halt with an actionable message. Count the number of consecutive transient failures; if more than 5 consecutive polls fail, treat as a hard failure and halt.</action>
|
|
311
|
+
<action>SUCCESS PATH (AC5): When all required CI checks are in a passed terminal state, exit the loop and emit a success summary containing: each check name, the per-check duration (completedAt - startedAt), and the total elapsed time. Then advance to Step 16 (Merge PR). This is the only happy path — all other paths halt.</action>
|
|
312
|
+
<action>FAILURE PATH (AC6) — MPC-26: When any required CI check is in a failed terminal state, extract the check name, a short failure log excerpt, and the CI run URL from the CLI response. Emit the failure detail, then HALT with this exact message format: "CI check {name} failed. Fix the issue, push again, and resume with /gaia-resume." Do NOT advance to Step 16. The story status remains in-progress so the developer can fix the issue and re-enter this step via /gaia-resume.</action>
|
|
313
|
+
<action>TIMEOUT PATH (AC4) — MPC-27: Before sleeping for the next poll, compare the elapsed time against the resolved timeout (in seconds). If the elapsed time meets or exceeds the timeout, build the list of checks still in pending / running state and HALT with this exact message format: "CI checks timed out after {N} minutes. Checks still pending: {list}. Resume with /gaia-resume after checks complete." Here {N} is the resolved ci_cd.ci_timeout_minutes value and {list} is a comma-separated list of pending check names. The story status MUST remain in-progress so `/gaia-resume` can re-enter Step 15 without recreating the PR. Do NOT advance to Step 16.</action>
|
|
314
|
+
<action>CHECKPOINT: After successful completion (all checks passed), write an intermediate checkpoint to {checkpoint_path}/dev-story-{story_key}.yaml capturing: step: 15, phase: ci_checks_passed, pr_number, total_elapsed_seconds, checks (list of {name, duration, conclusion}). On timeout or failure, write the checkpoint with phase: ci_timeout or phase: ci_failed so `/gaia-resume` can recover.</action>
|
|
315
|
+
</step>
|
|
316
|
+
<step n="16" title="Merge PR">
|
|
317
|
+
<critical>
|
|
318
|
+
<mandate>This step implements FR-250 (dev-story merge-PR) per architecture §10.24.5. It is gated by the ci_cd.promotion_chain configuration in global.yaml for backward compatibility (NFR-045). It is the primary mitigation for threat T27 (force merge bypassing reviews) — it MUST NOT use the admin-override flag or any flag that bypasses branch protection, and it MUST halt on branch-protection failures with an actionable unmet-requirements list. The dev-agent's scope ends at merging to promotion_chain[0]; no further promotion (staging → prod) happens here.</mandate>
|
|
319
|
+
</critical>
|
|
320
|
+
<action>PROMOTION CHAIN GUARD (NFR-045 / ADR-033 / E20-S11 / AC8): Read {project-root}/_gaia/_config/global.yaml and check whether ci_cd.promotion_chain has been opted into. When the chain is absent the engine MUST skip this step silently — no error, no warning, no output. The chain is treated as ABSENT when ANY of the following variants is encountered: (a) the ci_cd block is absent; (b) ci_cd is null; (c) ci_cd is an empty mapping; (d) ci_cd is present but has no promotion_chain key; (e) ci_cd.promotion_chain is null; (f) ci_cd.promotion_chain is an empty array. The chain is PRESENT only when ci_cd.promotion_chain is a non-null array with at least one entry. Reuse the guard decision already computed by Step 13 (Push and Create PR) if available; otherwise compute inline. When the chain is absent, proceed directly to Step 17.</action>
|
|
321
|
+
<action>MERGE STRATEGY RESOLUTION (AC1, AC9 / T27 — MPC-35): Read ci_cd.promotion_chain[0].merge_strategy from the resolved global.yaml. Validate the value is exactly one of the three allowed values: merge, squash, or rebase (case-sensitive). If the value is missing, null, or not in the allowed set, HALT BEFORE any `gh` call with this exact message: "Invalid merge_strategy '{value}' in promotion_chain[0]. Allowed: merge, squash, rebase." This is the canonical T27 mitigation — strict enum validation prevents a misconfigured merge strategy from silently bypassing review expectations.</action>
|
|
322
|
+
<action>STRATEGY FLAG MAPPING (AC2): Map the validated strategy to exactly one single gh flag:
|
|
323
|
+
— merge → --merge
|
|
324
|
+
— squash → --squash
|
|
325
|
+
— rebase → --rebase
|
|
326
|
+
Build the base command with exactly one strategy flag — NEVER combine --merge with --squash, --squash with --rebase, or any two strategy flags together. The composition code MUST produce a command containing one and only one of the three flags.</action>
|
|
327
|
+
<action>PR NUMBER RECOVERY (AC1): Retrieve the {pr_number} captured by Step 14 (Create PR) into the workflow's runtime state or checkpoint. If the PR number is missing (e.g., Step 14 was not executed, or the workflow was resumed after context loss), HALT with "No PR to merge — Step 14 output missing."</action>
|
|
328
|
+
<action>IDEMPOTENCY CHECK: Before running the merge, query `gh pr view {pr_number} --json state,mergedAt` and inspect the result. If the PR state is already `MERGED` (mergedAt is non-null), emit "PR {pr_number} already merged at {mergedAt} — skipping merge" and advance directly to Step 17. This makes Step 16 safe to re-invoke via /gaia-resume after a successful merge.</action>
|
|
329
|
+
<action>BRANCH DELETION FLAG (AC5, AC6): Read ci_cd.delete_branch_after_merge from global.yaml. Treat the field as `true` when absent or missing (default). If the value is `true`: append `--delete-branch` to the merge command. If the value is explicitly `false`: omit the flag and log "Branch deletion skipped per ci_cd.delete_branch_after_merge: false" — the remote feature branch will be preserved for post-merge inspection.</action>
|
|
330
|
+
<action>STORY-KEY COMMIT BODY (AC7): Append `--body "Story: {story_key}"` to the merge command so the merge commit body carries the story key on its own line. For squash strategy the story key MUST live in the body because GitHub rewrites the subject line. This enables `git log --grep "Story: E20-"` to surface all story commits on the target branch for traceability.</action>
|
|
331
|
+
<action>EXECUTE MERGE (AC1, AC7): Run the composed command in {project-path}:
|
|
332
|
+
`gh pr merge {pr_number} --{strategy_flag} [--delete-branch] --body "Story: {story_key}"`
|
|
333
|
+
Capture stdout, stderr, and exit code. The command MUST NOT contain the admin-override flag (the gh CLI accepts a flag that bypasses branch protection for repo admins — it is strictly forbidden here), `--auto`, or any other branch-protection bypass flag (T27 hard constraint). On exit code 0: emit a success summary containing the strategy used, the merge commit SHA (parsed from stdout or a follow-up `gh pr view {pr_number} --json mergeCommit`), the target branch, and whether the branch was deleted (y/n). Then advance to Step 17.</action>
|
|
334
|
+
<action>POST-MERGE STORY KEY VERIFICATION (AC7): After a successful merge, fetch the merge commit via `gh api repos/{owner}/{repo}/commits/{merge_sha}` (or `git log -1 --format=%B {merge_sha}` in the local clone after pulling target). Verify the body contains the line `Story: {story_key}`. If not (e.g., squash merge rewrote the message and the body was not preserved), log a warning "Story key not found in merge commit body — traceability degraded" but do NOT fail the step; the merge itself has already succeeded.</action>
|
|
335
|
+
<action>DOD AUTO-CHECK (E20-S9 / FR-251 / AC2): After a successful merge, open the story file at {implementation_artifacts}/{story_key}-*.md and locate the PR merge DoD line rendered by Step 10 under the Quality group — it reads "- [ ] PR merged to {resolved_branch}" where {resolved_branch} is the value of ci_cd.promotion_chain[0].branch. Rewrite the line in the story markdown, replacing "- [ ] PR merged to {resolved_branch}" with "- [x] PR merged to {resolved_branch}" — auto-check the DoD item in place. The N/A variant ("- [x] PR merged — N/A (no promotion chain configured)") is never rewritten because it is already pre-checked. Persist the checkpoint showing phase: dod_auto_checked alongside the merge metadata so the transition to `review` in Step 18 (when re-entered via a resumed run) can satisfy the PR merge DoD gate.</action>
|
|
336
|
+
<action>CONFLICT FAILURE PATH (AC3): Match stderr against known conflict signatures: "not mergeable", "merge conflict", "conflicts with base branch". On match, HALT with this exact message: "Merge conflict detected. Resolve conflicts locally, push, and resume with /gaia-resume." The story status MUST remain `in-progress` so the developer can resolve conflicts and re-enter the workflow via /gaia-resume. Do NOT advance to Step 17.</action>
|
|
337
|
+
<action>BRANCH PROTECTION FAILURE PATH (AC4): Match stderr against branch-protection signatures: "required status checks", "required approving reviews", "required signatures", "review required", "protected branch". On match, parse the specific unmet requirements from the stderr payload or call `gh api repos/{owner}/{repo}/branches/{target_branch}/protection` to enumerate the requirements. Build an actionable halt message listing each unmet requirement with the command the developer can run to satisfy it — for example: "Branch protection blocked the merge. Unmet requirements: (1) Required approvals: 1/2 — request review from @code-owners via `gh pr edit {pr_number} --add-reviewer @code-owners`; (2) Required status check 'ci/lint' missing — push a fix and re-run CI." The story status MUST remain `in-progress`. Do NOT retry with any bypass flag; do NOT use the admin-override flag under any circumstance.</action>
|
|
338
|
+
<action>GENERIC MERGE FAILURE PATH (AC3, AC4): On any other non-zero exit code that does not match conflict or branch-protection signatures, HALT with "Merge failed: {stderr_excerpt}. Resume with /gaia-resume after resolving." The story status remains `in-progress`.</action>
|
|
339
|
+
<action>CHECKPOINT: After a successful merge, write an intermediate checkpoint to {checkpoint_path}/dev-story-{story_key}.yaml capturing: step: 16, phase: merged, pr_number, merge_commit_sha, merge_strategy, target_branch, branch_deleted (boolean), story_key_in_body (boolean). On conflict, branch-protection, or generic failure, write the checkpoint with phase: merge_conflict, merge_protection_blocked, or merge_failed respectively so `/gaia-resume` can recover without recreating the PR.</action>
|
|
340
|
+
</step>
|
|
341
|
+
<step n="17" title="Post-Complete Gate">
|
|
243
342
|
<action>Verify all tests pass (final confirmation)</action>
|
|
244
343
|
<action>Verify all acceptance criteria met</action>
|
|
245
344
|
<action>Verify all subtasks marked complete</action>
|
|
@@ -247,7 +346,9 @@
|
|
|
247
346
|
<check if="any_test_fails">HALT: All tests must pass before marking complete</check>
|
|
248
347
|
<check if="any_dod_unchecked">HALT: All Definition of Done items must be checked before moving to review. Unchecked items: {list}. Return to Step 10 to resolve.</check>
|
|
249
348
|
</step>
|
|
250
|
-
<step n="
|
|
349
|
+
<step n="18" title="Update Status">
|
|
350
|
+
<action>PR MERGE DOD GATE (E20-S9 / FR-251 / AC4, AC5): Before invoking status-sync, re-read the "Definition of Done" section of the story file and locate the PR merge DoD line (the line rendered by Step 10 under the Quality group). Verify that the line is either (a) checked — "- [x] PR merged to {branch}" (auto-checked by Step 16 on successful merge), or (b) N/A — "- [x] PR merged — N/A (no promotion chain configured)" (pre-checked when ci_cd is absent). Both the checked and N/A variants are treated as GATE PASS and the workflow proceeds to status-sync. Any unchecked "- [ ] PR merged to ..." line is GATE FAIL.</action>
|
|
351
|
+
<check if="pr_merge_dod_item_unchecked">HALT: Cannot transition {story_key} to `review`: DoD item 'PR merged to {branch}' is not satisfied. Re-run Step 16 (Merge PR) or resolve manually before retrying the status transition.</check>
|
|
251
352
|
<invoke-protocol ref="status-sync" story_key="{story_key}" new_status="review" source_workflow="dev-story" />
|
|
252
353
|
<action>Append files changed list to story file</action>
|
|
253
354
|
<action>Initialize Review Gate section in story file: set all six rows (Code Review, QA Tests, Security Review, Test Automation, Test Review, Performance Review) to PENDING with report link "—". If Review Gate section already exists, reset all rows to PENDING.</action>
|
|
@@ -255,7 +356,7 @@
|
|
|
255
356
|
Update story file with status change to 'review', list of files changed, and initialized Review Gate table (all 6 rows PENDING).
|
|
256
357
|
</template-output>
|
|
257
358
|
</step>
|
|
258
|
-
<step n="
|
|
359
|
+
<step n="19" title="Auto-Run Reviews (YOLO only)">
|
|
259
360
|
<action if="not yolo_mode">Skip this step — in normal mode, user runs /gaia-run-all-reviews manually when ready.</action>
|
|
260
361
|
<action if="yolo_mode">Spawn a subagent using the Agent tool with this prompt:
|
|
261
362
|
"Load {project-root}/_gaia/core/engine/workflow.xml, then process {project-root}/_gaia/lifecycle/workflows/4-implementation/run-all-reviews/workflow.yaml as workflow-config. The story key is {story_key}. Run in YOLO mode — auto-proceed past all template-outputs. Follow the workflow engine instructions EXACTLY."
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '/gaia-ci-edit Validation'
|
|
3
|
+
validation-target: 'Updated ci_cd.promotion_chain in global.yaml'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Pre-conditions
|
|
7
|
+
- [ ] global.yaml exists and is readable
|
|
8
|
+
- [ ] ci_cd.promotion_chain block is present (not the initial-setup path)
|
|
9
|
+
- [ ] Current chain passes E20-S1 schema validator before edits begin
|
|
10
|
+
|
|
11
|
+
## Operation Safety
|
|
12
|
+
- [ ] Remove operation ran reference scan (checkpoints + stories + test-environment.yaml)
|
|
13
|
+
- [ ] Remove operation required explicit confirmation when references were found
|
|
14
|
+
- [ ] Edit operation rejected any attempt to change the immutable `id` field
|
|
15
|
+
- [ ] Edit operation re-checked branch uniqueness after field changes
|
|
16
|
+
- [ ] Reorder operation warned when position 0 changed (PR target change)
|
|
17
|
+
- [ ] No operation was allowed to leave the chain with zero entries
|
|
18
|
+
|
|
19
|
+
## Schema Validation
|
|
20
|
+
- [ ] Modified chain passes the E20-S1 schema validator before write
|
|
21
|
+
- [ ] All ids are unique
|
|
22
|
+
- [ ] All branches are unique
|
|
23
|
+
- [ ] All entries have required fields (id, name, branch, ci_provider)
|
|
24
|
+
- [ ] All ci_provider values are in the allowed enum
|
|
25
|
+
- [ ] All merge_strategy values are in the allowed enum
|
|
26
|
+
- [ ] All ids match the slug pattern [a-z0-9-]+
|
|
27
|
+
|
|
28
|
+
## Write Safety
|
|
29
|
+
- [ ] Only the ci_cd.promotion_chain block was modified in global.yaml
|
|
30
|
+
- [ ] All other fields (framework_version, user_name, project_path, ...) are preserved
|
|
31
|
+
- [ ] Comments in global.yaml are preserved
|
|
32
|
+
|
|
33
|
+
## Cascade Updates
|
|
34
|
+
- [ ] CI pipeline configs updated if branches changed
|
|
35
|
+
- [ ] test-environment.yaml tier mappings updated if ids changed
|
|
36
|
+
- [ ] ci-setup.md regenerated or annotated
|
|
37
|
+
- [ ] /gaia-build-configs re-ran to refresh .resolved/ cache
|
|
38
|
+
|
|
39
|
+
## Output Verification
|
|
40
|
+
- [ ] Updated chain written to _gaia/_config/global.yaml
|
|
41
|
+
- [ ] Summary displayed to user with operation + affected entries + cascade results
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<workflow name="ci-edit">
|
|
2
|
+
<critical>
|
|
3
|
+
<mandate>The `ci_cd.promotion_chain` block in global.yaml is the single source of truth for the promotion chain. Every write MUST pass the E20-S1 schema validator before being committed to disk.</mandate>
|
|
4
|
+
<mandate>The `id` field of every entry is immutable (ADR-033). Edits that attempt to change `id` must be rejected.</mandate>
|
|
5
|
+
<mandate>Every CRUD operation must be followed by a full chain re-validation. Partial updates are not permitted.</mandate>
|
|
6
|
+
<mandate>An operation that would leave zero entries in the chain is ALWAYS blocked. The chain must contain at least 1 environment at all times.</mandate>
|
|
7
|
+
<mandate>Remove and Edit operations must run the safety scan first — checkpoints, stories, test-environment.yaml — and require explicit user confirmation when references are found.</mandate>
|
|
8
|
+
</critical>
|
|
9
|
+
|
|
10
|
+
<step n="1" title="Load Current Promotion Chain">
|
|
11
|
+
<action>Read {project-root}/_gaia/_config/global.yaml in full. Preserve all fields and comments — this workflow only modifies the ci_cd.promotion_chain block.</action>
|
|
12
|
+
<action>Check whether a top-level ci_cd block exists and whether it contains a promotion_chain array.</action>
|
|
13
|
+
<check if="ci_cd block absent or promotion_chain field missing">
|
|
14
|
+
Display: "No promotion chain configured. Run /gaia-ci-setup first to create the initial chain, then re-run /gaia-ci-edit." HALT — do not attempt to add a chain from scratch.
|
|
15
|
+
</check>
|
|
16
|
+
<action>Invoke the E20-S1 validator at {project-path}/test/validators/promotion-chain-validator.js on the current chain to confirm it is in a valid starting state. If the current chain is already invalid, surface the violations to the user before proceeding.</action>
|
|
17
|
+
<action>Render the current chain as a formatted table: position | id | branch | environment | merge_strategy | test_tiers | ci_provider. Display this table to the user so they see exactly what they are editing.</action>
|
|
18
|
+
</step>
|
|
19
|
+
|
|
20
|
+
<step n="2" title="Present Operation Menu">
|
|
21
|
+
<action>Present the CRUD operation menu:
|
|
22
|
+
[a] add — insert a new environment into the chain
|
|
23
|
+
[r] remove — delete an existing environment (with safety scan)
|
|
24
|
+
[e] edit — modify fields of an existing environment (id is immutable)
|
|
25
|
+
[o] order — reorder the chain (warns on position 0 change)
|
|
26
|
+
[v] view — re-render the current chain table and return to the menu
|
|
27
|
+
[x] exit — close the workflow without writing
|
|
28
|
+
</action>
|
|
29
|
+
<ask>Select an operation: [a]dd / [r]emove / [e]dit / [o]rder / [v]iew / [x]it</ask>
|
|
30
|
+
<action if="[v]">Re-render the chain table and loop back to this menu.</action>
|
|
31
|
+
<action if="[x]">Write nothing — terminate the workflow cleanly.</action>
|
|
32
|
+
</step>
|
|
33
|
+
|
|
34
|
+
<step n="3" title="Add Operation" optional="true">
|
|
35
|
+
<critical>
|
|
36
|
+
<mandate>This step runs only when the user selected [a]dd.</mandate>
|
|
37
|
+
</critical>
|
|
38
|
+
<action>Prompt the user for each required field in order:
|
|
39
|
+
- id (string, slug format [a-z0-9-]+, must be unique in the chain) — required
|
|
40
|
+
- name (human-readable label) — required
|
|
41
|
+
- branch (git branch name, must be unique in the chain) — required
|
|
42
|
+
- ci_provider — enum: github_actions | gitlab_ci | jenkins | circleci | azure_devops | bitbucket | none
|
|
43
|
+
- merge_strategy — enum: merge | squash | rebase
|
|
44
|
+
- test_tiers — optional array of tier names
|
|
45
|
+
- auto_merge — boolean, default false
|
|
46
|
+
- approval_required — boolean, default false
|
|
47
|
+
</action>
|
|
48
|
+
<ask>Insertion position (0-based index, or leave blank to append to the end):</ask>
|
|
49
|
+
<action>Call `addEnvironment(currentChain, newEntry, {position})` from {project-path}/test/validators/promotion-chain-editor.js. The helper rejects duplicate id or branch and returns a new chain array.</action>
|
|
50
|
+
<check if="DuplicateFieldError thrown">Display the specific field and value, prompt the user to enter a unique replacement, and re-run the helper. Repeat until the entry is accepted.</check>
|
|
51
|
+
<action>Proceed to Step 7 (Validate + Write + Cascade).</action>
|
|
52
|
+
</step>
|
|
53
|
+
|
|
54
|
+
<step n="4" title="Remove Operation" optional="true">
|
|
55
|
+
<critical>
|
|
56
|
+
<mandate>This step runs only when the user selected [r]emove.</mandate>
|
|
57
|
+
</critical>
|
|
58
|
+
<action>Prompt the user for the id of the environment to remove.</action>
|
|
59
|
+
<check if="chain length is 1">
|
|
60
|
+
HALT the operation: "Cannot remove the last environment — promotion chain must have at least 1 environment. Add a replacement environment first, or use /gaia-ci-setup to reset the chain." Return to Step 2.
|
|
61
|
+
</check>
|
|
62
|
+
<action>Run the safety scan via scanReferences() using three source sets:
|
|
63
|
+
1. Checkpoints: enumerate {project-root}/_memory/checkpoints/ and {project-root}/_memory/checkpoints/completed/ for any dev-story-*.yaml whose `branch` field matches the target environment's branch.
|
|
64
|
+
2. Stories: glob {project-root}/docs/implementation-artifacts/*.md and grep for the environment id or branch name — collect matching story files.
|
|
65
|
+
3. test-environment.yaml: read {project-root}/_gaia/_config/test-environment.yaml and find any tier entry whose `environment` field equals the id being removed.
|
|
66
|
+
</action>
|
|
67
|
+
<check if="scanReferences returns found==true">
|
|
68
|
+
Display the list of references grouped by type (checkpoints, stories, test-environment tiers) and the specific detail for each. Present an explicit confirmation prompt:
|
|
69
|
+
"The environment '{id}' is referenced by {N} location(s) above. Removing it may break downstream workflows. Proceed anyway? [y] Yes, remove and cascade / [n] No, cancel"
|
|
70
|
+
Only on explicit [y] may the removal proceed.
|
|
71
|
+
</check>
|
|
72
|
+
<action>Call `removeEnvironment(currentChain, targetId)` from the editor module. This helper re-checks the minimum-1 rule and throws MinimumChainError if it would leave zero entries.</action>
|
|
73
|
+
<action>Proceed to Step 7 (Validate + Write + Cascade).</action>
|
|
74
|
+
</step>
|
|
75
|
+
|
|
76
|
+
<step n="5" title="Edit Operation" optional="true">
|
|
77
|
+
<critical>
|
|
78
|
+
<mandate>This step runs only when the user selected [e]dit. The `id` field is immutable per ADR-033 — any attempt to modify it is rejected.</mandate>
|
|
79
|
+
</critical>
|
|
80
|
+
<action>Prompt the user for the id of the environment to edit. Display its current field values.</action>
|
|
81
|
+
<action>Allow the user to modify any of the following fields: branch, name, environment, test_tiers, merge_strategy, auto_merge, approval_required, ci_provider, ci_checks.</action>
|
|
82
|
+
<check if="user attempts to edit id">
|
|
83
|
+
Display: "Field 'id' is immutable (ADR-033). To rename the stable key, remove this entry and add a new one with the desired id." Block the edit and return the user to the field selection prompt.
|
|
84
|
+
</check>
|
|
85
|
+
<action>Run the safety scan (same three sources as Step 4) BEFORE applying the edit, because an edited branch name has downstream consequences for CI pipelines and checkpoints.</action>
|
|
86
|
+
<check if="scanReferences returns found==true AND branch is being edited">
|
|
87
|
+
Warn the user that changing the branch may break active work and require explicit confirmation.
|
|
88
|
+
</check>
|
|
89
|
+
<action>Call `editEnvironment(currentChain, targetId, updates)` from the editor module. The helper rejects immutable field changes and duplicate branch values.</action>
|
|
90
|
+
<action>Proceed to Step 7 (Validate + Write + Cascade).</action>
|
|
91
|
+
</step>
|
|
92
|
+
|
|
93
|
+
<step n="6" title="Reorder Operation" optional="true">
|
|
94
|
+
<critical>
|
|
95
|
+
<mandate>This step runs only when the user selected [o]rder. Changing position 0 changes the PR target for all feature branches — the user must explicitly acknowledge this.</mandate>
|
|
96
|
+
</critical>
|
|
97
|
+
<action>Render the current chain as a numbered list and prompt the user to enter the new order as a comma-separated list of ids, e.g., "prod, dev, staging".</action>
|
|
98
|
+
<check if="reorder would result in empty chain">
|
|
99
|
+
HALT with MinimumChainError — chain must have at least 1 environment.
|
|
100
|
+
</check>
|
|
101
|
+
<action>Call `reorderChain(currentChain, orderList)` from the editor module. The helper rejects unknown ids, rejects incomplete orderings, and returns a new chain array with a `.meta` property describing the position-0 change.</action>
|
|
102
|
+
<check if="result.meta.position_zero_changed == true">
|
|
103
|
+
Warn the user: "Reordering position 0 changes the PR target from '{previous_pr_target}' to '{new_pr_target}'. All feature branches will merge into '{new_pr_target}' from this point forward. Continue? [y] Yes / [n] No"
|
|
104
|
+
Only proceed on explicit [y].
|
|
105
|
+
</check>
|
|
106
|
+
<action>Proceed to Step 7 (Validate + Write + Cascade).</action>
|
|
107
|
+
</step>
|
|
108
|
+
|
|
109
|
+
<step n="7" title="Validate, Write, and Cascade Updates">
|
|
110
|
+
<action>Invoke the E20-S1 schema validator at {project-path}/test/validators/promotion-chain-validator.js on the modified chain. This enforces: minimum 1 entry, unique ids, unique branches, required fields, valid enum values, id slug pattern.</action>
|
|
111
|
+
<check if="validator throws">
|
|
112
|
+
Display the list of violations returned by the validator and return the user to the operation menu without writing to global.yaml. The chain on disk remains unchanged.
|
|
113
|
+
</check>
|
|
114
|
+
<action>Write the updated chain back to {project-root}/_gaia/_config/global.yaml. Only the ci_cd.promotion_chain block may be modified — all other fields and comments must be preserved exactly.</action>
|
|
115
|
+
<action>Cascade updates after the write succeeds:
|
|
116
|
+
1. If any branch name changed, update the matching trigger in {project-root}/.github/workflows/*.yml (or the equivalent CI config for the configured ci_provider). If no matching trigger exists, log a warning but do not fail.
|
|
117
|
+
2. If any environment id was removed or renamed, update {project-root}/_gaia/_config/test-environment.yaml tier mappings to drop or rename the affected entries.
|
|
118
|
+
3. Regenerate {project-root}/docs/test-artifacts/ci-setup.md by re-running the relevant section of /gaia-ci-setup (or noting the change with a manual update marker).
|
|
119
|
+
4. Run /gaia-build-configs to regenerate the .resolved/ config cache so the new chain is visible to all workflows.
|
|
120
|
+
</action>
|
|
121
|
+
<action>On any cascade failure, surface the specific error to the user — do NOT attempt a rollback of global.yaml silently. Instead, report which cascade step failed and point the user at the file to correct manually.</action>
|
|
122
|
+
</step>
|
|
123
|
+
|
|
124
|
+
<step n="8" title="Summary">
|
|
125
|
+
<action>Display a summary of what changed: operation performed, entries affected, whether position 0 moved, which cascade steps ran, and any warnings encountered during cascade.</action>
|
|
126
|
+
<action>Remind the user to commit the updated global.yaml and any cascade targets on a feature branch — this workflow never commits automatically.</action>
|
|
127
|
+
</step>
|
|
128
|
+
|
|
129
|
+
<next-step source="lifecycle-sequence.yaml">
|
|
130
|
+
<standalone>This is a standalone workflow. Return to your current lifecycle phase.</standalone>
|
|
131
|
+
</next-step>
|
|
132
|
+
</workflow>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: ci-edit
|
|
2
|
+
description: 'Edit the ci_cd.promotion_chain in global.yaml — add, remove, edit, or reorder environments'
|
|
3
|
+
module: testing
|
|
4
|
+
agent: test-architect
|
|
5
|
+
val_validate_output: true
|
|
6
|
+
config_resolved: "{installed_path}/.resolved/ci-edit.yaml"
|
|
7
|
+
config_source: "{project-root}/_gaia/testing/config.yaml"
|
|
8
|
+
installed_path: "{project-root}/_gaia/testing/workflows/ci-edit"
|
|
9
|
+
instructions: "{installed_path}/instructions.xml"
|
|
10
|
+
validation: "{installed_path}/checklist.md"
|
|
11
|
+
input_file_patterns:
|
|
12
|
+
global_yaml:
|
|
13
|
+
whole: "{project-root}/_gaia/_config/global.yaml"
|
|
14
|
+
load_strategy: "FULL_LOAD"
|
|
15
|
+
test_environment:
|
|
16
|
+
whole: "{project-root}/_gaia/_config/test-environment.yaml"
|
|
17
|
+
load_strategy: "FULL_LOAD"
|
|
18
|
+
quality_gates:
|
|
19
|
+
pre_start:
|
|
20
|
+
- check: "global_yaml_exists"
|
|
21
|
+
on_fail: "HALT: global.yaml not found at {project-root}/_gaia/_config/global.yaml. This workflow edits the ci_cd.promotion_chain block — run /gaia-ci-setup first to create the initial chain."
|
|
22
|
+
post_complete:
|
|
23
|
+
- check: "chain_passes_e20_s1_validator"
|
|
24
|
+
on_fail: "HALT: updated promotion chain failed schema validation — changes were not written to {project-root}/_gaia/_config/global.yaml. Review violations above and re-run /gaia-ci-edit."
|
|
25
|
+
on_error:
|
|
26
|
+
missing_file: "ask_user"
|
|
27
|
+
unresolved_variable: "halt"
|
|
28
|
+
|
|
29
|
+
output:
|
|
30
|
+
primary: "{project-root}/_gaia/_config/global.yaml"
|
|
@@ -8,32 +8,100 @@
|
|
|
8
8
|
<action>If no config found: note that no existing CI platform was detected</action>
|
|
9
9
|
<ask>Which CI platform would you like to use? Options: GitHub Actions, GitLab CI, Jenkins, CircleCI, or other. {If detected: "Detected: {platform} — recommended based on existing config."}</ask>
|
|
10
10
|
</step>
|
|
11
|
-
<step n="2" title="
|
|
11
|
+
<step n="2" title="Preset Selection (Promotion Chain)">
|
|
12
|
+
<critical>
|
|
13
|
+
<mandate>This step configures the ci_cd.promotion_chain block in {project-root}/_gaia/_config/global.yaml. It uses the 4 canonical presets from {project-root}/_gaia/_config/environment-presets.yaml (created by E20-S2) and reuses the E20-S1 promotion-chain schema validator.</mandate>
|
|
14
|
+
</critical>
|
|
15
|
+
|
|
16
|
+
<!-- AC5 (Task 1.5): existing ci_cd block — overwrite / skip / edit -->
|
|
17
|
+
<action>Read {project-root}/_gaia/_config/global.yaml. Check whether a top-level ci_cd block exists (with or without a promotion_chain field).</action>
|
|
18
|
+
<check if="ci_cd block exists in global.yaml">
|
|
19
|
+
Warn the user: "Existing ci_cd configuration found in global.yaml." and present three options:
|
|
20
|
+
[o]verwrite — replace the existing ci_cd.promotion_chain with a newly selected preset (or custom chain)
|
|
21
|
+
[s]kip — leave the existing ci_cd block unchanged and proceed to Step 3 (no write performed)
|
|
22
|
+
[e]dit — redirect the user to /gaia-ci-edit (E20-S4) for structured editing of the existing chain
|
|
23
|
+
Respect the user's choice:
|
|
24
|
+
- On [s]kip: jump directly to Step 3 without modifying global.yaml — backward compatible, no-op.
|
|
25
|
+
- On [e]dit: hand off to /gaia-ci-edit and terminate this step.
|
|
26
|
+
- On [o]verwrite: fall through to the preset-selection prompt below.
|
|
27
|
+
</check>
|
|
28
|
+
|
|
29
|
+
<!-- AC1 (Task 1.2): load presets from environment-presets.yaml -->
|
|
30
|
+
<action>Read {project-root}/_gaia/_config/environment-presets.yaml — this file is produced by E20-S2 and contains the four canonical presets (solo, small-team, standard, enterprise). Each preset exposes a `description` field and a `promotion_chain` array.</action>
|
|
31
|
+
<check if="environment-presets.yaml not found">HALT with error "Environment presets file not found at _gaia/_config/environment-presets.yaml. Run E20-S2 (Environment Presets Definition) before re-running /gaia-ci-setup." — this is the AC10/test-scenario-10 failure mode.</check>
|
|
32
|
+
<action>Parse the YAML and extract the 4 preset names: solo, small-team, standard, enterprise. For each preset, extract its `description` string to show to the user.</action>
|
|
33
|
+
|
|
34
|
+
<!-- AC6 (Task 1.4): YOLO mode auto-selects 'standard' -->
|
|
35
|
+
<check if="yolo_mode">
|
|
36
|
+
Auto-select the `standard` preset without prompting the user — this follows the existing YOLO convention of auto-answering from context when unambiguous. Log to the user: "YOLO mode: auto-selected `standard` preset (3-tier dev → staging → prod flow)." Skip the ask prompt below and proceed straight to the preset application action.
|
|
37
|
+
</check>
|
|
38
|
+
|
|
39
|
+
<!-- AC1 (Task 1.3): present presets table + custom option -->
|
|
40
|
+
<ask>
|
|
41
|
+
Select a promotion-chain preset for this project:
|
|
42
|
+
|
|
43
|
+
| # | Preset | Description |
|
|
44
|
+
|---|--------------|--------------------------------------------------------------------------------------------------------------|
|
|
45
|
+
| 1 | solo | {presets.solo.description} — single environment, direct to main, auto-merge. |
|
|
46
|
+
| 2 | small-team | {presets.small-team.description} — 2 envs (develop → main) for a small team with one pre-prod gate. |
|
|
47
|
+
| 3 | standard | {presets.standard.description} — 3 envs (dev → staging → prod), the recommended default for product teams. |
|
|
48
|
+
| 4 | enterprise | {presets.enterprise.description} — 4 envs (dev → uat → staging → prod) with approval gates and audit trail. |
|
|
49
|
+
| 5 | custom | Define your own promotion_chain interactively (see Task 3 builder below). |
|
|
50
|
+
|
|
51
|
+
Choose [1] solo / [2] small-team / [3] standard / [4] enterprise / [5] custom:
|
|
52
|
+
</ask>
|
|
53
|
+
|
|
54
|
+
<!-- AC3 (Task 3): custom environment builder -->
|
|
55
|
+
<check if="user selected custom">
|
|
56
|
+
Enter the interactive custom environment builder. For each environment, prompt the user for the following fields one-by-one, then loop until the user chooses to finish:
|
|
57
|
+
<action>Prompt for `id` (string, slug format [a-z0-9-]+, must be unique within the chain) — required.</action>
|
|
58
|
+
<action>Prompt for `name` (human-readable string) — required.</action>
|
|
59
|
+
<action>Prompt for `branch` (git branch name, must be unique within the chain) — required.</action>
|
|
60
|
+
<action>Prompt for `ci_provider` — present enum selection: [1] github_actions [2] gitlab_ci [3] jenkins [4] circleci [5] azure_devops [6] bitbucket [7] none. Required.</action>
|
|
61
|
+
<action>Prompt for `merge_strategy` — present enum selection: [1] merge [2] squash [3] rebase. Required unless a default is set in ci_cd.default_merge_strategy.</action>
|
|
62
|
+
<action>Prompt for `ci_checks` — optional array of check names (e.g., lint, unit, integration, e2e). Accept empty to skip.</action>
|
|
63
|
+
<ask>Environment {n} defined. Add another environment? [y]es / [n]o (finish)</ask>
|
|
64
|
+
When the user finishes, assemble the `promotion_chain` array from the collected entries. If the user added zero environments, warn them that the E20-S1 schema validator requires a minimum of one environment and return to the loop.
|
|
65
|
+
</check>
|
|
66
|
+
|
|
67
|
+
<!-- AC2 (Task 2): apply the chosen preset — write ci_cd.promotion_chain to global.yaml -->
|
|
68
|
+
<action>If the user chose a named preset (solo/small-team/standard/enterprise): use the full promotion_chain array from the selected preset in environment-presets.yaml verbatim. If the user chose custom: use the array assembled by the custom builder above.</action>
|
|
69
|
+
<action>Load the current {project-root}/_gaia/_config/global.yaml content. Preserve all existing fields and comments — only add or replace the top-level `ci_cd` key. Merge semantics: write `ci_cd.promotion_chain: {selected array}` under the existing `ci_cd` block if one exists (from the overwrite path), or create a new `ci_cd` block containing only `promotion_chain` if none exists. All other global.yaml content (framework_version, user_name, project_path, planning_artifacts, etc.) MUST remain unchanged.</action>
|
|
70
|
+
<action>Write the updated content back to global.yaml. Do not reformat unrelated sections — emit a minimal diff focused on the ci_cd block.</action>
|
|
71
|
+
|
|
72
|
+
<!-- AC4 (Task 4): E20-S1 schema validation -->
|
|
73
|
+
<action>After the write completes, invoke the E20-S1 schema validator at {project-path}/test/validators/promotion-chain-validator.js on the newly written block. The validator enforces: (a) minimum 1 environment (FR-252), (b) no duplicate ids across entries, (c) no duplicate branches across entries, (d) each entry has required fields id/name/branch/ci_provider, (e) ci_provider is one of the enum values, (f) merge_strategy (if set) is one of merge/squash/rebase, (g) id matches slug pattern [a-z0-9-]+.</action>
|
|
74
|
+
<check if="validation fails">
|
|
75
|
+
Display the specific violation(s) returned by the validator — include each violation's field path and reason (e.g., "promotion_chain[1].id duplicates promotion_chain[0].id" or "promotion_chain is empty — minimum 1 environment required"). Prompt the user to correct the failing fields. After corrections, re-run the validator. Repeat this validate→correct loop until the block passes.
|
|
76
|
+
</check>
|
|
77
|
+
<action>When validation passes, log success: "ci_cd.promotion_chain written to global.yaml and validated ({n} environment(s))."</action>
|
|
78
|
+
</step>
|
|
79
|
+
<step n="3" title="Define Pipeline">
|
|
12
80
|
<action>Build > lint > test > coverage > deploy gates</action>
|
|
13
81
|
</step>
|
|
14
|
-
<step n="
|
|
82
|
+
<step n="4" title="Quality Gates">
|
|
15
83
|
<action>Define pass/fail thresholds: coverage %, test pass rate</action>
|
|
16
84
|
</step>
|
|
17
|
-
<step n="
|
|
85
|
+
<step n="5" title="Secrets Management">
|
|
18
86
|
<action>Identify all required secrets from architecture and PRD: API keys, database credentials, auth secrets, third-party service keys</action>
|
|
19
87
|
<action>Document how to add secrets to the selected CI platform (e.g., GitHub Repository Secrets, GitLab CI/CD Variables)</action>
|
|
20
88
|
<action>Define environment-level separation: which secrets differ between staging and production</action>
|
|
21
89
|
<action>List each secret with its name, purpose, and which pipeline stages need it</action>
|
|
22
90
|
</step>
|
|
23
|
-
<step n="
|
|
91
|
+
<step n="6" title="Deployment Strategy">
|
|
24
92
|
<action>Define staging deployment: auto-deploy on merge to develop branch after all gates pass</action>
|
|
25
93
|
<action>Define production deployment: deploy on merge to main with manual approval gate</action>
|
|
26
94
|
<action>Define rollback procedure: how to revert a failed deployment (rollback trigger, steps, verification)</action>
|
|
27
95
|
</step>
|
|
28
|
-
<step n="
|
|
96
|
+
<step n="7" title="Monitoring and Notifications">
|
|
29
97
|
<action>Configure pipeline failure notifications: Slack webhook, email, or platform-native alerts</action>
|
|
30
98
|
<action>Add pipeline status badge for the project README</action>
|
|
31
99
|
<action>Recommend metrics dashboard for pipeline health (run duration trends, failure rates, flaky test tracking)</action>
|
|
32
100
|
</step>
|
|
33
|
-
<step n="
|
|
101
|
+
<step n="8" title="Generate Pipeline Config">
|
|
34
102
|
<action>Generate CI config file (.github/workflows/ci.yml or equivalent)</action>
|
|
35
103
|
</step>
|
|
36
|
-
<step n="
|
|
104
|
+
<step n="9" title="Generate Output">
|
|
37
105
|
<action>Generate CI/CD pipeline configuration document with: pipeline stages, quality gates, secrets management, deployment strategy, and monitoring setup</action>
|
|
38
106
|
<template-output file="{test_artifacts}/ci-setup.md" />
|
|
39
107
|
</step>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# Test Gap Analysis Checklist
|
|
2
|
+
|
|
3
|
+
## Coverage Mode
|
|
2
4
|
- [ ] Execution mode determined (coverage or verification)
|
|
3
5
|
- [ ] Test plan scanned for test case IDs and story links
|
|
4
6
|
- [ ] Story files scanned for acceptance criteria
|
|
@@ -6,3 +8,13 @@
|
|
|
6
8
|
- [ ] Output follows FR-223 schema (summary count, per-story table, coverage %)
|
|
7
9
|
- [ ] Zero-gap case handled with "No coverage gaps detected" message
|
|
8
10
|
- [ ] Workflow completed within NFR-040 performance constraint (< 60 seconds)
|
|
11
|
+
|
|
12
|
+
## Verification Mode (FR-222, FR-226)
|
|
13
|
+
- [ ] Generated test cases scanned from docs/test-artifacts/
|
|
14
|
+
- [ ] Execution results detected: JUnit XML, LCOV, or E17 evidence JSON
|
|
15
|
+
- [ ] Cross-reference generated vs executed test cases completed
|
|
16
|
+
- [ ] Per-story generated-vs-executed count included in output
|
|
17
|
+
- [ ] Aggregate generated-vs-executed count included in output
|
|
18
|
+
- [ ] Stories with zero executed tests flagged as HIGH priority gaps
|
|
19
|
+
- [ ] Graceful degradation when no execution results — warning logged, fallback to coverage mode
|
|
20
|
+
- [ ] Workflow completed within NFR-040 performance constraint (< 60 seconds)
|
|
@@ -3,14 +3,20 @@
|
|
|
3
3
|
<mandate>Scan test-plan.md and story files to identify acceptance criteria gaps — NFR-040 requires completion in under 60 seconds</mandate>
|
|
4
4
|
<mandate>Output must follow the FR-223 schema: summary count, per-story gap table, coverage percentage</mandate>
|
|
5
5
|
<mandate>When no gaps are detected, output must state "No coverage gaps detected" with a summary count of zero</mandate>
|
|
6
|
+
<mandate>Verification mode must cross-reference generated test cases against execution results from JUnit XML, LCOV, or E17 evidence JSON sources (FR-222, FR-226)</mandate>
|
|
6
7
|
</critical>
|
|
7
8
|
|
|
8
9
|
<step n="1" title="Determine Mode">
|
|
9
10
|
<action>Check the --mode argument: coverage or verification</action>
|
|
10
11
|
<action>If no mode specified, default to coverage mode</action>
|
|
11
|
-
<action>If mode is '
|
|
12
|
+
<action>If mode is 'coverage', proceed to Step 2 (coverage mode steps)</action>
|
|
13
|
+
<action>If mode is 'verification', proceed to Step 7 (verification mode steps)</action>
|
|
12
14
|
</step>
|
|
13
15
|
|
|
16
|
+
<!-- ======================== -->
|
|
17
|
+
<!-- COVERAGE MODE: Steps 2-6 -->
|
|
18
|
+
<!-- ======================== -->
|
|
19
|
+
|
|
14
20
|
<step n="2" title="Scan Test Plan">
|
|
15
21
|
<action>Read {test_artifacts}/test-plan.md</action>
|
|
16
22
|
<action>Extract all test case IDs and their linked story keys from the test plan</action>
|
|
@@ -46,7 +52,60 @@
|
|
|
46
52
|
</template-output>
|
|
47
53
|
</step>
|
|
48
54
|
|
|
49
|
-
<step n="6" title="Performance Validation">
|
|
55
|
+
<step n="6" title="Performance Validation (Coverage Mode)">
|
|
56
|
+
<action>Verify workflow completed within the NFR-040 constraint of under 60 seconds</action>
|
|
57
|
+
<action>Log total execution time in the output footer</action>
|
|
58
|
+
</step>
|
|
59
|
+
|
|
60
|
+
<!-- ================================= -->
|
|
61
|
+
<!-- VERIFICATION MODE: Steps 7-11 -->
|
|
62
|
+
<!-- FR-222, FR-226, ADR-030 §10.22 -->
|
|
63
|
+
<!-- ================================= -->
|
|
64
|
+
|
|
65
|
+
<step n="7" title="Scan Generated Test Cases (Verification Mode)">
|
|
66
|
+
<action>Scan docs/test-artifacts/ for all generated test case files and test plan references</action>
|
|
67
|
+
<action>Build a map of generated test cases per story: story_key -> [test_case_id, test_file, test_name]</action>
|
|
68
|
+
<action>Cross-reference generated test cases with story files in docs/implementation-artifacts/</action>
|
|
69
|
+
<action>Count total generated test cases per story and in aggregate</action>
|
|
70
|
+
</step>
|
|
71
|
+
|
|
72
|
+
<step n="8" title="Detect and Parse Execution Results (Verification Mode)">
|
|
73
|
+
<action>Scan for available test execution result files in the following formats:
|
|
74
|
+
1. JUnit XML files — parse test name, status (pass/fail/skip) from XML testcase elements
|
|
75
|
+
2. LCOV coverage files — parse source file coverage data and hit counts
|
|
76
|
+
3. E17 evidence JSON files — parse test IDs and execution status per the E17-S10 schema
|
|
77
|
+
</action>
|
|
78
|
+
<action>If no execution result files are found in any format (no JUnit XML, no LCOV, no evidence JSON):
|
|
79
|
+
Log warning: "No test execution results found — verification mode cannot determine executed test counts. Falling back to coverage mode output."
|
|
80
|
+
Graceful degradation: fallback to coverage mode output and skip remaining verification steps.
|
|
81
|
+
Proceed to Step 5 (coverage mode output generation) instead.</action>
|
|
82
|
+
<action>For each detected result format, extract: test identifier, execution status (passed/failed/skipped/unrun), and timestamp if available</action>
|
|
83
|
+
<action>Build a unified executed tests map: test_id -> {status, source_format, last_run}</action>
|
|
84
|
+
</step>
|
|
85
|
+
|
|
86
|
+
<step n="9" title="Cross-Reference Generated vs Executed (Verification Mode)">
|
|
87
|
+
<action>For each story, cross-reference its generated test cases against the executed tests map</action>
|
|
88
|
+
<action>Classify each generated test case as: EXECUTED (found in results with pass/fail status) or UNEXECUTED (not found in any result file)</action>
|
|
89
|
+
<action>Calculate per story counts: generated test cases count, executed test cases count</action>
|
|
90
|
+
<action>Calculate aggregate totals: total generated across all stories, total executed across all stories</action>
|
|
91
|
+
<action>Flag stories with zero executed tests as HIGH priority gaps — these stories have generated test cases but none have been run</action>
|
|
92
|
+
</step>
|
|
93
|
+
|
|
94
|
+
<step n="10" title="Generate Verification Output (FR-226 Schema)">
|
|
95
|
+
<action>Generate the output artifact at {test_artifacts}/test-gap-analysis-{date}.md in verification mode format</action>
|
|
96
|
+
<action>Output must include the following FR-226 schema sections:
|
|
97
|
+
- Summary section with total generated test count, total executed test count, and verification percentage
|
|
98
|
+
- Per-story generated-vs-executed count table listing each story with its generated count, executed count, and gap priority
|
|
99
|
+
- Aggregate generated-vs-executed count showing overall totals
|
|
100
|
+
- Unverified tests table listing test files with UNVERIFIED status and story key
|
|
101
|
+
</action>
|
|
102
|
+
<action>For stories with zero executed tests: set gap priority to HIGH in the per-story table</action>
|
|
103
|
+
<template-output file="{test_artifacts}/test-gap-analysis-{date}.md">
|
|
104
|
+
Verification mode gap analysis report with per-story and aggregate generated-vs-executed counts, HIGH priority flags for zero-executed stories.
|
|
105
|
+
</template-output>
|
|
106
|
+
</step>
|
|
107
|
+
|
|
108
|
+
<step n="11" title="Performance Validation (Verification Mode)">
|
|
50
109
|
<action>Verify workflow completed within the NFR-040 constraint of under 60 seconds</action>
|
|
51
110
|
<action>Log total execution time in the output footer</action>
|
|
52
111
|
</step>
|