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.
Files changed (46) hide show
  1. package/.claude/commands/gaia-bridge-disable.md +18 -0
  2. package/.claude/commands/gaia-bridge-enable.md +18 -0
  3. package/.claude/commands/gaia-fill-test-gaps.md +17 -0
  4. package/CLAUDE.md +64 -1
  5. package/_gaia/_config/gaia-help.csv +2 -0
  6. package/_gaia/_config/global.yaml +14 -1
  7. package/_gaia/_config/lifecycle-sequence.yaml +23 -3
  8. package/_gaia/_config/skill-manifest.csv +1 -0
  9. package/_gaia/_config/workflow-manifest.csv +2 -0
  10. package/_gaia/core/agents/orchestrator.md +1 -1
  11. package/_gaia/core/protocols/review-gate-check.xml +45 -5
  12. package/_gaia/core/validators/test-environment-validator.js +191 -0
  13. package/_gaia/core/workflows/bridge-toggle/checklist.md +11 -0
  14. package/_gaia/core/workflows/bridge-toggle/instructions.xml +69 -0
  15. package/_gaia/core/workflows/bridge-toggle/workflow.yaml +27 -0
  16. package/_gaia/dev/skills/_skill-index.yaml +13 -0
  17. package/_gaia/dev/skills/code-review-standards.md +50 -0
  18. package/_gaia/dev/skills/edge-cases.md +201 -0
  19. package/_gaia/lifecycle/knowledge/brownfield/ci-test-detection.md +194 -0
  20. package/_gaia/lifecycle/knowledge/brownfield/test-execution-scan.md +13 -0
  21. package/_gaia/lifecycle/skills/document-rulesets.md +93 -3
  22. package/_gaia/lifecycle/templates/story-template.md +7 -7
  23. package/_gaia/lifecycle/templates/test-gap-analysis-template.md +221 -0
  24. package/_gaia/lifecycle/workflows/4-implementation/check-review-gate/checklist.md +1 -1
  25. package/_gaia/lifecycle/workflows/4-implementation/check-review-gate/instructions.xml +11 -11
  26. package/_gaia/lifecycle/workflows/4-implementation/code-review/instructions.xml +1 -1
  27. package/_gaia/lifecycle/workflows/4-implementation/create-story/instructions.xml +73 -2
  28. package/_gaia/lifecycle/workflows/4-implementation/dev-story/instructions.xml +25 -2
  29. package/_gaia/lifecycle/workflows/4-implementation/retrospective/instructions.xml +1 -1
  30. package/_gaia/lifecycle/workflows/4-implementation/run-all-reviews/instructions.xml +132 -9
  31. package/_gaia/lifecycle/workflows/4-implementation/security-review/checklist.md +2 -0
  32. package/_gaia/lifecycle/workflows/4-implementation/sprint-planning/instructions.xml +13 -0
  33. package/_gaia/lifecycle/workflows/4-implementation/sprint-planning/workflow.yaml +8 -0
  34. package/_gaia/lifecycle/workflows/4-implementation/validate-story/checklist.md +1 -0
  35. package/_gaia/lifecycle/workflows/4-implementation/validate-story/instructions.xml +11 -0
  36. package/_gaia/lifecycle/workflows/5-deployment/deployment-checklist/instructions.xml +11 -0
  37. package/_gaia/lifecycle/workflows/anytime/brownfield-onboarding/instructions.xml +48 -1
  38. package/_gaia/lifecycle/workflows/anytime/brownfield-onboarding/workflow.yaml +10 -0
  39. package/_gaia/testing/agents/test-architect.md +2 -0
  40. package/_gaia/testing/workflows/fill-test-gaps/checklist.md +16 -0
  41. package/_gaia/testing/workflows/fill-test-gaps/instructions.xml +128 -0
  42. package/_gaia/testing/workflows/fill-test-gaps/workflow.yaml +30 -0
  43. package/_gaia/testing/workflows/test-gap-analysis/instructions.xml +47 -14
  44. package/_gaia/testing/workflows/test-gap-analysis/workflow.yaml +1 -0
  45. package/gaia-install.sh +37 -0
  46. package/package.json +3 -3
