gaia-framework 1.87.0 → 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.
Files changed (26) hide show
  1. package/.claude/commands/gaia-ci-edit.md +17 -0
  2. package/CLAUDE.md +10 -0
  3. package/_gaia/_config/environment-presets.yaml +140 -0
  4. package/_gaia/_config/global.yaml +1 -1
  5. package/_gaia/_config/lifecycle-sequence.yaml +9 -0
  6. package/_gaia/_config/workflow-manifest.csv +1 -0
  7. package/_gaia/core/engine/workflow.xml +2 -0
  8. package/_gaia/core/validators/ci-edit-audit.js +181 -0
  9. package/_gaia/core/validators/ci-edit-test-env-scan.js +89 -0
  10. package/_gaia/core/validators/dev-story-security-controls.js +264 -0
  11. package/_gaia/core/validators/promotion-chain-env-resolver.js +140 -0
  12. package/_gaia/core/validators/test-environment-validator.js +292 -0
  13. package/_gaia/lifecycle/knowledge/brownfield/test-execution-scan.md +56 -9
  14. package/_gaia/lifecycle/workflows/4-implementation/create-story/instructions.xml +4 -0
  15. package/_gaia/lifecycle/workflows/4-implementation/dev-story/checklist.md +2 -0
  16. package/_gaia/lifecycle/workflows/4-implementation/dev-story/instructions.xml +94 -3
  17. package/_gaia/testing/workflows/ci-edit/checklist.md +41 -0
  18. package/_gaia/testing/workflows/ci-edit/instructions.xml +132 -0
  19. package/_gaia/testing/workflows/ci-edit/workflow.yaml +30 -0
  20. package/_gaia/testing/workflows/ci-setup/instructions.xml +75 -7
  21. package/_gaia/testing/workflows/test-gap-analysis/checklist.md +12 -0
  22. package/_gaia/testing/workflows/test-gap-analysis/instructions.xml +61 -2
  23. package/_gaia/testing/workflows/test-gap-analysis/workflow.yaml +2 -0
  24. package/gaia-install.sh +72 -76
  25. package/lib/copy-lib.sh +81 -0
  26. package/package.json +2 -1
@@ -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 'verification', skip to verification-mode steps (E19-S2 scope — not implemented yet)</action>
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>
@@ -14,7 +14,9 @@ instructions: "{installed_path}/instructions.xml"
14
14
  validation: "{installed_path}/checklist.md"
15
15
  traces_to:
16
16
  - FR-221
17
+ - FR-222
17
18
  - FR-223
19
+ - FR-226
18
20
  - NFR-040
19
21
  performance_constraints:
20
22
  max_duration_seconds: 60 # NFR-040 — workflow must complete in under 60 seconds
package/gaia-install.sh CHANGED
@@ -77,6 +77,7 @@ OPT_YES=false
77
77
  OPT_DRY_RUN=false
78
78
  OPT_VERBOSE=false
79
79
  OPT_BRANCH=""
80
+ OPT_SKIP_SPRINT_GATE=false
80
81
 
81
82
  # ─── Utility Functions ──────────────────────────────────────────────────────
82
83
 
@@ -195,76 +196,10 @@ copy_with_backup() {
195
196
  [[ "$OPT_VERBOSE" == true ]] && detail "Updated (backed up): $dst" || true
196
197
  }
197
198
 
