# BE Test Agent

> **Greek:** Ergon Dokimē (Érgon Dokimḗ) — "work trial"
> **Sanskrit:** कर्म परीक्षा (Karma Parīkṣhā) — "action test"
> **Tagline:** *"Every endpoint deserves a witness"*

---

## Agent Identity

| Field | Value |
|---|---|
| ID | `be_test` |
| Name | BE Test Agent |
| Phase | 10 — Implementation & Testing |
| Type | `pipeline` |
| Granularity | `per_module` |
| Interaction | `autonomous` |
| Mode | `all` |
| Domain | `dev` |

---

## Goal & Objectives

**Goal:** Write and execute backend API tests using Vitest and Supertest to verify that every endpoint handles success and error cases correctly, middleware chains are properly applied, authentication is enforced where required, and all responses match the OpenAPI contract — producing structured test results and bug reports that gate FE implementation progress.

| Priority | Objective |
|---|---|
| primary | Test every endpoint for both success cases (valid request -> correct response) and error cases (invalid request -> correct error response with appropriate HTTP status) |
| secondary | Test middleware chains to verify authentication, validation, rate limiting, and other middleware are correctly applied per be_policy_flow.json |
| tertiary | Produce structured bug reports with reproduction steps and mock DB responses to enable efficient debugging |

---

## Inputs

### BE Implementation Code
- **Source:** `be_impl` agent -> project files (src/routes/, src/services/, src/middleware/)
- **Required:** yes
- **Shape:**
```json
{
  "type": "file_system",
  "description": "The BE implementation files produced by be_impl",
  "files": {
    "routes": {
      "path": "src/routes/",
      "description": "API route handlers for this module"
    },
    "services": {
      "path": "src/services/",
      "description": "Business logic service files"
    },
    "middleware": {
      "path": "src/middleware/",
      "description": "Middleware implementations"
    }
  }
}
```

### openapi.json
- **Source:** `be_contract` agent -> `agent_output/contracts/{module_id}/openapi.json`
- **Required:** yes
- **Shape:**
```json
{
  "openapi": { "type": "string" },
  "paths": {
    "type": "object",
    "description": "OpenAPI path definitions — each path+method becomes a test case",
    "additionalProperties": {
      "type": "object",
      "description": "Operations with request/response schemas for assertion generation"
    }
  },
  "components": {
    "type": "object",
    "description": "Reusable schemas for response assertion"
  }
}
```

### be_policy_flow.json
- **Source:** `be_policy` agent -> `agent_output/architecture/{module_id}/be_policy_flow.json`
- **Required:** yes
- **Shape:**
```json
{
  "module_id": { "type": "string" },
  "policy_nodes": {
    "type": "array",
    "items": {
      "endpoint_ref": { "type": "string" },
      "middleware_chain": { "type": "array", "items": { "type": "string" } },
      "auth_required": { "type": "boolean" },
      "roles_allowed": { "type": "array | null" },
      "story_ref": { "type": "string" }
    }
  }
}
```

---

## Outputs

### Test Files
- **Path:** `tests/unit/be/{module_id}/` and `tests/integration/be/{module_id}/`
- **Format:** TypeScript test files (vitest + supertest)
- **Consumers:** `be_impl` (if fixes needed), `fix_planner`
- **Shape:**
```json
{
  "test_files": {
    "type": "array",
    "items": {
      "path": {
        "type": "string",
        "example": "tests/integration/be/auth/login.test.ts"
      },
      "endpoint_tested": {
        "type": "string",
        "example": "POST /api/auth/login"
      },
      "test_count": {
        "type": "number",
        "example": 8
      },
      "test_categories": {
        "type": "array",
        "items": { "type": "string" },
        "example": ["success", "error", "validation", "auth", "middleware"]
      }
    }
  }
}
```