@@ -0,0 +1,221 @@
1
+ ---
2
+ mode: coverage
3
+ date: "{date}"
4
+ project: "{project_name}"
5
+ story_count: 0
6
+ gap_count: 0
7
+ ---
8
+
9
+ # Test Gap Analysis — {date}
10
+
11
+ > **Schema version:** 1.0.0
12
+ > **Traces to:** FR-223, ADR-030 §10.22
13
+ > **Story:** E19-S3
14
+ > **Template location:** `_gaia/lifecycle/templates/test-gap-analysis-template.md`
15
+ >
16
+ > Standardized output schema for the `/gaia-test-gap-analysis` workflow.
17
+ > This template scaffolds the `test-gap-analysis-{date}.md` artifact written by
18
+ > the workflow in both `coverage` and `verification` modes. Downstream tools and
19
+ > agents parse this file — keep the schema stable and bump the schema version on
20
+ > any breaking change.
21
+
22
+ ## Schema Definition
23
+
24
+ The output file consists of five mandatory sections, in this order:
25
+
26
+ 1. **YAML frontmatter** — five required fields (see below)
27
+ 2. **Executive Summary** — high-level narrative and headline numbers
28
+ 3. **Gap Table** — one row per gap, four columns
29
+ 4. **Per-Story Detail** — one subsection per story with gaps
30
+ 5. **Recommendations** — prioritized remediation actions
31
+
32
+ ### YAML Frontmatter
33
+
34
+ Five required fields, parsed by `js-yaml` without error (AC4):
35
+
36
+ | Field | Type | Description |
37
+ |-------|------|-------------|
38
+ | `mode` | enum | `coverage` or `verification` — matches the workflow mode that produced the file |
39
+ | `date` | string | ISO-8601 date the gap analysis was run (e.g., `2026-04-09`) |
40
+ | `project` | string | Project name (from `global.yaml` `project_name`) |
41
+ | `story_count` | integer | Number of stories analyzed in this run |
42
+ | `gap_count` | integer | Total number of gaps detected across all stories |
43
+
44
+ All five fields are required. Missing any field MUST be flagged by Val as a
45
+ WARNING (AC6). The frontmatter block MUST be delimited by `---` lines at the
46
+ top of the file and MUST parse cleanly with any standards-compliant YAML
47
+ parser.
48
+
49
+ ### Gap Type Enum (closed)
50
+
51
+ Gap types are drawn from a fixed, **closed** enum. No extension is permitted
52
+ without a schema version bump (AC2).
53
+
54
+ | Value | Description |
55
+ |-------|-------------|
56
+ | `missing-test` | An acceptance criterion or requirement has no associated test case in `test-plan.md` |
57
+ | `unexecuted` | A test case exists but was never run (no JUnit, LCOV, or E17 evidence) |
58
+ | `uncovered-ac` | An acceptance criterion on a story is not referenced by any test case ID |
59
+ | `missing-edge-case` | The test plan references the story but fails to cover a required edge case documented in story Test Scenarios or ATDD |
60
+
61
+ Any value outside this enum MUST be flagged by Val as CRITICAL.
62
+
63
+ ### Severity Enum
64
+
65
+ Severity values are also fixed (AC3):
66
+
67
+ | Value | Description |
68
+ |-------|-------------|
69
+ | `critical` | Blocks release — high-risk story with no coverage |
70
+ | `high` | Significant coverage gap requiring prompt attention |
71
+ | `medium` | Moderate gap, should be addressed in the current sprint |
72
+ | `low` | Minor gap, can be deferred |
73
+
74
+ Any value outside this enum MUST be flagged by Val as CRITICAL.
75
+
76
+ ## Executive Summary
77
+
78
+ {1-3 sentence narrative summarizing the run.}
79
+
80
+ - **Stories analyzed:** {story_count}
81
+ - **Gaps detected:** {gap_count}
82
+ - **Overall coverage rate:** {aggregate_coverage_pct}%
83
+ - **Generated vs Executed:** {total_executed}/{total_generated} ({aggregate_exec_ratio}%)
84
+ - **Mode:** {mode}
85
+
86
+ If `gap_count` is 0, state `No coverage gaps detected.` explicitly.
87
+
88
+ The **Generated vs Executed** row (E19-S7, FR-226) reports the aggregate
89
+ number of generated test cases vs. the number actually executed across all
90
+ stories. It is rendered as `{total_executed}/{total_generated} ({aggregate_exec_ratio}%)`.
91
+ When `total_generated` is 0, the row renders as `0/0 (0.0%)` — no
92
+ division-by-zero error. The aggregate is computed by summing per-story
93
+ `generated` and `executed` counts from the Per-Story Detail section.
94
+
95
+ The `Overall coverage rate` is the aggregate `(tested_acs / total_acs) * 100`
96
+ computed across all included epics by the Per-Module Coverage step (E19-S6,
97
+ FR-225). It replaces any prior per-story averaged figure and is rounded to one
98
+ decimal place.
99
+
100
+ ## Per-Module Coverage
101
+
102
+ > **Traces to:** FR-225, ADR-030 §10.22
103
+ > **Story:** E19-S6
104
+ >
105
+ > Per-epic coverage percentage calculated as `(tested_acs / total_acs) * 100`,
106
+ > rounded to one decimal place. Rows sorted by `coverage_pct` ascending (lowest
107
+ > coverage first); ties broken by `module` key lexicographical ascending. Epics
108
+ > with zero story files are excluded from the table — a footnote reports how
109
+ > many were excluded when that count is non-zero.
110
+
111
+ | module | total_acs | tested_acs | coverage_pct | gap_count |
112
+ |--------|-----------|------------|--------------|-----------|
113
+ | E19 | 24 | 18 | 75.0% | 6 |
114
+ | E1 | 12 | 6 | 50.0% | 6 |
115
+
116
+ > _{N} epics with no story files were excluded._
117
+
118
+ When every included epic has zero ACs (the workflow finds story files but no
119
+ acceptance criteria items), render a single row reading
120
+ `| — | 0 | 0 | 0.0% | 0 |` and keep the aggregate `aggregate_coverage_pct`
121
+ at `0.0%`. The calculation is deterministic — identical inputs always produce
122
+ byte-identical rows and aggregate values (AC5).
123
+
124
+ ## Gap Table
125
+
126
+ Flat table of every gap in this run. Columns (in this order) are canonical:
127
+
128
+ | story_key | gap_type | severity | description |
129
+ |-----------|----------|----------|-------------|
130
+ | E1-S1 | uncovered-ac | high | AC3 has no matching test case in test-plan.md |
131
+ | E1-S2 | missing-edge-case | medium | Test scenario 4 (empty input) is not exercised |
132
+
133
+ - `story_key` — the canonical story key (e.g., `E19-S3`)
134
+ - `gap_type` — one of the four values from the closed enum above
135
+ - `severity` — one of the four values from the severity enum above
136
+ - `description` — one-line summary of the gap (keep under 120 chars)
137
+
138
+ If no gaps exist, render the table header alone with a single row reading
139
+ `| — | — | — | No gaps detected |`.
140
+
141
+ ## Per-Story Detail
142
+
143
+ One subsection per story that has one or more rows in the Gap Table.
144
+
145
+ ### {story_key} — {story_title}
146
+
147
+ - **Total ACs:** {count}
148
+ - **Covered ACs:** {count}
149
+ - **Uncovered ACs:** {list of AC identifiers}
150
+ - **Missing tests:** {list of test case IDs or descriptions}
151
+ - **generated:** {count of generated test cases for this story}
152
+ - **executed:** {count of executed test cases for this story}
153
+ - **exec_ratio:** {executed / generated * 100, one decimal}% (E19-S7, FR-226)
154
+ - **Remediation:** {1-2 sentence suggested action}
155
+
156
+ Stories with zero gaps MAY be omitted from this section to keep the document
157
+ focused. The Gap Table is the canonical list.
158
+
159
+ The `generated`, `executed`, and `exec_ratio` fields are required on every
160
+ story subsection that reports verification results (E19-S7, FR-226). When
161
+ `generated` is 0, render `exec_ratio` as `0.0%` with a note rather than
162
+ raising a division-by-zero error. When `executed` is 0 and `generated > 0`,
163
+ the story MUST be flagged as `HIGH` gap priority in the Gap Table and in
164
+ the per-story remediation line.
165
+
166
+ ## Recommendations
167
+
168
+ Prioritized list of concrete next steps, ordered by severity:
169
+
170
+ 1. **{critical|high|medium|low}** — {action} — owner: {agent or team}
171
+ 2. ...
172
+
173
+ Each recommendation SHOULD map to one or more Gap Table rows so downstream
174
+ tools can generate traceability.
175
+
176
+ ## Frontend Dimensions
177
+
178
+ > **Traces to:** FR-224, ADR-030 §10.22.3
179
+ > **Story:** E19-S5
180
+ >
181
+ > Six-dimension test-type breakdown for frontend projects. This section is
182
+ > **present only when** the workflow detects the scanned project as a
183
+ > frontend stack (Angular, Flutter, React, Vue, Svelte, or a generic
184
+ > `src/app/` layout). For non-frontend projects the section is **omitted
185
+ > entirely** — no empty table, no error, no warning.
186
+
187
+ | Dimension | Gap Count | Coverage Score | Top-3 Uncovered |
188
+ |-----------|-----------|----------------|-----------------|
189
+ | Unit Tests | {count} | {0-100}% | {list or "—"} |
190
+ | E2E Tests | {count} | {0-100}% | {list or "—"} |
191
+ | Cross-browser | {count} | {0-100}% | {list or "—"} |
192
+ | Accessibility | {count} | {0-100}% | {list or "—"} |
193
+ | Visual Regression | {count} | {0-100}% | {list or "—"} |
194
+ | Responsive | {count} | {0-100}% | {list or "—"} |
195
+
196
+ **Detection signals** (per architecture §10.22.3):
197
+
198
+ - **Unit Tests** — `*.test.{ts,js}` / `*.spec.{ts,js}` in `src/`; gap if coverage < 60%
199
+ - **E2E Tests** — Playwright or Cypress spec files; gap if none found
200
+ - **Cross-browser** — browser matrix in `playwright.config.{ts,js}` or `cypress.config.{ts,js}`; gap if `browsers: [chromium]` only or absent
201
+ - **Accessibility** — `axe-core`, `jest-axe`, `@testing-library/jest-axe`, `@axe-core/playwright`, or `cypress-axe` in package.json; gap if none installed
202
+ - **Visual Regression** — Percy, Chromatic, or `playwright-visual-comparisons` in package.json; gap if none configured
203
+ - **Responsive** — viewport resize tests, `--viewport` flag in Playwright, or `cy.viewport` in Cypress; gap if absent from test files
204
+
205
+ Per-dimension coverage scores feed into E19-S6's overall coverage percentage
206
+ calculation. A non-frontend project's output skips this section entirely and
207
+ E19-S6 falls back to the generic Gap Table totals.
208
+
209
+ ---
210
+
211
+ ## Notes
212
+
213
+ - This template is read by `/gaia-test-gap-analysis` in both coverage and
214
+ verification modes. The workflow populates placeholder values and writes
215
+ the result to `{test_artifacts}/test-gap-analysis-{date}.md`.
216
+ - The gap type enum is **closed**. Adding a new gap type is a breaking change
217
+ and requires a schema version bump in the `Schema version` header above.
218
+ - Val validates output files against this schema via the
219
+ `gap-analysis-output` ruleset in `_memory/validator-sidecar/ground-truth.md`.
220
+ - Per ADR-020, projects MAY override this template by placing a file at
221
+ `custom/templates/test-gap-analysis-template.md`.
@@ -8,7 +8,7 @@ validation-target: 'Composite review gate evaluation and status transition'
8
8
  - [ ] Story file found and loaded
