gaia-framework 1.105.1 → 1.127.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-bridge-disable.md +18 -0
- package/.claude/commands/gaia-bridge-enable.md +18 -0
- package/.claude/commands/gaia-fill-test-gaps.md +17 -0
- package/CLAUDE.md +64 -1
- package/_gaia/_config/gaia-help.csv +2 -0
- package/_gaia/_config/global.yaml +14 -1
- package/_gaia/_config/lifecycle-sequence.yaml +23 -3
- package/_gaia/_config/skill-manifest.csv +1 -0
- package/_gaia/_config/workflow-manifest.csv +2 -0
- package/_gaia/core/agents/orchestrator.md +1 -1
- package/_gaia/core/protocols/review-gate-check.xml +45 -5
- package/_gaia/core/validators/test-environment-validator.js +191 -0
- package/_gaia/core/workflows/bridge-toggle/checklist.md +11 -0
- package/_gaia/core/workflows/bridge-toggle/instructions.xml +69 -0
- package/_gaia/core/workflows/bridge-toggle/workflow.yaml +27 -0
- package/_gaia/dev/skills/_skill-index.yaml +13 -0
- package/_gaia/dev/skills/code-review-standards.md +50 -0
- package/_gaia/dev/skills/edge-cases.md +201 -0
- package/_gaia/lifecycle/knowledge/brownfield/ci-test-detection.md +194 -0
- package/_gaia/lifecycle/knowledge/brownfield/test-execution-scan.md +13 -0
- package/_gaia/lifecycle/skills/document-rulesets.md +93 -3
- package/_gaia/lifecycle/templates/story-template.md +7 -7
- package/_gaia/lifecycle/templates/test-gap-analysis-template.md +221 -0
- package/_gaia/lifecycle/workflows/4-implementation/check-review-gate/checklist.md +1 -1
- package/_gaia/lifecycle/workflows/4-implementation/check-review-gate/instructions.xml +11 -11
- package/_gaia/lifecycle/workflows/4-implementation/code-review/instructions.xml +1 -1
- package/_gaia/lifecycle/workflows/4-implementation/create-story/instructions.xml +73 -2
- package/_gaia/lifecycle/workflows/4-implementation/dev-story/instructions.xml +25 -2
- package/_gaia/lifecycle/workflows/4-implementation/retrospective/instructions.xml +1 -1
- package/_gaia/lifecycle/workflows/4-implementation/run-all-reviews/instructions.xml +132 -9
- package/_gaia/lifecycle/workflows/4-implementation/security-review/checklist.md +2 -0
- package/_gaia/lifecycle/workflows/4-implementation/sprint-planning/instructions.xml +13 -0
- package/_gaia/lifecycle/workflows/4-implementation/sprint-planning/workflow.yaml +8 -0
- package/_gaia/lifecycle/workflows/4-implementation/validate-story/checklist.md +1 -0
- package/_gaia/lifecycle/workflows/4-implementation/validate-story/instructions.xml +11 -0
- package/_gaia/lifecycle/workflows/5-deployment/deployment-checklist/instructions.xml +11 -0
- package/_gaia/lifecycle/workflows/anytime/brownfield-onboarding/instructions.xml +48 -1
- package/_gaia/lifecycle/workflows/anytime/brownfield-onboarding/workflow.yaml +10 -0
- package/_gaia/testing/agents/test-architect.md +2 -0
- package/_gaia/testing/workflows/fill-test-gaps/checklist.md +16 -0
- package/_gaia/testing/workflows/fill-test-gaps/instructions.xml +128 -0
- package/_gaia/testing/workflows/fill-test-gaps/workflow.yaml +30 -0
- package/_gaia/testing/workflows/test-gap-analysis/instructions.xml +47 -14
- package/_gaia/testing/workflows/test-gap-analysis/workflow.yaml +1 -0
- package/gaia-install.sh +37 -0
- package/package.json +3 -3
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 'bridge-disable'
|
|
3
|
+
description: 'Disable the Test Execution Bridge in global.yaml.'
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
IT IS CRITICAL THAT YOU FOLLOW THESE STEPS:
|
|
8
|
+
|
|
9
|
+
<steps CRITICAL="TRUE">
|
|
10
|
+
1. LOAD the FULL {project-root}/_gaia/core/engine/workflow.xml
|
|
11
|
+
2. READ its entire contents — this is the CORE OS
|
|
12
|
+
3. Pass {project-root}/_gaia/core/workflows/bridge-toggle/workflow.yaml as 'workflow-config'
|
|
13
|
+
4. Set parameter: --mode disable
|
|
14
|
+
5. Follow workflow.xml instructions EXACTLY
|
|
15
|
+
6. Save outputs after EACH section
|
|
16
|
+
</steps>
|
|
17
|
+
|
|
18
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 'bridge-enable'
|
|
3
|
+
description: 'Enable the Test Execution Bridge in global.yaml.'
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
IT IS CRITICAL THAT YOU FOLLOW THESE STEPS:
|
|
8
|
+
|
|
9
|
+
<steps CRITICAL="TRUE">
|
|
10
|
+
1. LOAD the FULL {project-root}/_gaia/core/engine/workflow.xml
|
|
11
|
+
2. READ its entire contents — this is the CORE OS
|
|
12
|
+
3. Pass {project-root}/_gaia/core/workflows/bridge-toggle/workflow.yaml as 'workflow-config'
|
|
13
|
+
4. Set parameter: --mode enable
|
|
14
|
+
5. Follow workflow.xml instructions EXACTLY
|
|
15
|
+
6. Save outputs after EACH section
|
|
16
|
+
</steps>
|
|
17
|
+
|
|
18
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 'fill-test-gaps'
|
|
3
|
+
description: 'Read gap report, triage by severity and story, propose remediation actions. Use when "fill test gaps".'
|
|
4
|
+
model: opus
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
IT IS CRITICAL THAT YOU FOLLOW THESE STEPS:
|
|
8
|
+
|
|
9
|
+
<steps CRITICAL="TRUE">
|
|
10
|
+
1. LOAD the FULL {project-root}/_gaia/core/engine/workflow.xml
|
|
11
|
+
2. READ its entire contents — this is the CORE OS
|
|
12
|
+
3. Pass {project-root}/_gaia/testing/workflows/fill-test-gaps/workflow.yaml as 'workflow-config'
|
|
13
|
+
4. Follow workflow.xml instructions EXACTLY
|
|
14
|
+
5. Save outputs after EACH section
|
|
15
|
+
</steps>
|
|
16
|
+
|
|
17
|
+
$ARGUMENTS
|
package/CLAUDE.md
CHANGED
|
@@ -140,17 +140,34 @@ backlog → validating → ready-for-dev → in-progress → invalid → review
|
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
**Review Gate:** A story in `review` requires ALL six reviews to pass before moving to `done`:
|
|
143
|
-
- `/gaia-code-review` —
|
|
143
|
+
- `/gaia-code-review` — PASSED or FAILED
|
|
144
144
|
- `/gaia-qa-tests` — PASSED or FAILED
|
|
145
145
|
- `/gaia-security-review` — PASSED or FAILED
|
|
146
146
|
- `/gaia-test-automate` — PASSED or FAILED
|
|
147
147
|
- `/gaia-test-review` — PASSED or FAILED
|
|
148
148
|
- `/gaia-review-perf` — PASSED or FAILED
|
|
149
149
|
|
|
150
|
+
**Gate status vocabulary** (canonical, enforced by `/gaia-validate-story`): `UNVERIFIED` (default, not yet run) | `PASSED` (review passed) | `FAILED` (review failed). No other values are permitted in the Review Gate table. Code Review uses `APPROVE`/`REQUEST_CHANGES` as its internal verdict keyword in the report body, but writes `PASSED`/`FAILED` to the Review Gate row.
|
|
151
|
+
|
|
150
152
|
Run `/gaia-run-all-reviews` to execute all six reviews sequentially via subagents — one command instead of six.
|
|
151
153
|
|
|
152
154
|
If any review fails, the story returns to `in-progress`. The Review Gate table in the story file tracks progress.
|
|
153
155
|
|
|
156
|
+
### Review Gate-to-Tier Mapping (E17-S12, FR-195)
|
|
157
|
+
|
|
158
|
+
When the Test Execution Bridge (ADR-028) is enabled, each review gate is linked to a set of test tiers (from the E17-S11 three-tier model) whose evidence is required to produce a PASSED verdict. The canonical mapping lives in `Gaia-framework/src/bridge/review-gate-tier-mapping.js` (`DEFAULT_GATE_TIER_MAPPING`) and can be overridden per-project via the `tiers.gate_mapping` block in `test-environment.yaml`.
|
|
159
|
+
|
|
160
|
+
| Review Gate | Required Tiers |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `/gaia-qa-tests` | Tier 1 + Tier 2 (unit + integration) |
|
|
163
|
+
| `/gaia-test-automate` | Tier 1 (unit) |
|
|
164
|
+
| `/gaia-test-review` | Tier 2 (integration) |
|
|
165
|
+
| `/gaia-review-perf` | Tier 3 (e2e) |
|
|
166
|
+
| `/gaia-security-review` | Tier 2 + Tier 3 (integration + e2e) |
|
|
167
|
+
| `/gaia-code-review` | no tier (static analysis only) |
|
|
168
|
+
|
|
169
|
+
When a gate is UNVERIFIED, the Nudge Block surfaces the required tiers (e.g., "run Tier 1 + Tier 2 tests") via `formatNudgeSuggestion(gate, mapping)`. Full rationale and override semantics live in architecture §10.20.4.
|
|
170
|
+
|
|
154
171
|
### Infra Review Gate Substitutions
|
|
155
172
|
|
|
156
173
|
For infrastructure stories (those whose `traces_to` field contains `IR-###`, `OR-###`, or `SR-###` requirement IDs), 4 of the 6 review gates use adapted criteria. Code Review and Security Review remain unchanged for all story types.
|
|
@@ -166,6 +183,52 @@ For infrastructure stories (those whose `traces_to` field contains `IR-###`, `OR
|
|
|
166
183
|
|
|
167
184
|
**Detection mechanism:** The `review-gate-check` protocol reads the story's `traces_to` field and checks the requirement ID prefix. Each story is evaluated independently — platform projects with mixed stories get per-story gate selection based on their own requirement prefix.
|
|
168
185
|
|
|
186
|
+
## Bridge Scope
|
|
187
|
+
|
|
188
|
+
The Test Execution Bridge (ADR-028, architecture §10.20) orchestrates test runs ONLY. The bridge does not deploy services, does not modify databases, and does not alter any infrastructure. This is a hard scope constraint enforced in code (FR-203) and must be preserved in every future change.
|
|
189
|
+
|
|
190
|
+
**Supported stacks (built-in adapters, architecture §10.20.11):**
|
|
191
|
+
|
|
192
|
+
The bridge ships with five static-import stack adapters, selected automatically by `getAdapter()` in `Gaia-framework/src/bridge/adapters/index.js`. Priority order is deterministic: `javascript → python → java → go → flutter`.
|
|
193
|
+
|
|
194
|
+
| Stack | Representative runner command | Detection pattern |
|
|
195
|
+
|---|---|---|
|
|
196
|
+
| JavaScript / TypeScript | `npx vitest run` (also `npm test`, Jest, Mocha, TAP) | `package.json` |
|
|
197
|
+
| Python | `pytest` | `pyproject.toml` / `pytest.ini` / `setup.cfg` / `setup.py` |
|
|
198
|
+
| Java | `mvn test` (also `gradle test`) | `pom.xml` / `build.gradle` |
|
|
199
|
+
| Go | `go test ./...` | `go.mod` |
|
|
200
|
+
| Flutter / Dart | `flutter test` | `pubspec.yaml` |
|
|
201
|
+
|
|
202
|
+
Adding a new stack adapter is documented in `docs/architecture/bridge-adapter-contract.md`. External / dynamic adapter loading is explicitly out of scope (architecture §10.20.11.4, threat T37).
|
|
203
|
+
|
|
204
|
+
**The bridge DOES:**
|
|
205
|
+
- Invoke project-owned test runners via standard CLI commands — one adapter per stack, one representative runner shown per row above
|
|
206
|
+
- Trigger a single CI workflow declared in `test-environment.yaml` via `gh workflow run`
|
|
207
|
+
- Poll the CI run until terminal state and fetch the run log
|
|
208
|
+
- Parse runner/CI output into the `test-results/{story_key}-execution.json` evidence schema
|
|
209
|
+
- Reject commands containing shell chaining operators (`;`, `&&`, `||`, `|`, `>`, `<`) outside of quoted arguments
|
|
210
|
+
- Reject any command not explicitly allowlisted from `test-environment.yaml` runners or the `package.json` test script
|
|
211
|
+
|
|
212
|
+
**The bridge DOES NOT:**
|
|
213
|
+
- Deploy services, applications, or container images
|
|
214
|
+
- Provision, modify, or tear down infrastructure (no `terraform apply`, no `kubectl apply`, no `docker run -d`)
|
|
215
|
+
- Alter databases (no migrations, no seed scripts, no schema changes)
|
|
216
|
+
- Commit code, push branches, or mutate the git repository
|
|
217
|
+
- Execute arbitrary shell commands or shell substitution (`` ` `` and `$()` are always rejected)
|
|
218
|
+
- Trigger any GitHub Actions workflow other than the `ci_workflow` declared in `test-environment.yaml`
|
|
219
|
+
|
|
220
|
+
**Enforcement points:**
|
|
221
|
+
- `Gaia-framework/src/bridge/bridge-scope-guard.js` — shared scope guard module exporting `assertInScope`, `assertCommandAllowed`, `assertCiWorkflowAllowed`
|
|
222
|
+
- Layer 2 local execution (`layer-2-local-execution.js`) calls all three guards before `spawn`
|
|
223
|
+
- Layer 2 CI execution (`layer-2-ci-execution.js`) calls the shell-operator guard on the runner command and the CI workflow allowlist guard before `gh workflow run`
|
|
224
|
+
|
|
225
|
+
**Threat model:** Architecture §10.20.10 enumerates the five bridge threats:
|
|
226
|
+
- **T20** — Environment misconfiguration (runner declared in `test-environment.yaml` does not match project stack). Mitigated by Layer 0 readiness checks and `assertCommandAllowed`.
|
|
227
|
+
- **T21** — Runner discovery failure (Layer 1 cannot match story key to test files). Mitigated by structured Layer 1 failure + `bridge_status: runner_not_found` evidence fallback.
|
|
228
|
+
- **T22** — Execution timeout (subprocess or CI workflow hangs). Mitigated by NFR-033 configurable timeout + SIGTERM/SIGKILL escalation.
|
|
229
|
+
- **T23** — Subprocess runaway via shell injection (chaining/substitution/redirection operators). Mitigated by `assertInScope` scope guard.
|
|
230
|
+
- **T24** — CI API unavailability (`gh` missing, auth expired, network failure). Mitigated by `defaultGhCheck` probe and local fallback + `assertCiWorkflowAllowed` on the fallback workflow.
|
|
231
|
+
|
|
169
232
|
## Memory Hygiene
|
|
170
233
|
|
|
171
234
|
Agent memory sidecars accumulate decisions across sessions. Run `/gaia-memory-hygiene` periodically (recommended before each sprint) to detect stale, contradicted, or orphaned entries by cross-referencing sidecar decisions against current planning and architecture artifacts.
|
|
@@ -51,6 +51,8 @@ module,phase,name,code,command,required,agent-name,description,output-location
|
|
|
51
51
|
"testing","anytime","test-review","test-review","gaia-test-review","false","test-architect","Review test quality","docs/test-artifacts"
|
|
52
52
|
"testing","anytime","nfr-assessment","nfr","gaia-nfr","false","test-architect","Assess non-functional requirements","docs/test-artifacts"
|
|
53
53
|
"testing","anytime","traceability","trace","gaia-trace","false","test-architect","Generate traceability matrix","docs/test-artifacts"
|
|
54
|
+
"testing","anytime","test-gap-analysis","test-gap-analysis","gaia-test-gap-analysis","false","test-architect","Scan test suite against requirements to identify coverage gaps","docs/test-artifacts"
|
|
55
|
+
"testing","4-implementation","fill-test-gaps","fill-test-gaps","gaia-fill-test-gaps","false","test-architect","End-to-end remediation for test-gap-analysis findings (sub-workflow composition)","docs/test-artifacts"
|
|
54
56
|
"lifecycle","3-solutioning","security-threat-model","threat-model","gaia-threat-model","false","security","Create STRIDE/DREAD threat model","docs/planning-artifacts"
|
|
55
57
|
"lifecycle","4-implementation","security-review","security-review","gaia-security-review","false","security","Pre-merge OWASP security review","docs/implementation-artifacts"
|
|
56
58
|
"lifecycle","3-solutioning","infrastructure-design","infra-design","gaia-infra-design","false","devops","Design deployment topology and IaC","docs/planning-artifacts"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# After modifying this file, run /gaia-build-configs to regenerate resolved configs.
|
|
4
4
|
|
|
5
5
|
framework_name: "GAIA"
|
|
6
|
-
framework_version: "1.
|
|
6
|
+
framework_version: "1.127.2"
|
|
7
7
|
|
|
8
8
|
# User settings
|
|
9
9
|
user_name: "jlouage"
|
|
@@ -48,3 +48,16 @@ installed_path: "{project-root}/_gaia"
|
|
|
48
48
|
config_path: "{project-root}/_gaia/_config"
|
|
49
49
|
memory_path: "{project-root}/_memory"
|
|
50
50
|
checkpoint_path: "{project-root}/_memory/checkpoints"
|
|
51
|
+
|
|
52
|
+
# Test Execution Bridge (ADR-028, FR-202, NFR-035)
|
|
53
|
+
# Opt-in subsystem that runs tests during the post-review phase of applicable workflows.
|
|
54
|
+
# When bridge_enabled is false (the default), ALL bridge layers are completely bypassed
|
|
55
|
+
# with zero behavior change — no log messages, no file reads. This is the safety toggle
|
|
56
|
+
# for the entire bridge subsystem. Existing installations are unaffected by default.
|
|
57
|
+
test_execution_bridge:
|
|
58
|
+
# Master switch. false = bridge completely inactive (default, opt-in semantics).
|
|
59
|
+
# Set to true to activate the bridge in applicable workflows.
|
|
60
|
+
bridge_enabled: false
|
|
61
|
+
# Maximum wall-clock seconds the bridge will wait for a test run before aborting.
|
|
62
|
+
# Only consulted when bridge_enabled is true.
|
|
63
|
+
timeout_seconds: 300
|
|
@@ -399,6 +399,13 @@ sequence:
|
|
|
399
399
|
standalone: true
|
|
400
400
|
note: "Return to current lifecycle phase"
|
|
401
401
|
|
|
402
|
+
bridge-toggle:
|
|
403
|
+
module: core
|
|
404
|
+
command: /gaia-bridge-enable
|
|
405
|
+
next:
|
|
406
|
+
standalone: true
|
|
407
|
+
note: "Run /gaia-build-configs to regenerate resolved configs after toggling"
|
|
408
|
+
|
|
402
409
|
party-mode:
|
|
403
410
|
module: core
|
|
404
411
|
command: /gaia-party
|
|
@@ -573,10 +580,23 @@ sequence:
|
|
|
573
580
|
next:
|
|
574
581
|
standalone: true
|
|
575
582
|
suggestions:
|
|
583
|
+
- command: /gaia-sprint-plan
|
|
584
|
+
context: "To schedule remediation stories discovered by the gap analysis"
|
|
585
|
+
- command: /gaia-trace
|
|
586
|
+
context: "To update traceability matrix after closing coverage gaps"
|
|
576
587
|
- command: /gaia-test-design
|
|
577
|
-
context: "To
|
|
578
|
-
|
|
579
|
-
|
|
588
|
+
context: "To redesign the test plan based on gap analysis findings"
|
|
589
|
+
|
|
590
|
+
fill-test-gaps:
|
|
591
|
+
module: testing
|
|
592
|
+
command: /gaia-fill-test-gaps
|
|
593
|
+
next:
|
|
594
|
+
standalone: true
|
|
595
|
+
suggestions:
|
|
596
|
+
- command: /gaia-test-gap-analysis
|
|
597
|
+
context: "To regenerate the gap analysis report before triaging"
|
|
598
|
+
- command: /gaia-sprint-plan
|
|
599
|
+
context: "To schedule remediation stories from the triage table"
|
|
580
600
|
|
|
581
601
|
traceability:
|
|
582
602
|
module: testing
|
|
@@ -14,3 +14,4 @@ name,displayName,description,path,applicable_agents
|
|
|
14
14
|
"memory-management-cross-agent","Memory Management Cross-Agent","Cross-agent memory read protocol for loading other agents' sidecar files","_gaia/lifecycle/skills/memory-management-cross-agent.md","all"
|
|
15
15
|
"document-rulesets","Document Rulesets","Artifact type detection, document-specific validation rulesets (prd, arch, ux, test-plan, epics), two-pass validation logic","_gaia/lifecycle/skills/document-rulesets.md","validator"
|
|
16
16
|
"figma-integration","Figma Integration","Design tool detection, token extraction (W3C DTCG), component specs, frame generation, asset export, per-stack resolution","_gaia/dev/skills/figma-integration.md","all-dev"
|
|
17
|
+
"edge-cases","Edge Cases","Structured edge case analysis for M+ stories — boundary, error, timing, concurrency, integration, security, data, environment categories","_gaia/dev/skills/edge-cases.md","all-dev,sm,pm,qa,test-architect"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
name,displayName,description,module,phase,path,command,agent
|
|
2
2
|
"brainstorming","Brainstorming","Facilitated brainstorming session","core","anytime","_gaia/core/workflows/brainstorming/workflow.yaml","gaia-brainstorming","orchestrator"
|
|
3
|
+
"bridge-toggle","Bridge Toggle","Enable or disable the Test Execution Bridge in global.yaml","core","anytime","_gaia/core/workflows/bridge-toggle/workflow.yaml","gaia-bridge-enable","orchestrator"
|
|
3
4
|
"party-mode","Party Mode","Multi-agent group discussion","core","anytime","_gaia/core/workflows/party-mode/workflow.yaml","gaia-party","orchestrator"
|
|
4
5
|
"advanced-elicitation","Advanced Elicitation","Deep requirements elicitation","lifecycle","1-analysis","_gaia/lifecycle/workflows/1-analysis/advanced-elicitation/workflow.yaml","gaia-advanced-elicitation","orchestrator"
|
|
5
6
|
"brainstorm-project","Brainstorm Project","Brainstorm a new project idea","lifecycle","1-analysis","_gaia/lifecycle/workflows/1-analysis/brainstorm-project/workflow.yaml","gaia-brainstorm","analyst"
|
|
@@ -47,6 +48,7 @@ name,displayName,description,module,phase,path,command,agent
|
|
|
47
48
|
"nfr-assessment","NFR Assessment","Assess non-functional requirements","testing","anytime","_gaia/testing/workflows/nfr-assessment/workflow.yaml","gaia-nfr","test-architect"
|
|
48
49
|
"traceability","Traceability","Generate traceability matrix","testing","anytime","_gaia/testing/workflows/traceability/workflow.yaml","gaia-trace","test-architect"
|
|
49
50
|
"test-gap-analysis","Test Gap Analysis","Scan test suite against requirements to identify coverage gaps","testing","anytime","_gaia/testing/workflows/test-gap-analysis/workflow.yaml","gaia-test-gap-analysis","test-architect"
|
|
51
|
+
"fill-test-gaps","Fill Test Gaps","End-to-end remediation for test-gap-analysis findings (sub-workflow composition)","testing","4-implementation","_gaia/testing/workflows/fill-test-gaps/workflow.yaml","gaia-fill-test-gaps","test-architect"
|
|
50
52
|
"security-threat-model","Security Threat Model","Create STRIDE/DREAD threat model","lifecycle","3-solutioning","_gaia/lifecycle/workflows/3-solutioning/security-threat-model/workflow.yaml","gaia-threat-model","security"
|
|
51
53
|
"security-review","Security Review","Pre-merge OWASP security review","lifecycle","4-implementation","_gaia/lifecycle/workflows/4-implementation/security-review/workflow.yaml","gaia-security-review","security"
|
|
52
54
|
"infrastructure-design","Infrastructure Design","Design deployment topology and IaC","lifecycle","3-solutioning","_gaia/lifecycle/workflows/3-solutioning/infrastructure-design/workflow.yaml","gaia-infra-design","devops"
|
|
@@ -122,7 +122,7 @@ You must fully embody this agent's persona and follow the activation protocol EX
|
|
|
122
122
|
|
|
123
123
|
{if review_count > 0:}
|
|
124
124
|
Stories still in review:
|
|
125
|
-
{for each: story key, which reviews PASSED/FAILED
|
|
125
|
+
{for each: story key, which reviews UNVERIFIED/PASSED/FAILED}
|
|
126
126
|
|
|
127
127
|
{if failed_count > 0:}
|
|
128
128
|
Failed stories:
|
|
@@ -27,9 +27,20 @@
|
|
|
27
27
|
|
|
28
28
|
<step n="1" title="Read Review Gate and Determine Gate Type">
|
|
29
29
|
<action>Read the story file's Review Gate table</action>
|
|
30
|
-
<action>If Review Gate section is missing: initialize it with EXACTLY 6 rows — Code Review (
|
|
30
|
+
<action>If Review Gate section is missing: initialize it with EXACTLY 6 rows — Code Review (UNVERIFIED), QA Tests (UNVERIFIED), Security Review (UNVERIFIED), Test Automation (UNVERIFIED), Test Review (UNVERIFIED), Performance Review (UNVERIFIED). Do NOT add any other rows.</action>
|
|
31
31
|
<action>If Review Gate table has extra rows beyond the 6 valid ones: remove the invalid rows</action>
|
|
32
|
-
<action>Parse each row: Review name, Status (
|
|
32
|
+
<action>Parse each row: Review name, Status (UNVERIFIED | PASSED | FAILED), Report link</action>
|
|
33
|
+
|
|
34
|
+
<!-- Legacy Status Normalization (E17-S2 / FR-191 / NFR-035)
|
|
35
|
+
Stories created before the UNVERIFIED/PASSED/FAILED vocabulary (E17-S1)
|
|
36
|
+
may carry legacy status values such as a literal dash ("-"), blank cells,
|
|
37
|
+
or the word "pending". These are treated as "not yet run" and MUST be
|
|
38
|
+
normalized to UNVERIFIED BEFORE gate evaluation in Step 2 so that Step 2
|
|
39
|
+
operates on canonical values only. NFR-035 requires this backward
|
|
40
|
+
compatibility — existing stories must not be broken by the vocabulary
|
|
41
|
+
change.
|
|
42
|
+
-->
|
|
43
|
+
<action>LEGACY NORMALIZATION (E17-S2 / NFR-035): Before evaluating gates, normalize every row's status by converting legacy values to the canonical vocabulary. For each of the 6 rows, if the Status cell is any of: a literal dash character "-", blank (empty cell or whitespace-only), or the word "pending" (case-insensitive), replace it with UNVERIFIED. This normalization happens in-memory during parsing — it does NOT rewrite the story file unless a subsequent review workflow persists its own update. Any other legacy value not in {"-", blank, "pending"} is left as-is and will be flagged by the PASSED/FAILED check in Step 2. The canonical mapping is: "-" → UNVERIFIED, blank → UNVERIFIED, "pending" → UNVERIFIED. After this step every row's in-memory status MUST be one of UNVERIFIED, PASSED, or FAILED.</action>
|
|
33
44
|
|
|
34
45
|
<!-- Infra Gate Detection (FR-129): per-story gate type selection based on requirement ID prefix -->
|
|
35
46
|
<action>Read the story file's YAML frontmatter traces_to field (e.g., traces_to: [IR-001, FR-128])</action>
|
|
@@ -44,14 +55,43 @@
|
|
|
44
55
|
<critical>
|
|
45
56
|
<mandate>You MUST execute the transition even if the gate was already fully passed before this run. The purpose is to ensure story status matches gate state.</mandate>
|
|
46
57
|
<mandate>Use the status-sync protocol to update story status — this ensures both story file and sprint-status.yaml stay in sync.</mandate>
|
|
58
|
+
<mandate>HARD GATE (E17-S15 / A-050): A story transitioning from 'review' to 'done' MUST have a {story_key}-review-summary.md file in {implementation_artifacts}/. This is enforced structurally — not advisory. The only exception is when the story has zero individual review reports (i.e., it never actually entered the review process).</mandate>
|
|
47
59
|
</critical>
|
|
48
60
|
<action>Check two things: (1) the Review Gate table rows, (2) the current story status</action>
|
|
49
61
|
<action>If ALL 6 rows show PASSED AND story status is 'review': read the "Definition of Done" section — verify every item is checked (- [x]). If any item is unchecked: log "BLOCKED: DoD incomplete — {unchecked items}". Do NOT transition to done.</action>
|
|
50
|
-
<action>If ALL 6 rows show PASSED AND all DoD items checked AND story status is 'review':
|
|
62
|
+
<action>REVIEW SUMMARY HARD GATE (E17-S15 / A-050 / AC1, AC2, AC3): If ALL 6 rows show PASSED AND all DoD items checked AND story status is 'review', perform the review-summary.md existence check BEFORE invoking status-sync:
|
|
63
|
+
1. Build the summary file path: {implementation_artifacts}/{story_key}-review-summary.md
|
|
64
|
+
2. Check whether the summary file exists on disk.
|
|
65
|
+
3. If the summary file EXISTS: the hard gate passes — proceed to invoke status-sync below.
|
|
66
|
+
4. If the summary file is MISSING: apply the skip-when-never-reviewed exception. Count how many of the 6 individual review reports exist on disk:
|
|
67
|
+
- {implementation_artifacts}/{story_key}-review.md (Code Review)
|
|
68
|
+
- {implementation_artifacts}/{story_key}-security-review.md (Security Review)
|
|
69
|
+
- {test_artifacts}/{story_key}-qa-tests.md (QA Tests)
|
|
70
|
+
- {test_artifacts}/{story_key}-test-automation.md (Test Automation)
|
|
71
|
+
- {test_artifacts}/{story_key}-test-review.md (Test Review)
|
|
72
|
+
- {implementation_artifacts}/{story_key}-performance-review.md (Performance Review)
|
|
73
|
+
If ALL 6 individual review reports are ALSO missing (count == 0), the story never entered review — the summary is not required for this edge case. Log "Review summary check skipped: story {story_key} has no review reports on disk (story was not actually reviewed)." and proceed to invoke status-sync below.
|
|
74
|
+
If ANY of the 6 individual review reports exist (count greater than 0) but the summary is missing, the hard gate FAILS. HALT with this exact message and do NOT invoke status-sync: "Review summary missing for {story_key}. Run `/gaia-run-all-reviews {story_key}` to generate the summary, or create it manually via `/gaia-create-review-summary {story_key}`."</action>
|
|
75
|
+
<action>If ALL 6 rows show PASSED AND all DoD items checked AND story status is 'review' AND the review-summary hard gate passed above:
|
|
51
76
|
<invoke-protocol ref="status-sync" story_key="{story_key}" new_status="done" source_workflow="review-gate-check" />
|
|
52
77
|
</action>
|
|
53
78
|
<action>If ALL 6 rows show PASSED AND the story status is already 'done': log "Story already done. No update needed."</action>
|
|
54
|
-
|
|
55
|
-
|
|
79
|
+
|
|
80
|
+
<!-- FAILED Gate Reporting (E17-S2 / FR-191 / AC3)
|
|
81
|
+
When any gate is FAILED the protocol surfaces which gates failed and
|
|
82
|
+
returns the story to in-progress so the developer can address the
|
|
83
|
+
review feedback and re-enter the review cycle.
|
|
84
|
+
-->
|
|
85
|
+
<action>FAILED GATE REPORTING (AC3): If any row has Status == FAILED, collect the list of failed gate names into a comma-separated list (e.g., "Code Review, Security Review"). Emit this exact message format: "Review gate FAILED for {story_key}. Failed gates: {list of FAILED gate names}. Story is returned to in-progress so the developer can address the review feedback." Then invoke the status-sync protocol to transition the story from 'review' to 'in-progress' — the story MUST be returned to in-progress when any gate is FAILED:
|
|
86
|
+
<invoke-protocol ref="status-sync" story_key="{story_key}" new_status="in-progress" source_workflow="review-gate-check" />
|
|
87
|
+
</action>
|
|
88
|
+
|
|
89
|
+
<!-- UNVERIFIED Gate Reporting (E17-S2 / FR-191 / AC4)
|
|
90
|
+
When any gate is UNVERIFIED the protocol reports the count and the
|
|
91
|
+
specific gate names of those not yet run. It blocks advancement to
|
|
92
|
+
done without changing the story status — the story stays in 'review'
|
|
93
|
+
until the outstanding reviews are executed.
|
|
94
|
+
-->
|
|
95
|
+
<action>UNVERIFIED GATE REPORTING (AC4): If no row is FAILED but any row has Status == UNVERIFIED, count the UNVERIFIED rows (N) and collect the list of gate names of the UNVERIFIED rows. Emit this exact message format: "{N} gates not yet run for {story_key}. Outstanding gate names: {list of UNVERIFIED gate names}. Run the corresponding review workflows (/gaia-code-review, /gaia-qa-tests, /gaia-security-review, /gaia-test-automate, /gaia-test-review, /gaia-review-perf) or /gaia-run-all-reviews to complete them." The count N and the names MUST both appear in the emitted message. This blocks advancement to done — do NOT change the story status; the story remains in 'review' until all gates show PASSED.</action>
|
|
56
96
|
</step>
|
|
57
97
|
</protocol>
|
|
@@ -194,6 +194,182 @@ function validateRunnerEntry(runner, index) {
|
|
|
194
194
|
return warnings;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// ─── E25-S6: tiers.stack_hints validation ──────────────────────
|
|
198
|
+
//
|
|
199
|
+
// The generic parseSimpleYaml above only supports 2-level maps, so the
|
|
200
|
+
// deeply-nested `tiers.stack_hints.{pytest_markers,gradle_tasks,go_build_tags,
|
|
201
|
+
// flutter_suites}` block is scanned directly from the raw YAML text. This keeps
|
|
202
|
+
// the existing parser untouched and avoids introducing a new YAML dependency
|
|
203
|
+
// (same approach used elsewhere in the bridge adapters — see ADR-038 §10.20.11).
|
|
204
|
+
//
|
|
205
|
+
// Contract: FR-312, ADR-038 §10.20.11 (stack adapter registry).
|
|
206
|
+
// See docs/test-artifacts/test-environment.yaml.example for canonical usage.
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Allowed keys inside `tiers.stack_hints`. Any other key is a validation error
|
|
210
|
+
* naming the unknown key and the accepted keys (AC6).
|
|
211
|
+
*/
|
|
212
|
+
const STACK_HINT_KEYS = Object.freeze([
|
|
213
|
+
"pytest_markers",
|
|
214
|
+
"gradle_tasks",
|
|
215
|
+
"go_build_tags",
|
|
216
|
+
"flutter_suites",
|
|
217
|
+
]);
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Extract the `tiers.stack_hints` block from raw YAML text using a
|
|
221
|
+
* line-oriented indent scan. Returns an object describing the block and any
|
|
222
|
+
* shape violations — does not throw. When the block is absent, returns null.
|
|
223
|
+
*
|
|
224
|
+
* Supported shapes (partial blocks are valid — unset tiers fall back to the
|
|
225
|
+
* adapter default, per Dev Notes):
|
|
226
|
+
* tiers:
|
|
227
|
+
* stack_hints:
|
|
228
|
+
* pytest_markers: ["slow", "integration"]
|
|
229
|
+
* gradle_tasks:
|
|
230
|
+
* unit: test
|
|
231
|
+
* integration: integrationTest
|
|
232
|
+
* e2e: e2eTest
|
|
233
|
+
* go_build_tags: [integration, e2e]
|
|
234
|
+
* flutter_suites:
|
|
235
|
+
* unit: test/
|
|
236
|
+
* integration: integration_test/
|
|
237
|
+
* e2e: integration_test/e2e/
|
|
238
|
+
*
|
|
239
|
+
* @param {string} text
|
|
240
|
+
* @returns {{ raw: object, warnings: string[] }|null}
|
|
241
|
+
*/
|
|
242
|
+
function extractStackHints(text) {
|
|
243
|
+
const lines = text.split(/\r?\n/);
|
|
244
|
+
|
|
245
|
+
// Locate `tiers:` at column 0.
|
|
246
|
+
let tiersIdx = -1;
|
|
247
|
+
for (let i = 0; i < lines.length; i++) {
|
|
248
|
+
if (/^tiers\s*:\s*(#.*)?$/.test(lines[i])) {
|
|
249
|
+
tiersIdx = i;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (tiersIdx === -1) return null;
|
|
254
|
+
|
|
255
|
+
// Find `stack_hints:` nested under `tiers:` (indent >= 2, < indent of next
|
|
256
|
+
// top-level key). We just look line-by-line for a `^(\s+)stack_hints\s*:`
|
|
257
|
+
// whose indent is > 0 and occurs before any column-0 key after `tiers:`.
|
|
258
|
+
let hintsIdx = -1;
|
|
259
|
+
let hintsIndent = -1;
|
|
260
|
+
for (let i = tiersIdx + 1; i < lines.length; i++) {
|
|
261
|
+
const l = lines[i];
|
|
262
|
+
if (l.trim() === "" || l.trimStart().startsWith("#")) continue;
|
|
263
|
+
const indent = l.length - l.trimStart().length;
|
|
264
|
+
if (indent === 0) break; // left the tiers: subtree
|
|
265
|
+
if (/^\s+stack_hints\s*:\s*(#.*)?$/.test(l)) {
|
|
266
|
+
hintsIdx = i;
|
|
267
|
+
hintsIndent = indent;
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (hintsIdx === -1) return null;
|
|
272
|
+
|
|
273
|
+
// Walk child lines whose indent is > hintsIndent. Stop when indent <= hintsIndent.
|
|
274
|
+
const warnings = [];
|
|
275
|
+
const block = {};
|
|
276
|
+
let currentKey = null;
|
|
277
|
+
let currentKeyIndent = -1;
|
|
278
|
+
let currentSubMap = null;
|
|
279
|
+
|
|
280
|
+
const recordUnknown = (key) => {
|
|
281
|
+
warnings.push(
|
|
282
|
+
`Unknown key 'tiers.stack_hints.${key}'. Accepted keys: ${STACK_HINT_KEYS.join(", ")}.`
|
|
283
|
+
);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
for (let i = hintsIdx + 1; i < lines.length; i++) {
|
|
287
|
+
const rawLine = lines[i];
|
|
288
|
+
const stripped = rawLine.replace(/#.*$/, "").trimEnd();
|
|
289
|
+
if (stripped.trim() === "") continue;
|
|
290
|
+
const indent = stripped.length - stripped.trimStart().length;
|
|
291
|
+
if (indent <= hintsIndent) break; // left stack_hints subtree
|
|
292
|
+
|
|
293
|
+
const trimmed = stripped.trim();
|
|
294
|
+
|
|
295
|
+
// Top-level stack_hints key (first indent level beneath stack_hints:).
|
|
296
|
+
// Track the first child indent we see — any line at that indent is a key.
|
|
297
|
+
if (currentKeyIndent === -1 || indent === currentKeyIndent) {
|
|
298
|
+
currentKeyIndent = indent;
|
|
299
|
+
const colonIdx = trimmed.indexOf(":");
|
|
300
|
+
if (colonIdx === -1) continue;
|
|
301
|
+
const key = trimmed.substring(0, colonIdx).trim();
|
|
302
|
+
const val = trimmed.substring(colonIdx + 1).trim();
|
|
303
|
+
|
|
304
|
+
if (!STACK_HINT_KEYS.includes(key)) {
|
|
305
|
+
recordUnknown(key);
|
|
306
|
+
currentKey = null;
|
|
307
|
+
currentSubMap = null;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
currentKey = key;
|
|
312
|
+
if (val === "") {
|
|
313
|
+
// Expect a sub-map on following lines (e.g., gradle_tasks: / flutter_suites:)
|
|
314
|
+
currentSubMap = {};
|
|
315
|
+
block[key] = currentSubMap;
|
|
316
|
+
} else if (val.startsWith("[") && val.endsWith("]")) {
|
|
317
|
+
// Flow sequence: pytest_markers: [a, b]
|
|
318
|
+
const items = val
|
|
319
|
+
.slice(1, -1)
|
|
320
|
+
.split(",")
|
|
321
|
+
.map((s) => s.trim().replace(/^['"]|['"]$/g, ""))
|
|
322
|
+
.filter((s) => s !== "");
|
|
323
|
+
// Validate shape: string[] only
|
|
324
|
+
const invalid = items.find((x) => typeof x !== "string");
|
|
325
|
+
if (invalid !== undefined) {
|
|
326
|
+
warnings.push(
|
|
327
|
+
`Invalid shape for 'tiers.stack_hints.${key}': expected array of strings.`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
block[key] = items;
|
|
331
|
+
currentSubMap = null;
|
|
332
|
+
} else {
|
|
333
|
+
// Scalar value where an array or map was expected — shape error.
|
|
334
|
+
warnings.push(
|
|
335
|
+
`Invalid shape for 'tiers.stack_hints.${key}': expected ${
|
|
336
|
+
key === "pytest_markers" || key === "go_build_tags"
|
|
337
|
+
? "array of strings"
|
|
338
|
+
: "map of { unit, integration, e2e }"
|
|
339
|
+
}, got scalar.`
|
|
340
|
+
);
|
|
341
|
+
block[key] = parseScalar(val);
|
|
342
|
+
currentSubMap = null;
|
|
343
|
+
}
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Nested sub-map entry (gradle_tasks / flutter_suites children).
|
|
348
|
+
if (indent > currentKeyIndent && currentKey && currentSubMap) {
|
|
349
|
+
const colonIdx = trimmed.indexOf(":");
|
|
350
|
+
if (colonIdx === -1) continue;
|
|
351
|
+
const k = trimmed.substring(0, colonIdx).trim();
|
|
352
|
+
const v = trimmed.substring(colonIdx + 1).trim();
|
|
353
|
+
// Only unit / integration / e2e are meaningful for tier maps, but we
|
|
354
|
+
// record whatever keys appear — downstream adapters pick the ones they need.
|
|
355
|
+
if (v === "") continue;
|
|
356
|
+
const parsed = parseScalar(v);
|
|
357
|
+
// For gradle_tasks / flutter_suites, values must be strings.
|
|
358
|
+
if (
|
|
359
|
+
(currentKey === "gradle_tasks" || currentKey === "flutter_suites") &&
|
|
360
|
+
typeof parsed !== "string"
|
|
361
|
+
) {
|
|
362
|
+
warnings.push(
|
|
363
|
+
`Invalid shape for 'tiers.stack_hints.${currentKey}.${k}': expected string, got ${typeof parsed}.`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
currentSubMap[k] = parsed;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return { raw: block, warnings };
|
|
371
|
+
}
|
|
372
|
+
|
|
197
373
|
// ─── Public API ─────────────────────────────────────────────────
|
|
198
374
|
|
|
199
375
|
/**
|
|
@@ -285,8 +461,23 @@ export function validateTestEnvironment(content, options = {}) {
|
|
|
285
461
|
}
|
|
286
462
|
}
|
|
287
463
|
|
|
464
|
+
// E25-S6 / FR-312 / ADR-038 §10.20.11: validate `tiers.stack_hints` block.
|
|
465
|
+
// The generic parseSimpleYaml above only supports 2-level maps, so the
|
|
466
|
+
// nested stack_hints block is scanned directly from the raw text.
|
|
467
|
+
const stackHints = extractStackHints(content);
|
|
468
|
+
if (stackHints && stackHints.warnings.length > 0) {
|
|
469
|
+
warnings.push(...stackHints.warnings);
|
|
470
|
+
}
|
|
471
|
+
|
|
288
472
|
return {
|
|
289
473
|
valid: warnings.length === 0,
|
|
290
474
|
warnings,
|
|
475
|
+
// Expose the parsed block for adapter consumers (AC3 wiring). Null when
|
|
476
|
+
// the block is absent — callers must fall back to adapter defaults.
|
|
477
|
+
stackHints: stackHints ? stackHints.raw : null,
|
|
291
478
|
};
|
|
292
479
|
}
|
|
480
|
+
|
|
481
|
+
// E25-S6: exported for unit tests and downstream consumers that need direct
|
|
482
|
+
// access to the scanner without running the full validator.
|
|
483
|
+
export { extractStackHints, STACK_HINT_KEYS };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Bridge Toggle — Post-Complete Checklist
|
|
2
|
+
|
|
3
|
+
## Validation Items
|
|
4
|
+
|
|
5
|
+
- [ ] `bridge_enabled` flag in global.yaml is in the target state (true for enable, false for disable)
|
|
6
|
+
- [ ] All YAML comments in global.yaml are preserved after the write
|
|
7
|
+
- [ ] No other keys in global.yaml were modified (only `bridge_enabled` value changed)
|
|
8
|
+
- [ ] Idempotent behavior verified: invoking the same mode twice produces no write on the second invocation
|
|
9
|
+
- [ ] Post-toggle summary was displayed with previous state, new state, and next-step suggestion
|
|
10
|
+
- [ ] Summary includes reminder to run `/gaia-build-configs`
|
|
11
|
+
- [ ] For disable mode: post-flip checks section was skipped entirely
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<workflow name="bridge-toggle">
|
|
2
|
+
<critical>
|
|
3
|
+
<mandate>This workflow modifies global.yaml — preserve ALL comments, key ordering, and formatting.</mandate>
|
|
4
|
+
<mandate>Use regex-based in-place edit targeting ONLY the bridge_enabled line — never regenerate the full file.</mandate>
|
|
5
|
+
<mandate>Idempotent: if the flag is already in the target state, do NOT write the file.</mandate>
|
|
6
|
+
</critical>
|
|
7
|
+
|
|
8
|
+
<step n="1" title="Read Current Bridge State">
|
|
9
|
+
<action>Read {project-root}/_gaia/_config/global.yaml</action>
|
|
10
|
+
<action>Extract test_execution_bridge.bridge_enabled value</action>
|
|
11
|
+
<action>If the test_execution_bridge section is missing: treat bridge_enabled as false (AC3)</action>
|
|
12
|
+
<action>If the section exists but bridge_enabled key is missing: treat as false (AC3)</action>
|
|
13
|
+
<action>Capture the raw file bytes for idempotency verification</action>
|
|
14
|
+
<action>Report: "Current bridge state: {state}"</action>
|
|
15
|
+
</step>
|
|
16
|
+
|
|
17
|
+
<step n="2" title="Idempotency Check">
|
|
18
|
+
<action>Compare current state against target mode (enable → true, disable → false)</action>
|
|
19
|
+
<check if="current_state == target_state">
|
|
20
|
+
Report "Bridge already {enabled|disabled}" and exit with status ok.
|
|
21
|
+
Do NOT write global.yaml. A byte-level diff must show zero changes.
|
|
22
|
+
</check>
|
|
23
|
+
</step>
|
|
24
|
+
|
|
25
|
+
<step n="3" title="Write Updated State">
|
|
26
|
+
<action>Use regex-based in-place edit to update ONLY the bridge_enabled: line within the test_execution_bridge: section</action>
|
|
27
|
+
<action>Regex pattern: /^(\s+bridge_enabled:\s*)(true|false)/m — replace capture group 2 with target value</action>
|
|
28
|
+
<action>This preserves inline comments on the same line and all surrounding YAML content</action>
|
|
29
|
+
<action>If the test_execution_bridge section is missing: emit error "test_execution_bridge section not found in global.yaml — cannot toggle. Add the section first (see ADR-028 §10.20.7)."</action>
|
|
30
|
+
<action>Write the updated content back to global.yaml</action>
|
|
31
|
+
</step>
|
|
32
|
+
|
|
33
|
+
<!-- Step 4: Post-Flip Checks (Enable Mode Only) — E17-S22
|
|
34
|
+
Delivered by E17-S22. After the flag flip in Step 3, detect and validate
|
|
35
|
+
docs/test-artifacts/test-environment.yaml and produce a structured
|
|
36
|
+
`post_flip_result` object for Step 5's summary composer. This step is
|
|
37
|
+
skipped on disable mode (AC7) and when Step 3 was an idempotent no-op
|
|
38
|
+
(Test Scenario #6 — no state transition means no post-flip checks). -->
|
|
39
|
+
<step n="4" title="Post-Flip Checks (Enable Only)">
|
|
40
|
+
<action if="mode == disable">Skip — disable mode does not perform post-flip checks (AC7). Set post_flip_result = {kind: "skipped", reason: "disable-mode"} and proceed to Step 5.</action>
|
|
41
|
+
<action if="mode == enable and not changed">Skip — no state transition occurred (bridge was already enabled). Set post_flip_result = {kind: "skipped", reason: "idempotent"} and proceed to Step 5.</action>
|
|
42
|
+
<action if="mode == enable and changed">Invoke runPostFlipChecks from {project-path}/src/bridge/bridge-post-flip-checks.js with {projectRoot, mode: "enable", changed: true, yolo: {yolo_mode}}. This module performs the filesystem stat of docs/test-artifacts/test-environment.yaml (resolved relative to {project-root}, NOT {project-path} — per AC) and calls into the existing E17-S7 validator at Gaia-framework/_gaia/core/validators/test-environment-validator.js. Capture its return value as post_flip_result.</action>
|
|
43
|
+
<action if="post_flip_result.kind == 'present_valid'">Collect post_flip_result.runners[] (name + tier) for inclusion in Step 5's summary. No prompt is shown. Proceed to Step 5.</action>
|
|
44
|
+
<action if="post_flip_result.kind == 'present_invalid'">Collect post_flip_result.errors[] as warnings for inclusion in Step 5's summary. Per AC5, do NOT roll back the bridge_enabled flag flip — the user can manually repair the manifest and re-run /gaia-build-configs. Proceed to Step 5.</action>
|
|
45
|
+
<action if="post_flip_result.kind == 'absent' and not yolo_mode">Render the 3-option prompt — options payload is available as post_flip_result.options (POST_FLIP_ABSENT_OPTIONS from bridge-post-flip-checks.js). Path A (ADR-028 §10.20.12.3): none of the options auto-invoke any sub-workflow. Present the three options exactly as written in the options list and ask the user to select one.</action>
|
|
46
|
+
<ask if="post_flip_result.kind == 'absent' and not yolo_mode">
|
|
47
|
+
`docs/test-artifacts/test-environment.yaml` was not found. The bridge is enabled, but Layer 1 will fail-fast at invocation time until the manifest is created. Select a next-step suggestion:
|
|
48
|
+
|
|
49
|
+
[a] Run `/gaia-brownfield` to auto-generate test-environment.yaml (next-step suggestion — NOT auto-invoked)
|
|
50
|
+
[b] Copy `docs/test-artifacts/test-environment.yaml.example` to `docs/test-artifacts/test-environment.yaml` and customize
|
|
51
|
+
[c] Skip — bridge is enabled but will fail-fast at Layer 1 with a clear error message until the manifest is created
|
|
52
|
+
|
|
53
|
+
Choose [a/b/c]:
|
|
54
|
+
</ask>
|
|
55
|
+
<action if="post_flip_result.kind == 'absent' and not yolo_mode">Record the user's selection as post_flip_result.choice (one of "a", "b", "c"). Per AC4, do NOT invoke any sub-workflow regardless of choice. Selection (a) does NOT run /gaia-brownfield; selection (b) does NOT copy the example file. Both are next-step suggestions the user must act on in the next conversation turn. Proceed to Step 5.</action>
|
|
56
|
+
<action if="post_flip_result.kind == 'absent' and yolo_mode">YOLO mode auto-selects option (c) Skip. runPostFlipChecks has already set post_flip_result.choice = "c" and post_flip_result.yoloAutoSkipped = true. Log a warning: "Bridge is enabled but docs/test-artifacts/test-environment.yaml is missing — Layer 1 will fail-fast until the manifest is created." Proceed to Step 5.</action>
|
|
57
|
+
<action>Pass post_flip_result to Step 5's summary composer (buildSummary receives it as the `postFlipResult` field).</action>
|
|
58
|
+
</step>
|
|
59
|
+
|
|
60
|
+
<step n="5" title="Post-Toggle Summary">
|
|
61
|
+
<action>Invoke buildSummary from {project-path}/src/bridge/bridge-toggle.js with {previousState, newState, mode, changed, postFlipResult} — the postFlipResult field is the structured object captured by Step 4 (or {kind: "skipped", ...} on disable / idempotent paths).</action>
|
|
62
|
+
<action>Display the returned summary. It always includes: previous state, new state, mode, and whether a write occurred.</action>
|
|
63
|
+
<action if="mode == enable and post_flip_result.kind == 'present_valid'">Summary includes the detected runners table (name + tier) produced by Step 4.</action>
|
|
64
|
+
<action if="mode == enable and post_flip_result.kind == 'present_invalid'">Summary includes the schema validation errors as warnings. The bridge_enabled flag is NOT rolled back (AC5).</action>
|
|
65
|
+
<action if="mode == enable and post_flip_result.kind == 'absent'">Summary includes the user's selected option (a/b/c) from Step 4, or — in YOLO mode — the auto-selected skip warning.</action>
|
|
66
|
+
<action>AC6: the summary always ends with the next-step suggestion "Run `/gaia-build-configs` to regenerate the resolved configs so the bridge_enabled change takes effect." — regardless of which Step 4 branch ran (present_valid, present_invalid, absent with any choice, skipped, or idempotent).</action>
|
|
67
|
+
<action if="mode == disable">Summary only confirms new state and reminds about /gaia-build-configs. No post-flip check output (AC7 — Step 4 was skipped).</action>
|
|
68
|
+
</step>
|
|
69
|
+
</workflow>
|