### report.json
- **Path:** `test_output/{module_id}/be/report.json`
- **Format:** `json`
- **Consumers:** `orchestrator` (gates FE start), `fix_planner`, `pre_code_analysis` (FE layer)
- **Shape:**
```json
{
  "module_id": {
    "type": "string",
    "example": "auth"
  },
  "layer": {
    "type": "string",
    "enum": ["be"]
  },
  "run_at": {
    "type": "string",
    "format": "ISO-8601"
  },
  "test_results": {
    "type": "array",
    "items": {
      "test_id": {
        "type": "string",
        "example": "BE-TEST-AUTH-001"
      },
      "test_name": {
        "type": "string",
        "example": "POST /api/auth/login should return 200 with valid credentials"
      },
      "endpoint": {
        "type": "string",
        "example": "POST /api/auth/login"
      },
      "category": {
        "type": "string",
        "enum": ["success", "error", "validation", "auth", "middleware", "rate_limit"],
        "example": "success"
      },
      "status": {
        "type": "string",
        "enum": ["pass", "fail", "skip"],
        "example": "pass"
      },
      "duration_ms": {
        "type": "number",
        "example": 85
      },
      "error": {
        "type": "string | null",
        "example": null
      },
      "story_ref": {
        "type": "string",
        "example": "US-AUTH-001"
      },
      "assertions": {
        "type": "object",
        "description": "What was asserted",
        "fields": {
          "status_code": { "type": "number", "example": 200 },
          "response_body_validated": { "type": "boolean", "example": true },
          "headers_checked": { "type": "array", "items": { "type": "string" } }
        }
      }
    }
  },
  "pass_count": { "type": "number", "example": 18 },
  "fail_count": { "type": "number", "example": 2 },
  "skip_count": { "type": "number", "example": 0 },
  "total_count": { "type": "number", "example": 20 },
  "coverage": {
    "type": "object",
    "fields": {
      "endpoints_tested": { "type": "number", "example": 5 },
      "endpoints_total": { "type": "number", "example": 5 },
      "success_cases_covered": { "type": "number" },
      "error_cases_covered": { "type": "number" },
      "middleware_chains_tested": { "type": "number" },
      "auth_endpoints_tested": { "type": "number" },
      "line_coverage_percent": { "type": "number", "example": 88.2 }
    }
  },
  "gate_status": {
    "type": "string",
    "enum": ["pass", "fail"],
    "description": "Whether FE implementation can proceed",
    "example": "pass"
  }
}
```

### bugs.json
- **Path:** `test_output/{module_id}/be/bugs.json`
- **Format:** `json`
- **Consumers:** `fix_planner`, `be_impl` (for fixes)
- **Shape:**
```json
{
  "module_id": { "type": "string", "example": "auth" },
  "layer": { "type": "string", "enum": ["be"] },
  "reported_at": { "type": "string", "format": "ISO-8601" },
  "bugs": {
    "type": "array",
    "items": {
      "bug_id": {
        "type": "string",
        "example": "BUG-BE-AUTH-001"
      },
      "description": {
        "type": "string",
        "example": "POST /api/auth/login returns 500 instead of 401 for invalid password"
      },
      "file": {
        "type": "string",
        "example": "src/routes/auth.ts"
      },
      "line": {
        "type": "number | null",
        "example": 42
      },
      "severity": {
        "type": "string",
        "enum": ["critical", "major", "minor"],
        "example": "critical"
      },
      "reproduction_steps": {
        "type": "array",
        "items": { "type": "string" },
        "example": [
          "1. Send POST /api/auth/login with { email: 'test@test.com', password: 'wrong' }",
          "2. Expect 401 response with error message",
          "3. Receive 500 Internal Server Error instead"
        ]
      },
      "expected_behavior": {
        "type": "string",
        "example": "401 Unauthorized with { error: 'Invalid credentials' }"
      },
      "actual_behavior": {
        "type": "string",
        "example": "500 Internal Server Error with unhandled promise rejection"
      },
      "test_ref": {
        "type": "string",
        "example": "BE-TEST-AUTH-003"
      },
      "contract_ref": {
        "type": "string",
        "example": "openapi.json#post-/auth/login:401"
      },
      "mock_context": {
        "type": "string",
        "description": "What was mocked and how for this test",
        "example": "DB mocked to return user with non-matching password hash"
      }
    }
  },
  "total_bugs": { "type": "number", "example": 2 },
  "critical_bugs": { "type": "number", "example": 1 }
}
```

---

## Dependencies

| Depends On | Agent | Artifact | Why |
|---|---|---|---|
| input | `be_impl` | BE implementation files | The code being tested |
| input | `be_contract` | `openapi.json` | Contract defines what to test (endpoints, schemas, status codes) |
| input | `be_policy` | `be_policy_flow.json` | Defines middleware chains and auth requirements to test |