9
9
  - [ ] Story status is review or done
10
10
  - [ ] Review Gate table has exactly 6 rows
11
- - [ ] All 6 review statuses parsed (PASSED/FAILED/PENDING)
11
+ - [ ] All 6 review statuses parsed (UNVERIFIED/PASSED/FAILED)
12
12
  - [ ] Shared protocol review-gate-check.xml loaded and executed
13
13
  - [ ] DoD validation performed before transition
14
14
  - [ ] Status transition applied correctly (or blocked with reason)
@@ -13,41 +13,41 @@
13
13
  <step n="2" title="Evaluate Review Gate">
14
14
  <action>Load and execute the shared protocol: {project-root}/_gaia/core/protocols/review-gate-check.xml</action>
15
15
  <action>Parse the Review Gate table — verify exactly 6 rows exist (Code Review, QA Tests, Security Review, Test Automation, Test Review, Performance Review)</action>
16
- <action>Classify each row as PASSED, FAILED, or PENDING</action>
16
+ <action>Classify each row as UNVERIFIED, PASSED, or FAILED</action>
17
17
  <action>If any row is missing or has an invalid status, flag it as an error</action>
18
18
  </step>
19
19
  <step n="3" title="Execute Gate Transition">
20
20
  <action>If ALL 6 rows PASSED AND all Definition of Done items checked AND story status is 'review': transition story status to 'done' in story file frontmatter ONLY</action>
21
21
  <action>If ALL 6 rows PASSED but DoD incomplete: log "BLOCKED: DoD incomplete" — do NOT transition</action>
22
22
  <action>If ALL 6 rows PASSED AND story already 'done': log "Story already done. No update needed."</action>
23
- <action>If any row FAILED or PENDING: do NOT change story status</action>
23
+ <action>If any row FAILED or UNVERIFIED: do NOT change story status</action>
24
24
  </step>
25
25
  <step n="4" title="Generate Gate Status Report">
26
26
  <action>Append Gate Status Report at the END of the story file, after a horizontal rule (---) separator</action>
27
27
  <template-output file="{implementation_artifacts}/{story_key}-{story_title_slug}.md">
28
28
  Append a section titled "## Review Gate Status Report" at the very end of the story file, preceded by a --- separator. Include:
29
29
  - Date of check
30
- - Overall verdict: ALL PASSED | HAS FAILURES | HAS PENDING
30
+ - Overall verdict: ALL PASSED | HAS FAILURES | HAS UNVERIFIED
31
31
  - Gate summary table:
32
32
 
33
33
  | Review | Status | Report |
34
34
  |--------|--------|--------|
35
- | Code Review | PASSED/FAILED/PENDING | link or — |
36
- | QA Tests | PASSED/FAILED/PENDING | link or — |
37
- | Security Review | PASSED/FAILED/PENDING | link or — |
38
- | Test Automation | PASSED/FAILED/PENDING | link or — |
39
- | Test Review | PASSED/FAILED/PENDING | link or — |
40
- | Performance Review | PASSED/FAILED/PENDING | link or — |
35
+ | Code Review | UNVERIFIED/PASSED/FAILED | link or — |
36
+ | QA Tests | UNVERIFIED/PASSED/FAILED | link or — |
37
+ | Security Review | UNVERIFIED/PASSED/FAILED | link or — |
38
+ | Test Automation | UNVERIFIED/PASSED/FAILED | link or — |
39
+ | Test Review | UNVERIFIED/PASSED/FAILED | link or — |
40
+ | Performance Review | UNVERIFIED/PASSED/FAILED | link or — |
41
41
 
42
42
  - Transition result: what action was taken (transitioned to done / blocked by DoD / no change)
43
43
  - If FAILED: list failed reviews and recommend re-running them individually
44
- - If PENDING: list pending reviews and recommend running them or /gaia-run-all-reviews
44
+ - If UNVERIFIED: list unverified reviews and recommend running them or /gaia-run-all-reviews
45
45
  - If ALL PASSED: confirm story is done
46
46
  </template-output>
47
47
  <next-step>
48
48
  <on_all_passed>Story is done — proceed to /gaia-sprint-status to update sprint tracking</on_all_passed>
49
49
  <on_failures>Re-run failed reviews individually, then run /gaia-check-review-gate again</on_failures>