198
- # Remove .resolved/*.yaml files from target _gaia/ directory.
199
- # Called after cp/tar copy to replicate rsync's --exclude behavior.
200
- # Only .resolved/*.yaml is relevant to the _gaia/ subtree; the other rsync
201
- # --exclude patterns target _memory/ paths outside _gaia/ and never match.
202
- clean_resolved_yaml() {
203
- local target_gaia="$1"
204
- find "$target_gaia" -path '*/.resolved/*.yaml' -delete 2>/dev/null || true
205
- }
206
-
207
- # Copy _gaia/ directory from source to target using a fallback chain:
208
- # rsync → cp -rp → tar
209
- # Tries each tool in order. If a tool is found but fails at runtime (e.g.,
210
- # broken rsync stub on Windows), falls through to the next tool. Exits with
211
- # a diagnostic error if all tools fail or none are available.
212
- #
213
- # Excludes .resolved/*.yaml files from the final output (rsync handles this
214
- # natively via --exclude; cp and tar do a post-copy cleanup).
215
- #
216
- # Note: No symlinks currently exist in _gaia/. If symlinks are introduced
217
- # in the future, verify that cp -rp behavior matches rsync -a on all
218
- # target platforms (ADR-004).
219
- copy_gaia_files() {
220
- local src="$1" dst="$2"
221
- local copy_done=false
222
-
223
- # Try rsync first (preferred — handles excludes natively)
224
- if command -v rsync >/dev/null 2>&1; then
225
- if rsync -a \
226
- --exclude='_memory/checkpoints/*.yaml' \
227
- --exclude='_memory/checkpoints/completed/*.yaml' \
228
- --exclude='.resolved/*.yaml' \
229
- --exclude='_memory/*-sidecar/*.md' \
230
- --exclude='_memory/*-sidecar/*.yaml' \
231
- "$src/_gaia/" "$dst/_gaia/" 2>/dev/null; then
232
- detail "Copied framework files using rsync"
233
- copy_done=true
234
- else
235
- detail "rsync found but failed — trying fallback methods"
236
- fi
237
- fi
238
-
239
- # Fallback: cp -rp (preserves permissions like rsync -a)
240
- if [[ "$copy_done" == false ]] && command -v cp >/dev/null 2>&1; then
241
- if cp -rp "$src/_gaia/." "$dst/_gaia/" 2>/dev/null; then
242
- clean_resolved_yaml "$dst/_gaia"
243
- detail "Copied framework files using cp -rp (rsync unavailable)"
244
- copy_done=true
245
- else
246
- error "cp failed to copy framework files — check permissions and disk space"
247
- exit 1
248
- fi
249
- fi
250
-
251
- # Fallback: tar (last resort — available on virtually all POSIX systems)
252
- if [[ "$copy_done" == false ]] && command -v tar >/dev/null 2>&1; then
253
- if (tar -cf - -C "$src" _gaia | tar -xf - -C "$dst") 2>/dev/null; then
254
- clean_resolved_yaml "$dst/_gaia"
255
- detail "Copied framework files using tar (rsync and cp unavailable)"
256
- copy_done=true
257
- else
258
- error "tar failed to copy framework files — check permissions and disk space"
259
- exit 1
260
- fi
261
- fi
262
-
263
- if [[ "$copy_done" == false ]]; then
264
- error "No suitable copy tool found (tried rsync, cp, tar). Cannot copy framework files."
265
- exit 1
266
- fi
267
- }
199
+ # Source extracted copy functions (clean_resolved_yaml, copy_gaia_files)
200
+ # from lib/copy-lib.sh E3-S11
201
+ # shellcheck source=lib/copy-lib.sh
202
+ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/copy-lib.sh"
268
203
 
269
204
  append_if_missing() {
270
205
  local file="$1" marker="$2" content="$3"
@@ -322,6 +257,53 @@ count_files() {
322
257
  find "$dir" -name "$pattern" -type f 2>/dev/null | wc -l | tr -d ' '
323
258
  }
324
259
 
260
+ # ─── Sprint Gate (E18-S1, ADR-029 §10.21.2) ───────────────────────────────
261
+ # Reads sprint-status.yaml and hard-blocks the upgrade if any story has an
262
+ # active status (in-progress, review, or ready-for-dev).
263
+
264
+ check_sprint_gate() {
265
+ local target="$1"
266
+ local sprint_file="$target/docs/implementation-artifacts/sprint-status.yaml"
267
+
268
+ # AC3: If no sprint file exists, gate passes silently
269
+ if [[ ! -f "$sprint_file" ]]; then
270
+ [[ "$OPT_VERBOSE" == true ]] && detail "No sprint-status.yaml found — sprint gate passes"
271
+ return 0
272
+ fi
273
+
274
+ # Extract sprint_id (top-level field, unindented)
275
+ local sprint_id
276
+ sprint_id="$(extract_yaml_value "$sprint_file" "sprint_id")"
277
+ [[ -z "$sprint_id" ]] && sprint_id="unknown"
278
+
279
+ # Count active stories — match only indented status: lines (story entries)
280
+ local active_count=0
281
+ while IFS= read -r line; do
282
+ local status_val
283
+ status_val="${line#*status:}" # strip key
284
+ status_val="${status_val#"${status_val%%[![:space:]]*}"}" # trim leading whitespace
285
+ status_val="${status_val#[\"\']}" # trim leading quote
286
+ status_val="${status_val%[\"\']}" # trim trailing quote
287
+ case "$status_val" in
288
+ in-progress|review|ready-for-dev)
289
+ active_count=$((active_count + 1))
290
+ ;;
291
+ esac
292
+ done < <(grep '^[[:space:]]\{1,\}status:' "$sprint_file")
293
+
294
+ # AC3: If no active stories, gate passes
295
+ if [[ "$active_count" -eq 0 ]]; then
296
+ [[ "$OPT_VERBOSE" == true ]] && detail "Sprint gate passes — no active stories"
297
+ return 0
298
+ fi
299
+
300
+ # AC2: Hard block with clear error message
301
+ local story_word="stories"
302
+ [[ "$active_count" -eq 1 ]] && story_word="story"
303
+ error "Upgrade blocked: sprint \`${sprint_id}\` is active (${active_count} ${story_word} in progress). Complete or pause the sprint before upgrading."
304
+ return 1
305
+ }
306
+
325
307
  # ─── cmd_init ───────────────────────────────────────────────────────────────