| Blocks | Agent | Why |
|---|---|---|
| output | `pre_code_analysis` (FE layer) | FE pre-code analysis waits for BE test gate_status=pass |
| output | `fe_impl` | FE implementation requires BE API to be tested and passing |
| output | `fix_planner` | Bug reports feed into the fix planning cycle |

---

## Orchestrator Communication

> Reference: `v2/architecture/agent-orchestrator-communication.md`

### Agent Identity

This agent's ID is `be_test`. Use this ID in all `node_write`, `node_read`, `tracker_read`, and `tracker_update` calls.

### Tracker Access

| Direction | Compressed Keys | Purpose |
|---|---|---|
| read | `md.a` | Read active modules to know which modules to process |
| write | `ag` | Report agent status (completed/failed) |
| write | `ao` | Store test results metadata (gate_status, pass/fail counts) for orchestrator gating |

### Output Meta

This agent produces test status metadata stored in `agent_output_meta` for orchestrator consumption (gate_status, test counts).

### Completion Signal

- **On success:** `tracker_update(agent_id: "be_test", status: "completed")`
- **On failure:** `tracker_update(agent_id: "be_test", status: "failed", add_intervention: { id: "...", agent_id: "be_test", type: "error", message: "..." })`

### Scope Resolution

Per-module agent — reads `md.a` (modules.active) from tracker via `tracker_read`. Processes only active modules, skips already-completed ones.

```
1. tracker_read(agent_id: "be_test", fields: ["md.a"])
   -> { "md": { "a": ["auth"] } }
2. For each module in active list:
   a. node_read(agent_id: "be_test", input_key: "be_code", unit_id: "auth")
   b. node_read(agent_id: "be_test", input_key: "openapi", unit_id: "auth")
   c. If node_read returns NR-009 -> upstream not ready, skip
   d. Write and execute BE tests
   e. node_write(agent_id: "be_test", output_key: "be_test_report", data: {...}, unit_id: "auth")
3. tracker_update(agent_id: "be_test", status: "completed")
```

---

## Compressed Keymap

Use these compressed keys in all `node_write` calls. The registry validates against this map — unknown keys are rejected.

**test_files[]**

| Key | Full Name | Description |
|---|---|---|
| `tf` | test_files | Array of test file records |
| `tf.pt` | path | Test file path |
| `tf.ep` | endpoint_tested | Endpoint being tested |
| `tf.tc` | test_count | Number of tests in file |
| `tf.tg` | test_categories | Test categories covered |

**report.json**

| Key | Full Name | Description |
|---|---|---|
| `m` | module_id | Module identifier |
| `ly` | layer | Layer (be) |
| `ra` | run_at | Timestamp of test run |
| `tr` | test_results | Array of test result objects |
| `tr.ti` | test_id | Unique test identifier |
| `tr.tn` | test_name | Test name |
| `tr.ep` | endpoint | Endpoint tested |
| `tr.ct` | category | Test category (unit/integration/auth/middleware) |
| `tr.st` | status | Test status (pass/fail/skip) |
| `tr.dm` | duration_ms | Test duration in milliseconds |
| `tr.er` | error | Error message if failed |
| `tr.sr` | story_ref | Story reference |
| `tr.as` | assertions | Assertions object |
| `tr.as.sc` | status_code | HTTP status code assertion |
| `tr.as.rb` | response_body_validated | Response body validated |
| `tr.as.hc` | headers_checked | Headers checked |
| `pc` | pass_count | Total passing tests |
| `fc` | fail_count | Total failing tests |
| `sk` | skip_count | Total skipped tests |
| `tl` | total_count | Total test count |
| `cv` | coverage | Coverage metrics object |
| `cv.et` | endpoints_tested | Endpoints tested count |
| `cv.eo` | endpoints_total | Total endpoints |
| `cv.sc` | success_cases_covered | Success cases covered |
| `cv.ec` | error_cases_covered | Error cases covered |
| `cv.mt` | middleware_chains_tested | Middleware chains tested |
| `cv.at` | auth_endpoints_tested | Auth endpoints tested |
| `cv.lc` | line_coverage_percent | Line coverage percentage |
| `gs` | gate_status | Quality gate status (pass/fail) |

**bugs.json**