50
- <on_pending>Run /gaia-run-all-reviews to complete remaining reviews</on_pending>
50
+ <on_unverified>Run /gaia-run-all-reviews to complete remaining reviews</on_unverified>
51
51
  </next-step>
52
52
  </step>
53
53
  </workflow>
@@ -50,7 +50,7 @@
50
50
  <step n="7" title="Update Review Gate and Transition">
51
51
  <action>Read story file, locate Review Gate table</action>
52
52
  <action>If APPROVE: update Code Review row status to PASSED, link report file</action>
53
- <action>If REQUEST_CHANGES: update Code Review row status to REQUEST_CHANGES, link report file. Do NOT change story status — the review-gate-check protocol or run-all-reviews orchestrator handles status transitions.</action>
53
+ <action>If REQUEST_CHANGES: update Code Review row status to FAILED, link report file. The machine-readable verdict keyword (APPROVE/REQUEST_CHANGES) remains in the review report body for the dev agent to parse — only the Review Gate row uses the canonical vocabulary {UNVERIFIED, PASSED, FAILED}. Do NOT change story status — the review-gate-check protocol or run-all-reviews orchestrator handles status transitions.</action>
54
54
  <template-output file="{implementation_artifacts}/{story_key}-*.md">
55
55
  Update story file Review Gate table with code review result and report link.
56
56
  </template-output>
@@ -89,8 +89,79 @@
89
89
  <action>Define subtasks for implementation</action>
90
90
 
91
91
  <!-- Edge Case Size Gate (E19-S8, FR-227, FR-228) -->
