mirror of
https://github.com/LerianStudio/ring
synced 2026-04-21 21:47:49 +00:00
Reclassify gates 1,2,4,5,6w,7w,8 (backend) and 1,2,4,5,6,7 (frontend) from subtask to task cadence. Gates 0, 3, 9 remain subtask-level. All 8 reviewers still run, all quality thresholds preserved. Additional changes: standards pre-cache at Step 1.5 (cached_standards in state); Gate 0.5 merged into Gate 0 exit criteria via ring:dev-implementation Step 7; dev-report aggregates cycle-wide via accumulated_metrics (single cycle-end dispatch); dev-refactor clusters findings by (file, pattern_category) with findings:[] traceability array; read-after-write state verification removed; per-subtask visual reports opt-in only. State schema v1.1.0 (additive - backward compatible). New shared patterns: standards-cache-protocol.md, gate-cadence-classification.md. X-Lerian-Ref: 0x1
599 lines
18 KiB
Markdown
599 lines
18 KiB
Markdown
---
|
|
name: ring:dev-unit-testing
|
|
description: |
|
|
Gate 3 of development cycle - ensures unit test coverage meets threshold (85%+)
|
|
for all acceptance criteria using TDD methodology.
|
|
|
|
trigger: |
|
|
- After implementation and SRE complete (Gate 0/1/2)
|
|
- Task has acceptance criteria requiring test coverage
|
|
- Need to verify implementation meets requirements
|
|
|
|
skip_when: |
|
|
- Not inside a development cycle (ring:dev-cycle)
|
|
- Task is documentation-only, configuration-only, or non-code
|
|
- No code implementation was produced (nothing to test)
|
|
- Changes are limited to CI/CD, infrastructure, or deployment configuration
|
|
|
|
NOT_skip_when: |
|
|
- "Manual testing validates all criteria" → Manual tests are not executable. Gate 3 requires unit tests.
|
|
- "Integration tests are better" → Gate 3 scope is unit tests only.
|
|
- "Coverage is close to 85%" → Close enough is not passing. Meet exact threshold.
|
|
|
|
sequence:
|
|
after: [ring:dev-implementation, ring:dev-devops, ring:dev-ring:sre]
|
|
before: [ring:codereview]
|
|
|
|
related:
|
|
complementary: [ring:test-driven-development, ring:qa-analyst]
|
|
|
|
input_schema:
|
|
required:
|
|
- name: unit_id
|
|
type: string
|
|
description: "Task or subtask identifier"
|
|
- name: acceptance_criteria
|
|
type: array
|
|
items: string
|
|
description: "List of acceptance criteria to test"
|
|
- name: implementation_files
|
|
type: array
|
|
items: string
|
|
description: "Files from Gate 0 implementation"
|
|
- name: language
|
|
type: string
|
|
enum: [go, typescript, python]
|
|
description: "Programming language"
|
|
optional:
|
|
- name: coverage_threshold
|
|
type: float
|
|
default: 85.0
|
|
description: "Minimum coverage percentage (cannot be below 85)"
|
|
- name: gate0_handoff
|
|
type: object
|
|
description: "Full handoff from Gate 0"
|
|
- name: existing_tests
|
|
type: array
|
|
items: string
|
|
description: "Existing test files"
|
|
|
|
output_schema:
|
|
format: markdown
|
|
required_sections:
|
|
- name: "Testing Summary"
|
|
pattern: "^## Testing Summary"
|
|
required: true
|
|
- name: "Coverage Report"
|
|
pattern: "^## Coverage Report"
|
|
required: true
|
|
- name: "Traceability Matrix"
|
|
pattern: "^## Traceability Matrix"
|
|
required: true
|
|
- name: "Handoff to Next Gate"
|
|
pattern: "^## Handoff to Next Gate"
|
|
required: true
|
|
metrics:
|
|
- name: result
|
|
type: enum
|
|
values: [PASS, FAIL]
|
|
- name: coverage_actual
|
|
type: float
|
|
- name: coverage_threshold
|
|
type: float
|
|
- name: tests_written
|
|
type: integer
|
|
- name: criteria_covered
|
|
type: string
|
|
description: "X/Y format"
|
|
- name: iterations
|
|
type: integer
|
|
|
|
verification:
|
|
automated:
|
|
- command: "go test ./... -covermode=atomic -coverprofile=coverage.out && go tool cover -func=coverage.out | grep total"
|
|
description: "Go tests pass with coverage"
|
|
success_pattern: 'total:.*[8-9][0-9]|100'
|
|
- command: "npm test -- --coverage | grep -E 'All files|Statements'"
|
|
description: "TypeScript tests pass with coverage"
|
|
success_pattern: '[8-9][0-9]|100'
|
|
manual:
|
|
- "Every acceptance criterion has at least one test"
|
|
- "No skipped or pending tests"
|
|
|
|
---
|
|
|
|
# Dev Unit Testing (Gate 3)
|
|
|
|
## Overview
|
|
|
|
Ensure every acceptance criterion has at least one **unit test** proving it works. Follow TDD methodology: RED (failing test) -> GREEN (implementation) -> REFACTOR.
|
|
|
|
**Core principle:** Untested acceptance criteria are unverified claims. Each criterion MUST map to at least one executable unit test.
|
|
|
|
<block_condition>
|
|
- Coverage below 85% = FAIL
|
|
- Any acceptance criterion without test = FAIL
|
|
</block_condition>
|
|
|
|
**Coverage threshold:** 85% minimum (Ring standard). PROJECT_RULES.md can raise, not lower.
|
|
|
|
## CRITICAL: Role Clarification
|
|
|
|
**This skill ORCHESTRATES. QA Analyst Agent EXECUTES.**
|
|
|
|
| Who | Responsibility |
|
|
|-----|----------------|
|
|
| **This Skill** | Gather requirements, dispatch agent, track iterations |
|
|
| **QA Analyst Agent** | Write tests, run coverage, report results |
|
|
|
|
---
|
|
|
|
## Step 1: Validate Input
|
|
|
|
```text
|
|
REQUIRED INPUT (from ring:dev-cycle orchestrator):
|
|
<verify_before_proceed>
|
|
- unit_id exists
|
|
- acceptance_criteria is not empty
|
|
- implementation_files is not empty
|
|
- language is valid (go|typescript|python)
|
|
</verify_before_proceed>
|
|
|
|
```text
|
|
- unit_id: [task/subtask being tested]
|
|
- acceptance_criteria: [list of ACs to test]
|
|
- implementation_files: [files from Gate 0]
|
|
- language: [go|typescript|python]
|
|
|
|
OPTIONAL INPUT:
|
|
- coverage_threshold: [default 85.0, cannot be lower]
|
|
- gate0_handoff: [full Gate 0 output]
|
|
- existing_tests: [existing test files]
|
|
|
|
if any REQUIRED input is missing:
|
|
→ STOP and report: "Missing required input: [field]"
|
|
→ Return to orchestrator with error
|
|
|
|
if coverage_threshold < 85:
|
|
→ STOP and report: "Coverage threshold cannot be below Ring minimum (85%)"
|
|
→ Use 85% as threshold
|
|
```
|
|
|
|
## Step 2: Initialize Testing State
|
|
|
|
```text
|
|
testing_state = {
|
|
unit_id: [from input],
|
|
coverage_threshold: max(85, [from input]),
|
|
coverage_actual: null,
|
|
verdict: null,
|
|
iterations: 0,
|
|
max_iterations: 3,
|
|
traceability_matrix: [],
|
|
tests_written: 0,
|
|
# Goroutine leak detection (Go only)
|
|
goroutine_check: null, # NOT_APPLICABLE | REQUIRED
|
|
goroutine_files: 0, # Count of files with goroutines
|
|
goleak_coverage: null, # "X/Y" packages with goleak
|
|
leaks_detected: 0, # Count of actual leaks
|
|
goroutine_verdict: null # PASS | NEEDS_ACTION | FAIL
|
|
}
|
|
```
|
|
|
|
## Step 3: Dispatch QA Analyst Agent
|
|
|
|
<dispatch_required agent="ring:qa-analyst">
|
|
Write unit tests for all acceptance criteria with 85%+ coverage.
|
|
</dispatch_required>
|
|
|
|
```yaml
|
|
Task:
|
|
subagent_type: "ring:qa-analyst"
|
|
description: "Write unit tests for [unit_id]"
|
|
prompt: |
|
|
⛔ WRITE UNIT TESTS for All Acceptance Criteria
|
|
|
|
## Input Context
|
|
- **Unit ID:** [unit_id]
|
|
- **Language:** [language]
|
|
- **Coverage Threshold:** [coverage_threshold]%
|
|
|
|
## Acceptance Criteria to Test
|
|
[list acceptance_criteria with AC-1, AC-2, etc.]
|
|
|
|
## Implementation Files to Test
|
|
[list implementation_files]
|
|
|
|
## Standards Source (Cache-First Pattern)
|
|
|
|
**Standards Source (Cache-First Pattern):** This sub-skill reads standards from `state.cached_standards` populated by dev-cycle Step 1.5. If invoked outside a cycle (standalone), it falls back to direct WebFetch with a warning. See `shared-patterns/standards-cache-protocol.md` for protocol details.
|
|
|
|
## Standards Reference
|
|
|
|
For Go: https://raw.githubusercontent.com/LerianStudio/ring/main/dev-team/docs/standards/golang.md
|
|
For TS: https://raw.githubusercontent.com/LerianStudio/ring/main/dev-team/docs/standards/typescript.md
|
|
|
|
**Cache-first loading protocol:**
|
|
For each required standards URL:
|
|
IF state.cached_standards[url] exists:
|
|
→ Read content from state.cached_standards[url].content
|
|
→ Log: "Using cached standard: {url} (fetched {state.cached_standards[url].fetched_at})"
|
|
ELSE:
|
|
→ WebFetch url (fallback — should not happen if orchestrator ran Step 1.5)
|
|
→ Log warning: "Standard {url} was not pre-cached; fetched inline"
|
|
|
|
Focus on: Testing Patterns section
|
|
|
|
## Requirements
|
|
|
|
### Test Coverage
|
|
- Minimum: [coverage_threshold]% branch coverage
|
|
- Every AC MUST have at least one test
|
|
- Edge cases REQUIRED (null, empty, boundary, error conditions)
|
|
|
|
### Test Naming
|
|
- Go: `Test{Unit}_{Method}_{Scenario}`
|
|
- TS: `describe('{Unit}', () => { it('should {scenario}', ...) })`
|
|
|
|
### Test Structure
|
|
- One behavior per test
|
|
- Arrange-Act-Assert pattern
|
|
- Mock all external dependencies
|
|
- no database/API calls (unit tests only)
|
|
|
|
### Edge Cases Required per AC Type
|
|
|
|
<cannot_skip>
|
|
- Minimum 3 edge cases per AC type
|
|
- null, empty, boundary conditions required
|
|
- Error conditions required
|
|
</cannot_skip>
|
|
|
|
| AC Type | Required Edge Cases | Minimum |
|
|
|---------|---------------------|---------|
|
|
| Input validation | null, empty, boundary, invalid format | 3+ |
|
|
| CRUD operations | not found, duplicate, concurrent | 3+ |
|
|
| Business logic | zero, negative, overflow, boundary | 3+ |
|
|
| Error handling | timeout, connection failure, retry | 2+ |
|
|
|
|
### Multi-Tenant Dual-Mode Testing (Go backend only)
|
|
|
|
Every repository/service test that accesses a resource (PostgreSQL, MongoDB, Redis, S3, RabbitMQ) must verify BOTH modes. The resolvers in lib-commons v4 work transparently — the same code path handles both modes. Tests verify this contract.
|
|
|
|
**Required pattern:** Add dual-mode sub-tests for any test that touches a resource:
|
|
|
|
```go
|
|
func TestCreateAccount(t *testing.T) {
|
|
modes := []struct {
|
|
name string
|
|
multiTenant string
|
|
}{
|
|
{"single-tenant", "false"},
|
|
{"multi-tenant", "true"},
|
|
}
|
|
for _, mode := range modes {
|
|
t.Run(mode.name, func(t *testing.T) {
|
|
t.Setenv("MULTI_TENANT_ENABLED", mode.multiTenant)
|
|
// ... same test logic, same assertions
|
|
// Resolvers handle the connection routing transparently
|
|
})
|
|
}
|
|
}
|
|
```
|
|
|
|
**What to verify in multi-tenant mode:**
|
|
- Context contains tenant ID → resolver returns tenant-specific connection
|
|
- Context WITHOUT tenant ID → resolver returns error (not default connection)
|
|
- Backward compat: no MULTI_TENANT_* env vars → works as single-tenant
|
|
|
|
**What does NOT need dual-mode tests:**
|
|
- Pure business logic (no resource access)
|
|
- Utility/helper functions
|
|
- Frontend/TypeScript tests
|
|
|
|
## Required Output Format
|
|
|
|
### Test Files Created
|
|
| File | Tests | Lines |
|
|
|------|-------|-------|
|
|
| [path] | [count] | +N |
|
|
|
|
### Coverage Report
|
|
**Command:** [coverage command]
|
|
**Result:**
|
|
```
|
|
[paste actual coverage output]
|
|
```
|
|
|
|
| Package/File | Coverage |
|
|
|--------------|----------|
|
|
| [name] | [X%] |
|
|
| **TOTAL** | **[X%]** |
|
|
|
|
### Traceability Matrix
|
|
| AC ID | Criterion | Test File | Test Function | Status |
|
|
|-------|-----------|-----------|---------------|--------|
|
|
| AC-1 | [criterion text] | [file] | [function] | ✅/❌ |
|
|
| AC-2 | [criterion text] | [file] | [function] | ✅/❌ |
|
|
|
|
### Quality Checks
|
|
| Check | Status |
|
|
|-------|--------|
|
|
| No skipped tests | ✅/❌ |
|
|
| No assertion-less tests | ✅/❌ |
|
|
| Edge cases per AC | ✅/❌ |
|
|
| Test isolation | ✅/❌ |
|
|
|
|
### VERDICT
|
|
**Coverage:** [X%] vs Threshold [Y%]
|
|
**VERDICT:** PASS / FAIL
|
|
|
|
If FAIL:
|
|
- **Gap Analysis:** [what needs more tests]
|
|
- **Files needing coverage:** [list with line numbers]
|
|
```
|
|
|
|
## Step 3.5: Goroutine Leak Detection (Go only)
|
|
|
|
**⛔ CONDITIONAL: Only execute if `language == "go"`**
|
|
|
|
After unit tests pass, detect goroutine usage and verify goleak coverage.
|
|
|
|
See [ring:dev-goroutine-leak-testing](../dev-goroutine-leak-testing/SKILL.md) for full detection patterns and dispatch templates.
|
|
See [architecture.md](../../docs/standards/golang/architecture.md#goroutine-leak-detection-mandatory) for goleak standards.
|
|
|
|
### Detection Logic
|
|
|
|
```text
|
|
if language != "go":
|
|
→ Skip to Step 4
|
|
|
|
# Detect goroutine patterns: "go func(", "go methodCall("
|
|
if no goroutine patterns found:
|
|
→ testing_state.goroutine_check = "NOT_APPLICABLE"
|
|
→ Skip to Step 4
|
|
|
|
# Goroutines detected
|
|
→ testing_state.goroutine_check = "REQUIRED"
|
|
→ Dispatch ring:qa-analyst with test_mode="goroutine-leak"
|
|
```
|
|
|
|
### Dispatch
|
|
|
|
<dispatch_required agent="ring:qa-analyst" test_mode="goroutine-leak">
|
|
MUST dispatch with test_mode="goroutine-leak" to detect leaks and verify goleak coverage.
|
|
</dispatch_required>
|
|
|
|
### Parse Output and Handle Verdict
|
|
|
|
| Verdict | Action |
|
|
|---------|--------|
|
|
| PASS | Proceed to Step 4 |
|
|
| NEEDS_ACTION | Dispatch `ring:backend-engineer-golang` to add goleak tests, re-run |
|
|
| FAIL | Dispatch `ring:backend-engineer-golang` to fix leaks, re-run |
|
|
|
|
---
|
|
|
|
## Step 4: Parse QA Analyst Output
|
|
|
|
```text
|
|
Parse agent output:
|
|
|
|
1. Extract coverage percentage from Coverage Report
|
|
2. Extract traceability matrix
|
|
3. Extract verdict
|
|
|
|
testing_state.coverage_actual = [extracted coverage]
|
|
testing_state.traceability_matrix = [extracted matrix]
|
|
testing_state.tests_written = [count from Test Files Created]
|
|
|
|
if verdict == "PASS" and coverage_actual >= coverage_threshold:
|
|
→ testing_state.verdict = "PASS"
|
|
→ Proceed to Step 6
|
|
|
|
if verdict == "FAIL" or coverage_actual < coverage_threshold:
|
|
→ testing_state.verdict = "FAIL"
|
|
→ testing_state.iterations += 1
|
|
→ if iterations >= max_iterations: Go to Step 7 (Escalate)
|
|
→ Go to Step 5 (Dispatch Fix)
|
|
```
|
|
|
|
## Step 5: Dispatch Fix to Implementation Agent
|
|
|
|
**Coverage below threshold → Return to Gate 0 for more tests**
|
|
|
|
```yaml
|
|
Task:
|
|
subagent_type: "[implementation_agent from Gate 0]" # e.g., "ring:backend-engineer-golang"
|
|
description: "Add tests to meet coverage threshold for [unit_id]"
|
|
prompt: |
|
|
⛔ COVERAGE BELOW THRESHOLD - Add More Tests
|
|
|
|
## Current Status
|
|
- **Coverage Actual:** [coverage_actual]%
|
|
- **Coverage Threshold:** [coverage_threshold]%
|
|
- **Gap:** [threshold - actual]%
|
|
- **Iteration:** [iterations] of [max_iterations]
|
|
|
|
## Gap Analysis (from QA)
|
|
[paste gap analysis from QA output]
|
|
|
|
## Files Needing Coverage
|
|
[paste files list from QA output]
|
|
|
|
## Requirements
|
|
1. Add tests to cover the identified gaps
|
|
2. Focus on edge cases and error paths
|
|
3. Run coverage after each addition
|
|
4. Stop when coverage >= [threshold]%
|
|
|
|
## Required Output
|
|
- Tests added: [list]
|
|
- New coverage: [X%]
|
|
- Coverage command output
|
|
```
|
|
|
|
After fix → Go back to Step 3 (Re-dispatch QA Analyst)
|
|
|
|
## Step 6: Prepare Success Output
|
|
|
|
```text
|
|
Generate skill output:
|
|
|
|
## Testing Summary
|
|
**Status:** PASS
|
|
**Unit ID:** [unit_id]
|
|
**Iterations:** [testing_state.iterations]
|
|
|
|
## Coverage Report
|
|
**Threshold:** [coverage_threshold]%
|
|
**Actual:** [coverage_actual]%
|
|
**Status:** ✅ PASS
|
|
|
|
| Package/File | Coverage |
|
|
|--------------|----------|
|
|
[from QA output]
|
|
| **TOTAL** | **[coverage_actual]%** |
|
|
|
|
## Traceability Matrix
|
|
| AC ID | Criterion | Test | Status |
|
|
|-------|-----------|------|--------|
|
|
[from testing_state.traceability_matrix]
|
|
|
|
**Criteria Covered:** [X]/[Y] (100%)
|
|
|
|
## Quality Checks
|
|
| Check | Status |
|
|
|-------|--------|
|
|
| Coverage ≥ threshold | ✅ |
|
|
| All ACs tested | ✅ |
|
|
| No skipped tests | ✅ |
|
|
| Edge cases present | ✅ |
|
|
| Goroutine leak check (Go only) | [✅/N/A] |
|
|
|
|
## Goroutine Leak Report (Go only)
|
|
[If language == "go" and goroutines detected]
|
|
|
|
| Metric | Value |
|
|
|--------|-------|
|
|
| Goroutines detected | [count] |
|
|
| Packages with goleak | [X]/[Y] |
|
|
| Leaks found | 0 |
|
|
| Status | ✅ PASS |
|
|
|
|
[If language != "go" or no goroutines: "N/A - No goroutines detected"]
|
|
|
|
## Handoff to Next Gate
|
|
- Testing status: COMPLETE
|
|
- Coverage: [coverage_actual]% (threshold: [coverage_threshold]%)
|
|
- All criteria tested: ✅
|
|
- Ready for Gate 4 (Review): YES
|
|
```
|
|
|
|
## Step 7: Escalate - Max Iterations Reached
|
|
|
|
```text
|
|
Generate skill output:
|
|
|
|
## Testing Summary
|
|
**Status:** FAIL
|
|
**Unit ID:** [unit_id]
|
|
**Iterations:** [max_iterations] (MAX REACHED)
|
|
|
|
## Coverage Report
|
|
**Threshold:** [coverage_threshold]%
|
|
**Actual:** [coverage_actual]%
|
|
**Gap:** [threshold - actual]%
|
|
**Status:** ❌ FAIL
|
|
|
|
## Gap Analysis
|
|
[from last QA output]
|
|
|
|
## Files Still Needing Coverage
|
|
[from last QA output]
|
|
|
|
## Handoff to Next Gate
|
|
- Testing status: FAILED
|
|
- Ready for Gate 4: no
|
|
- **Action Required:** User must manually add tests or adjust scope
|
|
|
|
⛔ ESCALATION: Max iterations (3) reached. Coverage still below threshold.
|
|
User intervention required.
|
|
```
|
|
|
|
---
|
|
|
|
## Severity Calibration
|
|
|
|
| Severity | Criteria | Examples |
|
|
|----------|----------|----------|
|
|
| **CRITICAL** | Test infrastructure broken, no coverage possible | Test framework failure, build broken |
|
|
| **HIGH** | Coverage below threshold, missing AC tests | 84% coverage (below 85%), untested acceptance criteria |
|
|
| **MEDIUM** | Test quality issues, edge case gaps | Missing edge case tests, poor assertion messages |
|
|
| **LOW** | Test naming, documentation gaps | Non-standard test names, missing test descriptions |
|
|
|
|
Report all severities. CRITICAL/HIGH = immediate fix. MEDIUM = fix in iteration. LOW = document for follow-up.
|
|
|
|
---
|
|
|
|
## Pressure Resistance
|
|
|
|
See [shared-patterns/shared-pressure-resistance.md](../shared-patterns/shared-pressure-resistance.md) for universal pressure scenarios.
|
|
|
|
| User Says | Your Response |
|
|
|-----------|---------------|
|
|
| "84% is close enough" | "85% is minimum threshold. 84% = FAIL. Adding more tests." |
|
|
| "Manual testing covers it" | "Gate 3 requires executable unit tests. Dispatching QA analyst." |
|
|
| "Skip testing, deadline" | "Testing is MANDATORY. Untested code = unverified claims." |
|
|
|
|
---
|
|
|
|
## Anti-Rationalization Table
|
|
|
|
See [shared-patterns/shared-anti-rationalization.md](../shared-patterns/shared-anti-rationalization.md) for universal anti-rationalizations.
|
|
|
|
### Gate 3-Specific Anti-Rationalizations
|
|
|
|
| Rationalization | Why It's WRONG | Required Action |
|
|
|-----------------|----------------|-----------------|
|
|
| "Tool shows 83% but real is 90%" | Tool output IS real. Your belief is not. | **Fix issue, re-measure** |
|
|
| "Excluding dead code gets us to 85%" | Delete dead code, don't exclude it. | **Delete dead code** |
|
|
| "84.5% rounds to 85%" | Rounding is not allowed. 84.5% < 85%. | **Write more tests** |
|
|
| "Close enough with all AC tested" | "Close enough" is not passing. | **Meet exact threshold** |
|
|
| "Integration tests cover this" | Gate 3 = unit tests only. Different scope. | **Write unit tests** |
|
|
|
|
## Unit Test vs Integration Test
|
|
|
|
| Type | Characteristics | Gate 3? |
|
|
|------|----------------|---------|
|
|
| **Unit** ✅ | Mocks all external deps, tests single function | YES |
|
|
| **Integration** ❌ | Hits real database/API/filesystem | no |
|
|
|
|
---
|
|
|
|
## Execution Report Format
|
|
|
|
```markdown
|
|
## Testing Summary
|
|
**Status:** [PASS|FAIL]
|
|
**Unit ID:** [unit_id]
|
|
**Duration:** [Xm Ys]
|
|
**Iterations:** [N]
|
|
|
|
## Coverage Report
|
|
**Threshold:** [X%]
|
|
**Actual:** [Y%]
|
|
**Status:** [✅ PASS | ❌ FAIL]
|
|
|
|
## Traceability Matrix
|
|
| AC ID | Criterion | Test | Status |
|
|
|-------|-----------|------|--------|
|
|
| AC-1 | [text] | [test] | ✅/❌ |
|
|
|
|
**Criteria Covered:** [X/Y]
|
|
|
|
## Handoff to Next Gate
|
|
- Testing status: [COMPLETE|FAILED]
|
|
- Coverage: [X%]
|
|
- Ready for Gate 4: [YES|no]
|
|
```
|