326
308
 
327
309
  cmd_init() {
@@ -602,6 +584,15 @@ cmd_update() {
602
584
  [[ "$confirm" =~ ^[Yy] ]] || { info "Aborted."; exit 0; }
603
585
  fi
604
586
 
587
+ # Sprint Gate (E18-S1, ADR-029 §10.21.2): block upgrade if active sprint
588
+ if [[ "$OPT_SKIP_SPRINT_GATE" == true ]]; then
589
+ warn "Sprint gate bypassed via --skip-sprint-gate — proceed with caution"
590
+ else
591
+ if ! check_sprint_gate "$TARGET"; then
592
+ exit 1
593
+ fi
594
+ fi
595
+
605
596
  local timestamp
606
597
  timestamp="$(date +%Y%m%d-%H%M%S)"
607
598
  local backup_dir="$TARGET/_gaia/_backups/$timestamp"
@@ -995,12 +986,13 @@ ${BOLD}Commands:${RESET}
995
986
  status Show installation info
996
987
 
997
988
  ${BOLD}Options:${RESET}
998
- --source <path> Local GAIA source (or clones from GitHub if omitted)
999
- --branch <name> Clone from a specific branch
1000
- --yes Skip confirmation prompts
1001
- --dry-run Show what would be done without making changes
1002
- --verbose Show detailed progress
1003
- --help Show this help message
989
+ --source <path> Local GAIA source (or clones from GitHub if omitted)
990
+ --branch <name> Clone from a specific branch
991
+ --yes Skip confirmation prompts
992
+ --dry-run Show what would be done without making changes
993
+ --verbose Show detailed progress
994
+ --skip-sprint-gate Bypass the active-sprint upgrade gate (NOT RECOMMENDED)
995
+ --help Show this help message
1004
996
 
1005
997
  ${BOLD}Examples:${RESET}
1006
998
  gaia-install.sh init ~/my-new-project
@@ -1070,6 +1062,10 @@ parse_args() {
1070
1062
  OPT_VERBOSE=true
1071
1063
  shift
1072
1064
  ;;
1065
+ --skip-sprint-gate)
1066
+ OPT_SKIP_SPRINT_GATE=true
1067
+ shift
1068
+ ;;
1073
1069
  --branch)
1074
1070
  if [[ -z "${2:-}" ]]; then
1075
1071
  error "--branch requires a branch name argument"
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env bash
2
+ # ─────────────────────────────────────────────────────────────────────────────
3
+ # copy-lib.sh — Extracted copy functions for gaia-install.sh
4
+ # Origin: gaia-install.sh (E3-S11 — Extract copy_gaia_files for Unit Testability)
5
+ #
6
+ # This library is intentionally free of `set -euo pipefail`. The caller's
7
+ # shell options govern execution. When BATS sources this directly, the BATS
8
+ # process shell options apply. When gaia-install.sh sources it, the
9
+ # installer's `set -euo pipefail` applies. Function bodies are neutral.
10
+ # ─────────────────────────────────────────────────────────────────────────────
11
+
12
+ # Remove .resolved/*.yaml files from target _gaia/ directory.
13
+ # Called after cp/tar copy to replicate rsync's --exclude behavior.
14
+ # Only .resolved/*.yaml is relevant to the _gaia/ subtree; the other rsync
15
+ # --exclude patterns target _memory/ paths outside _gaia/ and never match.
16
+ clean_resolved_yaml() {
17
+ local target_gaia="$1"
18
+ find "$target_gaia" -path '*/.resolved/*.yaml' -delete 2>/dev/null || true
19
+ }
20
+
21
+ # Copy _gaia/ directory from source to target using a fallback chain:
22
+ # rsync → cp -rp → tar
23
+ # Tries each tool in order. If a tool is found but fails at runtime (e.g.,
24
+ # broken rsync stub on Windows), falls through to the next tool. Exits with
25
+ # a diagnostic error if all tools fail or none are available.
26
+ #
27
+ # Excludes .resolved/*.yaml files from the final output (rsync handles this
28
+ # natively via --exclude; cp and tar do a post-copy cleanup).
29
+ #
30
+ # Note: No symlinks currently exist in _gaia/. If symlinks are introduced
31
+ # in the future, verify that cp -rp behavior matches rsync -a on all
32
+ # target platforms (ADR-004).
33
+ copy_gaia_files() {
34
+ local src="$1" dst="$2"
35
+ local copy_done=false
36
+
37
+ # Try rsync first (preferred — handles excludes natively)
38
+ if command -v rsync >/dev/null 2>&1; then
39
+ if rsync -a \
40
+ --exclude='_memory/checkpoints/*.yaml' \
41
+ --exclude='_memory/checkpoints/completed/*.yaml' \
42
+ --exclude='.resolved/*.yaml' \
43
+ --exclude='_memory/*-sidecar/*.md' \
44
+ --exclude='_memory/*-sidecar/*.yaml' \
45
+ "$src/_gaia/" "$dst/_gaia/" 2>/dev/null; then
46
+ detail "Copied framework files using rsync"
47
+ copy_done=true
48
+ else
49
+ detail "rsync found but failed — trying fallback methods"
50
+ fi
51
+ fi
52
+
53
+ # Fallback: cp -rp (preserves permissions like rsync -a)
54
+ if [[ "$copy_done" == false ]] && command -v cp >/dev/null 2>&1; then
55
+ if cp -rp "$src/_gaia/." "$dst/_gaia/" 2>/dev/null; then
56
+ clean_resolved_yaml "$dst/_gaia"
57
+ detail "Copied framework files using cp -rp (rsync unavailable)"
58
+ copy_done=true
59
+ else
60
+ error "cp failed to copy framework files — check permissions and disk space"
61
+ exit 1
62
+ fi
63
+ fi
64
+
65
+ # Fallback: tar (last resort — available on virtually all POSIX systems)
66
+ if [[ "$copy_done" == false ]] && command -v tar >/dev/null 2>&1; then
67
+ if (tar -cf - -C "$src" _gaia | tar -xf - -C "$dst") 2>/dev/null; then
68
+ clean_resolved_yaml "$dst/_gaia"
69
+ detail "Copied framework files using tar (rsync and cp unavailable)"
70
+ copy_done=true
71
+ else
72
+ error "tar failed to copy framework files — check permissions and disk space"
73
+ exit 1
74
+ fi
75
+ fi
76
+
77
+ if [[ "$copy_done" == false ]]; then
78
+ error "No suitable copy tool found (tried rsync, cp, tar). Cannot copy framework files."
79
+ exit 1
80
+ fi
81
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gaia-framework",
3
- "version": "1.87.0",
3
+ "version": "1.105.0",
4
4
  "description": "GAIA — Generative Agile Intelligence Architecture installer",
5
5
  "bin": {
6
6
  "gaia-framework": "./bin/gaia-framework.js"
@@ -42,6 +42,7 @@
42
42
  },
43
43
  "files": [
44
44
  "bin/",
45
+ "lib/",
45
46
  "gaia-install.sh",
46
47
  "_gaia/",
47
48
  ".claude/",