92
- <check if="size == 'S'">Skip edge case analysis sub-step — story is small enough that edge case analysis would waste token budget. Log to Dev Notes: "Edge case analysis: skipped (size=S)"</check>
93
- <check if="size in ['M', 'L', 'XL']">Edge case analysis sub-step is mandatory for this story size. Proceed with edge case analysis. Log to Dev Notes: "Edge case analysis: completed (size={size})"</check>
92
+ <check if="size == 'S'">Skip edge case analysis sub-step — story is small enough that edge case analysis would waste token budget. Log to Dev Notes: "Edge case analysis: skipped (size=S)". Set edge_case_results = [].</check>
93
+ <check if="size in ['M', 'L', 'XL']">Edge case analysis sub-step is mandatory for this story size. Proceed to Step 4b (Edge Case Analysis Sub-Step) below. Log to Dev Notes: "Edge case analysis: completed (size={size})"</check>
94
+ </step>
95
+ <step n="4b" title="Edge Case Analysis Sub-Step (M/L/XL only)">
96
+ <critical>
97
+ <mandate>This sub-step implements FR-227: /gaia-create-story MUST invoke the edge-cases skill as a mandatory sub-step for M+ stories after acceptance criteria are drafted. The sub-step runs in-context — it does NOT use invoke-workflow or invoke-task. It is a JIT skill load only.</mandate>
98
+ <mandate>Token budget: the entire sub-step (input context + skill output) MUST stay within 8K tokens (NFR-042). If the budget is exceeded, truncate results with a warning logged to Dev Notes.</mandate>
99
+ <mandate>Sub-step failure is NON-BLOCKING: if the edge case skill fails, times out, or returns malformed output, log a warning and continue story creation with edge_case_results = []. Story file write MUST NOT be blocked by edge case sub-step failure.</mandate>
100
+ </critical>
101
+ <check if="size == 'S'">Skip this entire step — the size gate in Step 4 already excluded S-sized stories. Proceed to Step 5.</check>
102
+ <action>JIT-load the edge case analysis skill from {project-root}/_gaia/dev/skills/edge-cases.md. Do NOT use invoke-workflow or invoke-task — this is a direct skill load in the current create-story context. The skill file must exist at that path; if missing, log warning "Edge case skill not loaded — continuing without edge cases", set edge_case_results = [], and proceed to Step 5 (non-blocking).</action>
103
+ <action>Build the input context for the edge-cases skill per its input-contract section: story_key, story_title, story_description, acceptance_criteria (the list drafted in Step 4), size, and an optional architecture_excerpt (only if directly relevant). Keep the input context under 5K tokens to stay within the NFR-042 8K total budget.</action>
104
+ <action>Invoke the edge case analysis inline, following the edge-cases.md skill heuristics. Generate a structured list of edge cases using the skill's output-schema. Each edge case MUST include all five required fields: id, scenario, input, expected, category. The id uses EC-{N} sequential numbering (EC-1, EC-2, ...). The category field uses one of the enum values defined in edge-cases.md (boundary, error, timing, concurrency, integration, security, data, environment).</action>
105
+ <action>Store the skill's structured output in a named runtime variable `edge_case_results` — a list of objects each with {id, scenario, input, expected, category}. This variable MUST be captured and stored BEFORE the Step 6 template-output writes the story file to disk, satisfying the completion gate (AC5). Example: edge_case_results = [{id: "EC-1", scenario: "...", input: "...", expected: "...", category: "boundary"}, ...].</action>
106
+ <action>Validate the structured output: confirm every entry has all five required fields (id, scenario, input, expected, category). If any entry is missing a required field, treat the output as malformed per the skill's failure-handling section — log warning "Edge case output schema invalid — continuing without edge cases", set edge_case_results = [], and proceed (non-blocking).</action>
107
+ <action>TOKEN BUDGET CHECK (NFR-042): After the skill returns, estimate the total tokens consumed by (input context + skill output). If the total exceeds the 8K NFR-042 token budget, truncate edge_case_results — drop lower-priority entries (keep boundary + error + security first) and log warning to Dev Notes: "Edge case output truncated at 8K tokens — N results dropped". If token usage reaches 80% of budget (6.4K) without exceeding, log a note to Dev Notes: "Edge case sub-step token usage: {used}K / 8K".</action>
108
+ <action>TIMEOUT / FAILURE GUARD (AC6): Wrap the entire edge case sub-step invocation in an error handler. If the skill fails for ANY reason — skill file not found, timeout (> 30s wall clock), exception during analysis, malformed output, or token budget blowout — log a warning "Edge case analysis failed: {reason} — continuing without edge cases", set edge_case_results = [], and proceed to Step 5. This sub-step is explicitly non-blocking: edge case failure MUST NOT halt story creation. This is the only place in create-story where a sub-step failure is allowed to warn-and-continue instead of HALT.</action>
109
+ <action>COMPLETION GATE (AC5): Confirm that edge_case_results has been captured (either as a populated list or as an empty list after failure). Only after this confirmation may the workflow proceed to Step 5 and eventually Step 6's template-output. If edge_case_results is unset (not merely empty), treat as a malformed invocation and reset to []. Log to Dev Notes: "Edge case sub-step complete: {count} results captured".</action>
110
+ <action>Persist edge_case_results into the story for traceability: the Step 6 template-output appends a summary of the captured edge cases into the story's Test Scenarios section (or Dev Notes if Test Scenarios is not applicable). Each edge case is rendered as a row with its id, scenario, input, expected, and category — preserving the structured shape.</action>
111
+ </step>
112
+ <step n="4c" title="Append Edge Case Results to Acceptance Criteria (FR-229)">
113
+ <critical>
114
+ <mandate>This sub-step implements FR-229: edge case results captured by Step 4b MUST be appended to the story's Acceptance Criteria section as AC-EC{N} items BEFORE Step 6 writes the story file to disk. This ensures edge cases are formally tracked and verifiable at review time.</mandate>
115
+ <mandate>Primary ACs are IMMUTABLE at this point — never modify, never reorder, never insert between existing primary ACs. AC-EC items are append-only, added AFTER the last primary AC in the Acceptance Criteria section. This is the AC4 safety guarantee.</mandate>
116
+ <mandate>AC-EC numbering restarts from 1 per story. Each story's AC-EC counter is independent of other stories and independent of the primary AC numbers — there is no collision because the AC-EC prefix is distinct.</mandate>
117
+ </critical>
118
+ <check if="size == 'S'">Skip this entire step — Step 4's size gate already excluded S-sized stories from edge case analysis. Proceed to Step 5.</check>
119
+ <action>SNAPSHOT PRIMARY ACs (AC4): Before processing edge_case_results, capture the list of primary ACs drafted in Step 4 into a frozen variable primary_acs_snapshot. This snapshot is read-only for the remainder of the workflow. After the AC-EC append completes, verify that the first len(primary_acs_snapshot) entries in the Acceptance Criteria list still match the snapshot exactly (same order, same text). If any primary AC text or order has changed, HALT with "AC4 violation: primary AC list was modified during edge case append." This safety check ensures primary ACs are never touched.</action>
120
+ <action>ZERO-RESULT FAST PATH (AC5): If edge_case_results is empty (length == 0 or the list is []) — either because the edge case sub-step returned no results, failed non-blocking, or was skipped — do NOT add any AC-EC items to the Acceptance Criteria section. Append the note "No edge cases identified." to the story's Dev Notes section and proceed to Step 5. The Acceptance Criteria section remains exactly as drafted in Step 4.</action>
121
+ <action>FORMAT EACH EDGE CASE AS AC-EC (AC1, AC2, AC3): For each entry in edge_case_results, format a new acceptance criterion using the canonical AC-EC rendering template:
122
+ - [ ] **AC-EC{N}:** {scenario} — Expected: {expected} [category: {category}]
123
+ where:
124
+ - {N} is a sequential counter starting at 1 for this story (AC-EC1, AC-EC2, AC-EC3, ...). The counter restarts from 1 for every story — there is no global AC-EC numbering and no collision with primary AC numbers because the "AC-EC" prefix is distinct from the primary "AC" prefix.
125
+ - {scenario} is the scenario field from the edge case result (a short natural-language description of the edge case).
126
+ - {expected} is the expected field from the edge case result (the observable outcome that verifies the edge case is handled).
127
+ - {category} is the category field from the edge case result (one of the enum values: boundary, error, timing, concurrency, integration, security, data, environment).
128
+ The rendered line must include all three fields (scenario, expected, category) in exactly this order. The bracketed `[category: {category}]` tag is part of the canonical format so reviewers can quickly triage edge-case ACs by category.</action>
129
+ <action>APPEND AFTER LAST PRIMARY AC (AC4): Insert the formatted AC-EC lines immediately AFTER the last primary AC in the Acceptance Criteria section — never before, never between primary ACs, never in a separate section. The final Acceptance Criteria list order is: [all primary ACs in their original order, then AC-EC1, AC-EC2, ..., AC-ECn]. Do NOT renumber or rewrite any primary AC. Do NOT alter the spacing, formatting, or text of any primary AC. The append is strictly additive.</action>
130
+ <action>NUMBERING CONSISTENCY (Task 4): Confirm the AC-EC counter started from 1 for this story and that no AC-EC number collides with a primary AC number (e.g., if the story has primary ACs AC1..AC5, the edge case ACs are AC-EC1..AC-ECn, NOT AC6..). The "AC-EC" prefix is the canonical disambiguator — never drop it, never merge AC-EC numbering into the primary AC sequence.</action>
131
+ <action>DEV NOTES LOG: Append to the story's Dev Notes section: "Edge case AC append: {count} AC-EC items added (FR-229)". If count is 0, the zero-result fast path above has already logged "No edge cases identified." — do not double-log.</action>
132
+ <action>POST-APPEND PRIMARY AC VERIFICATION (AC4): Re-read the Acceptance Criteria section after the append and compare the first len(primary_acs_snapshot) items against primary_acs_snapshot. They MUST match exactly. If not, HALT with "AC4 violation: primary ACs were modified during AC-EC append." This is the final safety gate before the workflow proceeds to Step 5.</action>
133
+ </step>
134
+ <step n="4d" title="Append Edge Case Results to Test Plan (FR-230)">
135
+ <critical>
136
+ <mandate>This sub-step implements FR-230: edge case results captured by Step 4b MUST be appended to {test_artifacts}/test-plan.md as new rows BEFORE Step 6 writes the story file to disk. This ensures edge case scenarios are captured in the test artifact, not only in the story file.</mandate>
137
+ <mandate>Sub-step failure is NON-BLOCKING (AC4): if test-plan.md does not exist, log a note in the story's Dev Notes and continue without error. Story creation MUST NOT be blocked by a missing test-plan.md.</mandate>
138
+ <mandate>Idempotency is REQUIRED (AC5): re-running create-story for the same story_key MUST NOT duplicate edge case rows in the test plan. Dedup key = (story_key, scenario).</mandate>
139
+ </critical>
140
+ <check if="size == 'S'">Skip this entire step — Step 4's size gate already excluded S-sized stories from edge case analysis. Proceed to Step 5.</check>
141
+ <action>ZERO-RESULT FAST PATH: If edge_case_results is empty (length == 0) — either because the edge case sub-step returned no results, failed non-blocking, or was skipped — do NOT open or modify test-plan.md. Proceed to Step 5. No-op, no dev note (the AC-EC append step 4c already logged "No edge cases identified.").</action>
142
+ <action>FILE EXISTENCE CHECK (AC4): Check whether {test_artifacts}/test-plan.md exists. If the file does not exist (file absent, path not found, or the directory is missing), log a note in the story's Dev Notes section — exactly "Edge case test plan append: skipped — test-plan.md not found at {test_artifacts}/test-plan.md (non-blocking)." Do NOT raise an error, do NOT create test-plan.md, do NOT halt. Proceed to Step 5. This is the non-blocking fallback path.</action>
143
+ <action>READ TEST PLAN: Read {test_artifacts}/test-plan.md into memory. The content is the authoritative target for both the existing-section locate and the highest-TC-ID scan below.</action>
144
+ <action>LOCATE STORY SECTION (AC1): Search the test-plan.md content for a heading or row that references this story_key. Locate the story's section via any of: (a) a markdown heading containing the story_key (e.g., "### E19-S11 — ..." or "## {story_key}"); (b) an existing table row in the test-plan.md whose trailing cell contains the story_key. If a section is found, remember the insertion point (immediately after the last existing row of that section). If no section is found, the insertion point is the end of the file — a new section will be created.</action>
145
+ <action>TC ID NUMBERING (AC3): Scan the entire test-plan.md content for the highest existing test case ID. Match the canonical TC ID patterns used by the test plan (e.g., TC-{N}, TGA-{N}, ECI-{N}, and any other prefix already present in the file). For the purposes of this append, find the highest numeric suffix among all IDs sharing the same prefix the story's Dev Notes declares (e.g., ECI-13 for E19-S11 → next is ECI-14). If no prefix is declared in Dev Notes, default to TC-{N} and auto-increment from the highest existing TC-{N}. If no TC IDs exist at all, start at TC-1. The next TC ID assigned to the first new edge case row is (highest + 1), and subsequent edge cases increment sequentially.</action>
146
+ <action>IDEMPOTENCY / DEDUP CHECK (AC5): Before appending any row, scan the test-plan.md content for existing rows that match this (story_key, scenario) pair. A row is considered a duplicate if its trailing cell contains the story_key AND its scenario cell contains the exact scenario text from the current edge_case_results entry. For each edge case result: if a duplicate row exists, SKIP that entry (do not append); otherwise, mark it for append. Track the count of skipped duplicates and the count of new rows to append. The dedup key is (story_key, scenario) — this makes re-runs of create-story for the same story_key idempotent.</action>
147
+ <action>FORMAT ROWS (AC2): For each non-duplicate edge case result, format a new test-plan row using the canonical row format:
148
+ | {tc_id} | {scenario} | edge-case | {severity} | {story_key} |
149
+ where:
150
+ - {tc_id} is the auto-incremented test case ID from the numbering step above (e.g., ECI-14, ECI-15).
151
+ - {scenario} is the scenario field from the edge case result (verbatim from edge_case_results).
152
+ - edge-case is the literal tag string — never replaced, never translated, never lower/upper-cased differently.
153
+ - {severity} is derived from the edge case category: boundary/data → medium; error/integration → high; security → high; timing/concurrency → high; environment → low. If category is missing or unmapped, default to medium.
154
+ - {story_key} is the current story's key (e.g., E19-S11) — this is the dedup key used in AC5.
155
+ The row columns MUST appear in exactly this order: tc_id | scenario | edge-case | severity | story_key. Never reorder.</action>
156
+ <action>APPEND ROWS: If the story section was found, append the formatted rows immediately after the last existing row of that section. If no story section was found, append a new section at the end of the test-plan.md file:
157
+ ### {story_key} — {story_title}
158
+ | ID | Scenario | Type | Severity | Story |
159
+ |----|----------|------|----------|-------|
160
+ {formatted rows}
161
+ The new section uses the same table header as existing sections so renderers and scanners keep working.</action>
162
+ <action>WRITE TEST PLAN: Write the updated test-plan.md content back to {test_artifacts}/test-plan.md. Preserve the original file's trailing newline convention and do not touch any content outside the insertion point. If the write fails for any reason (permission denied, disk full, etc.), log a warning to Dev Notes "Edge case test plan append: write failed — {error}. Scenarios preserved in story file only." and proceed non-blockingly.</action>
163
+ <action>DEV NOTES LOG: Append to the story's Dev Notes section exactly: "Edge case test plan append: {new_count} rows added, {dup_count} duplicates skipped (FR-230)". If both counts are zero (everything was a duplicate on a re-run), the line is still logged so the idempotency path is observable.</action>
164
+ <action>COMPLETION GATE: Confirm the test plan append step has run to completion (either by appending rows, skipping on missing file, skipping on zero results, or logging a write failure). Only after this confirmation may the workflow proceed to Step 5.</action>
94
165
  </step>