| Key | Full Name | Description |
|---|---|---|
| `m` | module_id | Module identifier |
| `ly` | layer | Layer (be) |
| `ra` | reported_at | Timestamp of bug report |
| `bg` | bugs | Array of bug objects |
| `bg.bi` | bug_id | Unique bug identifier |
| `bg.ds` | description | Bug description |
| `bg.fl` | file | File where bug was found |
| `bg.ln` | line | Line number of bug |
| `bg.sv` | severity | Bug severity (critical/major/minor) |
| `bg.rs` | reproduction_steps | Steps to reproduce |
| `bg.eb` | expected_behavior | Expected behavior |
| `bg.ab` | actual_behavior | Actual behavior |
| `bg.tr` | test_ref | Reference to failing test |
| `bg.cr` | contract_ref | Contract reference |
| `bg.mc` | mock_context | Mock context for reproduction |
| `tb` | total_bugs | Total bug count |
| `cb` | critical_bugs | Critical bug count |

---

## Tools Required

| Tool | Purpose | Exists? |
|---|---|---|
| `node_write` | Write BE test output via registry-validated compressed keys. Agent calls `node_write(agent_id: "be_test", output_key: "be_test_report", data: {...}, unit_id: "{module_id}")`. | Pending |
| `node_read` | Read upstream artifacts (be_code, openapi, be_policy_flow). Agent calls `node_read(agent_id: "be_test", input_key: "openapi", unit_id: "{module_id}")`. | Pending |
| `tracker_read` | Read active modules. Agent calls `tracker_read(agent_id: "be_test", fields: ["md.a"])`. | Pending |
| `tracker_update` | Report completion/failure. Agent calls `tracker_update(agent_id: "be_test", status: "completed")`. | Pending |
| `git_operations` | Commit test files to impl/be/{module_id} branch | yes |

---

## Guardrails

### Rules

| ID | Category | Severity | Rule |
|---|---|---|---|
| R-001 | `constraint` | `must` | Must test every endpoint for at least one success case and one error case. No endpoint may go untested. |
| R-002 | `constraint` | `must` | Must test middleware chains — verify that auth middleware rejects unauthenticated requests to protected endpoints. |
| R-003 | `constraint` | `must` | Must test auth requirements — endpoints requiring auth must return 401 without valid token. |
| R-004 | `constraint` | `must` | Must mock DB interactions (use mock Prisma client). Tests must not use a real database. |
| R-005 | `output_quality` | `must` | Must produce structured bug reports in bugs.json with reproduction_steps and mock_context for every failure. |
| R-006 | `constraint` | `must` | Test gate_status determines whether FE can proceed. gate_status=fail blocks FE implementation. |
| R-007 | `output_quality` | `must` | report.json must accurately reflect pass_count + fail_count + skip_count = total_count. |
| R-008 | `output_quality` | `should` | Should test request validation — verify that malformed requests return 400 with descriptive error messages. |
| R-009 | `output_quality` | `should` | Should validate response body shapes against OpenAPI component schemas. |
| R-010 | `scope_boundary` | `should` | Should test rate limiting middleware if defined in the policy flow (verify 429 response after limit). |
| R-011 | `constraint` | `must` | Must use compressed keys as defined in the Compressed Keymap section for all `node_write` / `node_read` calls. Never use expanded/full key names. |
| R-012 | `constraint` | `must` | Must use `node_write` to write output and `node_read` to read upstream artifacts. Must not use raw file writes, generic file_writer, or any other method. |
| R-013 | `constraint` | `must` | Must call `tracker_update(agent_id: "be_test", status: "completed")` before exiting on success. Must call `tracker_update(agent_id: "be_test", status: "failed", add_intervention: {...})` before exiting on failure. |
| R-014 | `constraint` | `must` | Must read active modules via `tracker_read(agent_id: "be_test", fields: ["md.a"])` and process only active modules. Must not hardcode module lists. |

### Limits

| Resource | Value |
|---|---|
| max_retries | 3 |
| max_tokens | 16384 |
| max_test_duration_seconds | 180 |
| timeout_seconds | 300 |

---

## Scope Boundary

**In scope:**
- Writing vitest + supertest test files for all endpoints
- Testing success and error response codes
- Testing middleware chain application
- Testing authentication and authorization enforcement
- Mocking DB and external service calls
- Executing tests and collecting results
- Producing structured test reports and bug reports
- Committing test files to impl/be/{module_id} branch
- Setting gate_status to control FE implementation flow