95
166
  <step n="5" title="Definition of Done">
96
167
  <action>Append DoD checklist: all AC met, tests pass, code reviewed, docs updated</action>
@@ -8,6 +8,29 @@
8
8
  <mandate>All tests must pass before marking complete</mandate>
9
9
  <mandate>When reading or running application source code, use {project-path} as the base directory — NOT {project-root}. {project-path} is resolved by the engine from global.yaml.</mandate>
10
10
  </critical>
11
+ <!--
12
+ Test Execution Bridge — Layer 3 integration (E17-S10, FR-194, FR-197, FR-198, NFR-034, ADR-028)
13
+
14
+ After the GREEN phase's test run, when test_execution_bridge.bridge_enabled is true in global.yaml, the
15
+ workflow invokes Bridge Layer 3 (src/bridge/layer-3-result-parsing.js) on the captured Layer 2 output
16
+ { stdout, stderr, exit_code } to parse results and generate the evidence file. Layer 3 supports Vitest
17
+ TAP, Jest JSON, and BATS TAP runner outputs; unknown formats fall back to a minimal evidence record with
18
+ parse_error: true and the first 2KB captured as raw_output_snippet.
19
+
20
+ Layer 3 writes the evidence file to docs/test-artifacts/test-results/{story_key}-execution.json using
21
+ the FR-194 / FR-197 schema: { schema_version, story_key, runner, mode, executed_at, duration_seconds,
22
+ summary: { total, passed, failed, skipped }, tests: [ { name, status, duration_ms, failure_message? } ],
23
+ truncated }. When serialized size exceeds 500KB, Layer 3 truncates the tests array (NFR-034 size cap)
24
+ and sets truncated: true while preserving the summary block intact.
25
+
26
+ The evidence file path (returned by writeEvidence) MUST be reported to the user after Layer 3 writes
27
+ the file, and a linked reference to the evidence file path MUST be added to the story's Review Gate
28
+ section so downstream review workflows and the review-gate-check protocol can discover the evidence.
29
+
30
+ The review-gate-check protocol (§10.20.6) reads this execution.json and derives PASSED / FAILED /
31
+ UNVERIFIED from the evidence summary. Stories without an execution.json report UNVERIFIED (not FAILED)
32
+ for backward compatibility with pre-bridge workflows.
33
+ -->
11
34
  <step n="1" title="Load Story File">
12
35
  <action>Read story .md file, parse YAML frontmatter</action>
13
36
  <action>Extract: key, status, acceptance criteria, subtasks, dependencies</action>
@@ -351,9 +374,9 @@
351
374
  <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>
352
375
  <invoke-protocol ref="status-sync" story_key="{story_key}" new_status="review" source_workflow="dev-story" />
353
376
  <action>Append files changed list to story file</action>
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>
377
+ <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 UNVERIFIED with report link "—". If Review Gate section already exists, reset all rows to UNVERIFIED.</action>
355
378
  <template-output file="{implementation_artifacts}/{story_key}-*.md">
356
- Update story file with status change to 'review', list of files changed, and initialized Review Gate table (all 6 rows PENDING).
379
+ Update story file with status change to 'review', list of files changed, and initialized Review Gate table (all 6 rows UNVERIFIED).
357
380
  </template-output>
358
381
  </step>
359
382
  <step n="19" title="Auto-Run Reviews (YOLO only)">
@@ -10,7 +10,7 @@
10
10
  <action>Calculate: stories completed, stories invalid, stories carried over, velocity (points delivered vs planned)</action>
11
11
  <action>Read ALL story files for this sprint (from sprint-status.yaml story list). For each story extract:
12
12
  - Status (done, review, in-progress, invalid)
13
- - Review Gate table results (which reviews PASSED/FAILED/PENDING)
13
+ - Review Gate table results (which reviews UNVERIFIED/PASSED/FAILED)
14
14
  - Findings table (count and types of findings)
15
15
  - Definition of Done checklist results</action>
16
16
  <action>Read {memory_path}/validator-sidecar/decision-log.md — extract all entries for this sprint's stories (validation attempts, findings counts, pass/fail results)</action>
@@ -63,16 +63,139 @@
63
63
  <action>When subagent returns: read story file, check Performance Review row status. Log result.</action>
64
64
  </step>
65
65
 
66
- <step n="8" title="Review Summary and Status Transition">
67
- <action>Read story file — parse full Review Gate table</action>
68
- <action>Generate summary table: review name | verdict | report link</action>
69
- <action>If ALL 6 PASSED: invoke the review-gate-check protocol to evaluate DoD and transition story to 'done' if appropriate.</action>
70
- <action>If any FAILED:
71
- <invoke-protocol ref="status-sync" story_key="{story_key}" new_status="in-progress" source_workflow="run-all-reviews" />
72
- List failed reviews with report links. Report: "Story {story_key} moved to in-progress fix issues and re-run failed reviews."</action>
73
- <invoke-protocol name="review-gate-check" file="{project-root}/_gaia/core/protocols/review-gate-check.xml" />
66
+ <step n="8" title="Generate Review Summary and Transition Status">
67
+ <critical>
68
+ <mandate>This step MUST write the {story_key}-review-summary.md file BEFORE invoking the review-gate-check protocol. The protocol's hard gate (E17-S15 / A-050) checks that the summary exists as a prerequisite for the review→done transition — if the template-output is skipped or ordered after the protocol invocation, every story will HALT at the gate.</mandate>
69
+ <mandate>The summary file MUST aggregate the 6 review verdicts do NOT regenerate or re-run the reviews here. Read each review report's Review Gate row and consolidate.</mandate>
70
+ </critical>
71
+ <action>Read story file — parse the full Review Gate table. Extract each of the 6 rows: Code Review, QA Tests, Security Review, Test Automation, Test Review, Performance Review — with status (UNVERIFIED / PASSED / FAILED) and report link.</action>
72
+ <action>Resolve report paths for each review (used in the aggregate summary body):
73
+ - Code Review: {implementation_artifacts}/{story_key}-review.md
74
+ - Security Review: {implementation_artifacts}/{story_key}-security-review.md
75
+ - QA Tests: {test_artifacts}/{story_key}-qa-tests.md
76
+ - Test Automation: {test_artifacts}/{story_key}-test-automation.md
77
+ - Test Review: {test_artifacts}/{story_key}-test-review.md
78
+ - Performance Review: {implementation_artifacts}/{story_key}-performance-review.md</action>
79
+ <action>Compute overall_status: if ALL 6 rows show PASSED → overall_status = "PASSED". If ANY row shows FAILED → overall_status = "FAILED". If ANY row is still UNVERIFIED → overall_status = "INCOMPLETE".</action>
80
+ <action>Build the review-summary.md content and aggregate the verdicts using this exact schema (AC5). Frontmatter carries story_key, date, overall_status, and reviewers. The body has one section per review (verdict + report link + one-line synopsis) and a final aggregate Gate Status table:
81
+ ```
82
+ ---
83
+ story_key: {story_key}
84
+ date: {date}
85
+ overall_status: {overall_status}
86
+ reviewers: [code-review, qa-tests, security-review, test-automate, test-review, review-perf]
87
+ ---
88
+
89
+ # Review Summary: {story_key}
90
+
91
+ > Aggregate of the 6-review gate for {story_key}. This file does NOT regenerate reviews — it consolidates existing verdicts from the 6 individual review reports.
92
+
93
+ ## Code Review
94
+ **Verdict:** {code_review_status}
95
+ **Report:** [{code_review_report_relpath}]({code_review_report_relpath})
96
+ **Synopsis:** {one_line_synopsis_or_"See report for details"}
97
+
98
+ ## QA Tests
99
+ **Verdict:** {qa_tests_status}
100
+ **Report:** [{qa_tests_report_relpath}]({qa_tests_report_relpath})
101
+ **Synopsis:** {one_line_synopsis}
102
+
103
+ ## Security Review
104
+ **Verdict:** {security_review_status}
105
+ **Report:** [{security_review_report_relpath}]({security_review_report_relpath})
106
+ **Synopsis:** {one_line_synopsis}
107
+
108
+ ## Test Automation
109
+ **Verdict:** {test_automation_status}
110
+ **Report:** [{test_automation_report_relpath}]({test_automation_report_relpath})
111
+ **Synopsis:** {one_line_synopsis}
112
+
113
+ ## Test Review
114
+ **Verdict:** {test_review_status}
115
+ **Report:** [{test_review_report_relpath}]({test_review_report_relpath})
116
+ **Synopsis:** {one_line_synopsis}
117
+
118
+ ## Performance Review
119
+ **Verdict:** {performance_review_status}
120
+ **Report:** [{performance_review_report_relpath}]({performance_review_report_relpath})
121
+ **Synopsis:** {one_line_synopsis}
122
+
123
+ ## Aggregate Gate Status
124
+
125
+ | Review | Verdict | Report |
126
+ |---|---|---|
127
+ | Code Review | {code_review_status} | [link]({code_review_report_relpath}) |
128
+ | QA Tests | {qa_tests_status} | [link]({qa_tests_report_relpath}) |
129
+ | Security Review | {security_review_status} | [link]({security_review_report_relpath}) |
130
+ | Test Automation | {test_automation_status} | [link]({test_automation_report_relpath}) |
131
+ | Test Review | {test_review_status} | [link]({test_review_report_relpath}) |
132
+ | Performance Review | {performance_review_status} | [link]({performance_review_report_relpath}) |
133
+
134
+ **Overall Status:** {overall_status}
135
+ ```
136
+ </action>
74
137
  <template-output file="{implementation_artifacts}/{story_key}-review-summary.md">