**Out of scope:**
- Testing database operations directly (db_test does this)
- Testing UI components or E2E flows (fe_test does this)
- Fixing bugs (be_impl handles fixes via fix_planner loop)
- Modifying the BE implementation code
- Performance or load testing of API endpoints
- Testing with real databases or external services

---

## Triggers

- Orchestrator activates this agent after be_impl commits for the module
- Runs on the impl/be/{module_id} branch
- In retrofit mode, triggered only for modules with BE layer changes

---

## Checkpoints

| ID | Description | Action |
|---|---|---|
| `CP-001` | BE implementation files found and loaded | `log` |
| `CP-002` | OpenAPI spec and policy flow loaded for test generation | `log` |
| `CP-003` | Mock generators created for DB and external services | `log` |
| `CP-004` | Test files generated for all endpoints | `log` |
| `CP-005` | Tests executed | `notify` — reports pass/fail summary |
| `CP-006` | Coverage report generated | `log` |
| `CP-007` | Bug reports generated for failures (if any) | `notify` — if critical bugs found |
| `CP-008` | Test files committed and gate_status set | `notify` — gate_status determines if FE can proceed |

---

## Validation Criteria

- Test files exist for every endpoint in openapi.json
- Every endpoint has at least one success test and one error test
- All tests use mocked DB (no real database calls)
- report.json pass_count + fail_count + skip_count = total_count
- All bugs in bugs.json have non-empty description, severity, reproduction_steps, and mock_context
- gate_status is "pass" only if fail_count = 0 for critical tests
- Protected endpoints have auth denial tests (401 without token)
- Test files are committed to impl/be/{module_id} branch

---

## Context Sources

- BE implementation files (from be_impl)
- openapi.json (endpoint definitions for test cases)
- be_policy_flow.json (middleware chains and auth requirements)
- global_security_policies.json (auth strategy for mock setup)
- global_middleware_registry.json (middleware to test)

---

## Operation Mode

| Field | Value |
|---|---|
| Type | `autonomous` |
| Fallback | `none` — if BE tests fail, gate_status=fail blocks FE implementation until bugs are fixed |

---

## Tool Gaps

| Gap ID | Description | Needed By | Impact Without |
|---|---|---|---|
| `TG-001` | `node_write` MCP tool not yet built | this agent | Cannot write output with registry validation -- blocked |
| `TG-002` | `node_read` MCP tool not yet built | this agent | Cannot read upstream artifacts with field enforcement -- blocked |
| `TG-003` | `tracker_read` MCP tool not yet built | this agent | Cannot read active modules -- blocked |
| `TG-004` | `tracker_update` MCP tool not yet built | this agent | Cannot report completion -- blocked |
| `TG-005` | OpenAPI test generator that produces vitest+supertest test cases from OpenAPI spec with correct request bodies, headers, and expected response assertions | this agent | Manual test derivation from spec is time-consuming and risks missing edge cases |
| `TG-006` | Mock generator that creates Prisma client mocks and external service mocks with type-safe interfaces | this agent | Manual mock creation risks type mismatches and incomplete mock coverage |
| `TG-007` | Supertest request builder that generates HTTP request chains from OpenAPI operations with correct content types, auth headers, and body encoding | this agent | Manual request construction risks missing headers or incorrect content types |

---

## Generation Readiness

| `generate_agent` Param | Status | Notes |
|---|---|---|
| `fileName` | ready | `be-test` |
| `agentName` | ready | `be_test` |
| `agentRole` | ready | "Backend API Test Writer and Executor" |
| `agentDescription` | ready | Full description available from Goal section |
| `operationMode` | ready | `autonomous`, no fallback |
| `goal` | ready | 3 objectives defined with priorities |
| `inputs` | ready | 3 inputs: BE impl code, openapi.json, be_policy_flow.json |
| `guardrails` | ready | 14 rules defined across constraint, output_quality, scope_boundary categories |
| `scopeBoundary` | ready | 9 in-scope items, 6 out-of-scope items |
| `outputFormat` | ready | TypeScript test files, JSON report, JSON bug report with full schemas |
| `triggers` | ready | 3 triggers defined |
| `checkpoints` | ready | 8 checkpoints with actions |
| `validation` | ready | 8 validation criteria |
| `contextSources` | ready | 5 context sources |
| `metadata` | ready | phase: "10", mode: "both", granularity: "per_module" |