75
- Generate review summary: story key, date, all 6 review verdicts with report links, final story status, and next actions if any reviews failed.
138
+ Write the aggregated review summary per the schema above. Frontmatter fields: story_key, date, overall_status, reviewers. Body: 6 review sections with verdict + report link + one-line synopsis, plus a final aggregate Gate Status table. This template-output MUST execute before the review-gate-check protocol invocation below so the hard gate can find the summary file.
76
139
  </template-output>
140
+ <action>After the summary file is written, handle the status transition:
141
+ - If ALL 6 PASSED: invoke the review-gate-check protocol to evaluate DoD and transition story to 'done' if appropriate. The protocol's hard gate will find the summary file we just wrote and pass.
142
+ - If any FAILED:
143
+ <invoke-protocol ref="status-sync" story_key="{story_key}" new_status="in-progress" source_workflow="run-all-reviews" />
144
+ List failed reviews with report links. Report: "Story {story_key} moved to in-progress — fix issues and re-run failed reviews."</action>
145
+ <action>PROGRESSIVE NUDGE BLOCK (E17-S3 / FR-193 / AC1-AC6): After the review summary file has been written and the status transition (if any) has been invoked, render a Progressive Nudge Block directly in the conversation. The nudge block is additive — it does not replace or block the existing completion output and the review summary template-output above. The nudge block MUST render in all execution modes (both normal and YOLO) — it is unconditional of execution_mode. The block has three parts:
146
+
147
+ 1. GATE SUMMARY TABLE — render a markdown table with columns (gate name, status, linked report) containing one row per review gate using the six rows previously parsed from the story's Review Gate table. The linked report column uses the resolved report paths resolved earlier in this step (code-review report, qa-tests report, security-review report, test-automation report, test-review report, performance-review report). Format the table as:
148
+
149
+ | Gate | Status | Report |
150
+ |---|---|---|
151
+ | Code Review | {code_review_status} | [report]({code_review_report_relpath}) |
152
+ | QA Tests | {qa_tests_status} | [report]({qa_tests_report_relpath}) |
153
+ | Security Review | {security_review_status} | [report]({security_review_report_relpath}) |
154
+ | Test Automation | {test_automation_status} | [report]({test_automation_report_relpath}) |
155
+ | Test Review | {test_review_status} | [report]({test_review_report_relpath}) |
156
+ | Performance Review | {performance_review_status} | [report]({performance_review_report_relpath}) |
157
+
158
+ 2. OVERALL OUTCOME LINE — classify the gate results using the same overall_status already computed for the review summary file and render one of three classification strings:
159
+ - "ALL PASSED" when all 6 rows are PASSED
160
+ - "N FAILED" when any row is FAILED (substitute N with the actual count of FAILED rows)
161
+ - "N UNVERIFIED" when no FAILED rows but at least one row is still UNVERIFIED (substitute N with the actual count of UNVERIFIED rows)
162
+ When both FAILED and UNVERIFIED rows exist, render both classification strings on separate lines (FAILED first) so the developer sees the full picture. Render as: "**Overall:** {classification(s)}".
163
+
164
+ 3. SUGGESTED NEXT COMMAND — based on the overall outcome, render exactly one "Suggested next:" line using the branching rules below. This is the progressive nudge payload that tells the developer exactly what to do next without re-reading gate documentation:
165
+
166
+ ALL PASSED BRANCH (AC2): When all 6 rows are PASSED, render "Suggested next: /gaia-check-review-gate {story_key}" to confirm the advancement to `done`. Substitute {story_key} with the actual story key.
167
+
168
+ FAILED BRANCH (AC3): When any row is FAILED, collect the failed gate names into a list and render:
169
+ "Failed gates: {comma-separated list of failed gate names}"
170
+ "Suggested next: /gaia-correct-course {story_key} — return to in-progress and fix the failed review(s)"
171
+
172
+ UNVERIFIED BRANCH (AC4): When no rows are FAILED but one or more rows are still at UNVERIFIED, collect the unrun (UNVERIFIED, not yet run) gate names and for each, render the individual review command that would run it. The six canonical per-gate commands are:
173
+ - Code Review → /gaia-code-review {story_key}
174
+ - QA Tests → /gaia-qa-tests {story_key}
175
+ - Security Review → /gaia-security-review {story_key}
176
+ - Test Automation → /gaia-test-automate {story_key}
177
+ - Test Review → /gaia-test-review {story_key}
178
+ - Performance Review → /gaia-review-perf {story_key}
179
+ Render:
180
+ "Unrun gates ({count}): {comma-separated list of unrun gate names}"
181
+ "Suggested next: run the following review(s) individually:"
182
+ followed by a bulleted list of the matching commands above, one per unrun gate.
183
+
184
+ MIXED BRANCH: If the run has both FAILED and UNVERIFIED rows, the FAILED branch takes precedence for the "Suggested next:" line (correct-course is more urgent than re-running unrun reviews), but still list the unrun gates under an "Also unrun:" label so the developer can address both.
185
+
186
+ NUDGE BLOCK RENDER TEMPLATE — wrap the three parts in a visually distinct block so it is easy to spot in the conversation:
187
+
188
+ ```
189
+ --- Review Gate Nudge ---
190
+ {gate summary table}
191
+
192
+ **Overall:** {classification}
193
+
194
+ {suggested next section based on branch}
195
+ ---
196
+ ```
197
+
198
+ The nudge MUST be rendered regardless of whether the status transition above succeeded — even if the review-gate-check protocol advanced the story to done, the nudge still shows the final gate state and the /gaia-check-review-gate suggestion for transparency. The nudge is additive to existing output — it does not remove, replace, or block the review summary template-output, the status transition, or the review-gate-check protocol invocation.</action>
199
+ <invoke-protocol name="review-gate-check" file="{project-root}/_gaia/core/protocols/review-gate-check.xml" />
77
200
  </step>
78
201
  </workflow>
@@ -25,5 +25,7 @@ required-inputs:
25
25
  - [ ] If PASSED: Security Review row shows PASSED with report link
26
26
  - [ ] If FAILED: Security Review row shows FAILED, story status set to in-progress
27
27
  - [ ] Review gate check protocol invoked
28
+ ## Bridge Security
29
+ - [ ] Bridge remote executors MUST use argv-array spawn with `shell: false`
28
30
  ## Output Verification
29
31
  - [ ] Report generated with findings table