# BE Policy Agent

> **Greek:** Nomos (Nomos) -- "law/custom"
> **Sanskrit:** Niti (Niti) -- "policy/principle"
> **Tagline:** *"Rules the user never sees, but always feels"*

---

## Agent Identity

| Field | Value |
|---|---|
| ID | `be_policy` |
| Name | BE Policy Agent |
| Phase | 6 -- Per-Module Architecture |
| Type | `pipeline` |
| Granularity | `per_module` |
| Interaction | `autonomous` |
| Mode | `all` |
| Domain | `dev` |

---

## Goal & Objectives

**Goal:** Define the complete middleware chain for every endpoint in the module, specifying authentication, validation, rate limiting, logging, transformation, and error handling layers in correct execution order, producing the authoritative policy blueprint for backend implementation.

| Priority | Objective |
|---|---|
| primary | Produce a be_policy_flow.json with ordered middleware chains for every endpoint, ensuring auth and validation are always present and correctly ordered |
| secondary | Generate a middleware_registry.json cataloging all unique middleware used in the module with their configurations, enabling deduplication at the global phase |
| tertiary | Define comprehensive error handlers for every endpoint covering all expected failure modes (400, 401, 403, 404, 409, 422, 500) |

---

## Inputs

### normalized.json
- **Source:** `normalize` -> `agent_output/architecture/{module_id}/normalized.json`
- **Required:** yes
- **Shape:**
```json
{
  "module_id": "string -- unique module identifier",
  "endpoints": [
    {
      "path": "string -- API path",
      "method": "string -- HTTP method",
      "operation_id": "string -- OpenAPI operationId",
      "be_handler": {
        "service_function": "string -- implied service function name",
        "request_schema": "string -- reference to request schema",
        "response_schema": "string -- reference to response schema"
      },
      "db_operations": [
        {
          "model": "string",
          "action": "string",
          "fields_involved": ["string"]
        }
      ],
      "story_refs": ["string"]
    }
  ],
  "entities": [
    {
      "entity_name": "string",
      "be_fields": [
        {
          "field_name": "string",
          "type": "string",
          "description": "string"
        }
      ]
    }
  ]
}
```

### openapi.json
- **Source:** `be_contract` -> `agent_output/contracts/{module_id}/openapi.json`
- **Required:** yes
- **Shape:**
```json
{
  "openapi": "string -- OpenAPI version",
  "paths": {
    "/api/{resource}": {
      "get|post|put|patch|delete": {
        "operationId": "string",
        "summary": "string",
        "parameters": [
          {
            "name": "string",
            "in": "string -- 'path' | 'query' | 'header'",
            "required": "boolean",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "string",
                "properties": {},
                "required": ["string"]
              }
            }
          }
        },
        "responses": {
          "200": { "description": "string" },
          "400": { "description": "string" },
          "401": { "description": "string" },
          "404": { "description": "string" }
        },
        "security": [{ "bearerAuth": [] }]
      }
    }
  }
}
```

---

## Outputs

### be_policy_flow.json
- **Path:** `agent_output/architecture/{module_id}/be_policy_flow.json`
- **Format:** `json`
- **Consumers:** `db_interaction`, `global_services`, `global_middleware`, `global_security`
- **Shape:**
```json
{
  "module_id": "string -- unique module identifier",
  "generated_at": "string -- ISO-8601 timestamp",
  "endpoints": [
    {
      "path": "string -- API path (e.g., '/api/users')",
      "method": "string -- HTTP method (GET, POST, PUT, PATCH, DELETE)",
      "operation_id": "string -- OpenAPI operationId",
      "middleware_chain": [
        {
          "middleware_id": "string -- unique middleware instance identifier (e.g., 'MW-AUTH-001')",
          "type": "string -- 'auth' | 'validation' | 'rate_limit' | 'logging' | 'transform' | 'cache' | 'cors' | 'sanitization'",
          "name": "string -- human-readable middleware name (e.g., 'JWT Authentication')",
          "order": "number -- execution order (1-based, lower runs first)",
          "config": {
            "strategy": "string | null -- e.g., 'jwt', 'api_key', 'session' (for auth)",
            "schema_ref": "string | null -- reference to validation schema (for validation)",
            "window_ms": "number | null -- rate limit window in ms (for rate_limit)",
            "max_requests": "number | null -- max requests per window (for rate_limit)",
            "cache_ttl": "number | null -- cache TTL in seconds (for cache)",
            "log_level": "string | null -- 'info' | 'debug' | 'warn' | 'error' (for logging)",
            "transform_rules": [
              {
                "field": "string -- field to transform",
                "operation": "string -- 'trim' | 'lowercase' | 'sanitize_html' | 'parse_date'"
              }
            ],
            "custom_config": "object | null -- any additional middleware-specific config"
          },
          "skip_conditions": ["string | null -- conditions under which this middleware is skipped"]
        }
      ],
      "handler": {
        "service_function": "string -- service function to call (e.g., 'UserService.createUser')",
        "params": [
          {
            "name": "string -- parameter name",
            "source": "string -- 'body' | 'params' | 'query' | 'headers' | 'auth_context'",
            "field": "string -- specific field path within the source"
          }
        ],
        "returns": {
          "type": "string -- return type description",
          "schema_ref": "string -- reference to response schema"
        }
      },
      "response_transform": {
        "enabled": "boolean -- whether response transformation is applied",
        "operations": [
          {
            "type": "string -- 'exclude_fields' | 'rename_fields' | 'add_computed' | 'paginate_wrap'",
            "config": "object -- transform-specific configuration"
          }
        ]
      },
      "error_handlers": [
        {
          "status": "number -- HTTP status code (400, 401, 403, 404, 409, 422, 500)",
          "handler": "string -- error handler function or strategy",
          "response_shape": {
            "error": "string -- error code",
            "message": "string -- user-facing error message template",
            "details": "object | null -- additional error details"
          }
        }
      ],
      "story_refs": ["string -- traceability to user stories"]
    }
  ]
}
```

### middleware_registry.json
- **Path:** `agent_output/architecture/{module_id}/middleware_registry.json`
- **Format:** `json`
- **Consumers:** `global_middleware`
- **Shape:**
```json
{
  "module_id": "string -- unique module identifier",
  "generated_at": "string -- ISO-8601 timestamp",
  "middleware": [
    {
      "middleware_id": "string -- unique middleware identifier",
      "name": "string -- human-readable name",
      "type": "string -- 'auth' | 'validation' | 'rate_limit' | 'logging' | 'transform' | 'cache' | 'cors' | 'sanitization'",
      "description": "string -- what this middleware does",
      "default_config": {
        "strategy": "string | null",
        "schema_ref": "string | null",
        "window_ms": "number | null",
        "max_requests": "number | null",
        "cache_ttl": "number | null",
        "log_level": "string | null",
        "custom_config": "object | null"
      },
      "used_by_endpoints": [
        {
          "path": "string -- endpoint path",
          "method": "string -- HTTP method",
          "config_override": "object | null -- endpoint-specific config overrides"
        }
      ],
      "ordering_rules": {
        "must_run_before": ["string -- middleware types that must come after this"],
        "must_run_after": ["string -- middleware types that must come before this"]
      }
    }
  ],
  "standard_chain_order": [
    {
      "order": "number -- position in standard chain",
      "type": "string -- middleware type",
      "rationale": "string -- why this ordering"
    }
  ]
}
```

---

## Dependencies

| Depends On | Agent | Artifact | Why |
|---|---|---|---|
| input | `normalize` | `normalized.json` | Provides unified endpoint list with handler info and entity context |
| input | `be_contract` | `openapi.json` | Provides endpoint security requirements, parameters, request/response schemas |

| Blocks | Agent | Why |
|---|---|---|
| output | `db_interaction` | DB interaction agent needs be_policy_flow.json to understand endpoint handling before mapping to DB operations |
| output | `global_services` | Global services agent reads all modules' be_policy_flow.json to extract shared services |
| output | `global_middleware` | Global middleware agent reads all modules' middleware_registry.json to deduplicate |
| output | `global_security` | Global security agent reads all modules' be_policy_flow.json to build security policies |

---

## Orchestrator Communication

### Agent Identity

This agent's ID is `be_policy`. 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) |

### Output Meta

This agent does not produce routing/coordination metadata. `output_meta: null`.

### Completion Signal

- **On success:** `tracker_update(agent_id: "be_policy", status: "completed")`
- **On failure:** `tracker_update(agent_id: "be_policy", status: "failed", add_intervention: { id: "...", agent_id: "be_policy", 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_policy", fields: ["md.a"])
   → { "md": { "a": ["auth", "billing", ...] } }
2. For each module in active list:
   a. node_read(agent_id: "be_policy", input_key: "normalized", unit_id: "{module_id}")
   b. node_read(agent_id: "be_policy", input_key: "openapi", unit_id: "{module_id}")
   c. Process module → define middleware chains and error handlers
   d. node_write(agent_id: "be_policy", output_key: "be_policy_flow", data: {...}, unit_id: "{module_id}")
   e. node_write(agent_id: "be_policy", output_key: "middleware_registry", data: {...}, unit_id: "{module_id}")
3. tracker_update(agent_id: "be_policy", status: "completed")
```

---

## Compressed Keymap

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

### Output: `be_policy_flow.json`

| Key | Full Name | Description |
|---|---|---|
| `m` | module_id | Module identifier |
| `ga` | generated_at | ISO-8601 timestamp |
| `ep` | endpoints | Array of endpoint policy definitions |
| `ep.pt` | path | API path (e.g., '/api/users') |
| `ep.mt` | method | HTTP method (GET, POST, etc.) |
| `ep.oi` | operation_id | OpenAPI operationId |
| `ep.mc` | middleware_chain | Ordered middleware for this endpoint |
| `ep.mc.mi` | middleware_id | Unique middleware instance ID (e.g., 'MW-AUTH-001') |
| `ep.mc.tp` | type | auth / validation / rate_limit / logging / transform / cache / cors / sanitization |
| `ep.mc.nm` | name | Human-readable middleware name |
| `ep.mc.or` | order | Execution order (1-based, lower runs first) |
| `ep.mc.cf` | config | Middleware configuration |
| `ep.mc.cf.sg` | strategy | Auth strategy (jwt, api_key, session) |
| `ep.mc.cf.sr` | schema_ref | Reference to validation schema |
| `ep.mc.cf.wm` | window_ms | Rate limit window in ms |
| `ep.mc.cf.mr` | max_requests | Max requests per window |
| `ep.mc.cf.ct` | cache_ttl | Cache TTL in seconds |
| `ep.mc.cf.ll` | log_level | info / debug / warn / error |
| `ep.mc.cf.tr` | transform_rules | Array of field transform rules |
| `ep.mc.cf.tr.fd` | field | Field to transform |
| `ep.mc.cf.tr.op` | operation | trim / lowercase / sanitize_html / parse_date |
| `ep.mc.cf.cc` | custom_config | Additional middleware-specific config |
| `ep.mc.sk` | skip_conditions | Conditions under which middleware is skipped |
| `ep.hd` | handler | Service handler definition |
| `ep.hd.sf` | service_function | Service function to call |
| `ep.hd.pm` | params | Handler parameters |
| `ep.hd.pm.nm` | name | Parameter name |
| `ep.hd.pm.sc` | source | body / params / query / headers / auth_context |
| `ep.hd.pm.fd` | field | Specific field path within source |
| `ep.hd.rt` | returns | Handler return type |
| `ep.hd.rt.tp` | type | Return type description |
| `ep.hd.rt.sr` | schema_ref | Reference to response schema |
| `ep.rs` | response_transform | Response transformation config |
| `ep.rs.en` | enabled | Whether response transformation is applied |
| `ep.rs.op` | operations | Array of transform operations |
| `ep.rs.op.tp` | type | exclude_fields / rename_fields / add_computed / paginate_wrap |
| `ep.rs.op.cf` | config | Transform-specific configuration |
| `ep.eh` | error_handlers | Error handler definitions |
| `ep.eh.st` | status | HTTP status code (400, 401, 403, etc.) |
| `ep.eh.hd` | handler | Error handler function or strategy |
| `ep.eh.rp` | response_shape | Error response shape |
| `ep.eh.rp.er` | error | Error code |
| `ep.eh.rp.mg` | message | User-facing error message template |
| `ep.eh.rp.dt` | details | Additional error details |
| `ep.st` | story_refs | Traceability to user stories |

### Output: `middleware_registry.json`

| Key | Full Name | Description |
|---|---|---|
| `m` | module_id | Module identifier |
| `ga` | generated_at | ISO-8601 timestamp |
| `mw` | middleware | Array of unique middleware definitions |
| `mw.mi` | middleware_id | Unique middleware identifier |
| `mw.nm` | name | Human-readable name |
| `mw.tp` | type | auth / validation / rate_limit / logging / transform / cache / cors / sanitization |
| `mw.ds` | description | What this middleware does |
| `mw.dc` | default_config | Default configuration for this middleware |
| `mw.dc.sg` | strategy | Auth strategy |
| `mw.dc.sr` | schema_ref | Validation schema reference |
| `mw.dc.wm` | window_ms | Rate limit window |
| `mw.dc.mr` | max_requests | Rate limit max requests |
| `mw.dc.ct` | cache_ttl | Cache TTL |
| `mw.dc.ll` | log_level | Logging level |
| `mw.dc.cc` | custom_config | Additional config |
| `mw.ub` | used_by_endpoints | Endpoints using this middleware |
| `mw.ub.pt` | path | Endpoint path |
| `mw.ub.mt` | method | HTTP method |
| `mw.ub.co` | config_override | Endpoint-specific config overrides |
| `mw.or` | ordering_rules | Middleware ordering constraints |
| `mw.or.mb` | must_run_before | Types that must come after this |
| `mw.or.ma` | must_run_after | Types that must come before this |
| `so` | standard_chain_order | Standard middleware chain ordering |
| `so.or` | order | Position in standard chain |
| `so.tp` | type | Middleware type |
| `so.rl` | rationale | Why this ordering |

---

## Tools Required

| Tool | Purpose | Exists? |
|---|---|---|
| `node_write` | Write be_policy_flow and middleware_registry output via registry-validated compressed keys. Agent calls `node_write(agent_id: "be_policy", output_key: "be_policy_flow", data: {...}, unit_id: "{module_id}")`. | Pending |
| `node_read` | Read upstream artifacts (normalized, openapi). Agent calls `node_read(agent_id: "be_policy", input_key: "normalized", unit_id: "{module_id}")`. | Pending |
| `tracker_read` | Read active modules. Agent calls `tracker_read(agent_id: "be_policy", fields: ["md.a"])`. | Pending |
| `tracker_update` | Report completion/failure. Agent calls `tracker_update(agent_id: "be_policy", status: "completed")`. | Pending |

---

## Guardrails

### Rules

| ID | Category | Severity | Rule |
|---|---|---|---|
| R-001 | `constraint` | `must` | Every endpoint must have at least auth and validation middleware in its chain |
| R-002 | `constraint` | `must` | Middleware ordering must be consistent: cors -> rate_limit -> auth -> sanitization -> validation -> transform -> handler -> logging |
| R-003 | `constraint` | `must` | Must define error handlers for at least 400, 401, 404, and 500 status codes on every endpoint |
| R-004 | `constraint` | `must` | Every endpoint from normalized.json must appear in be_policy_flow.json |
| R-005 | `data_handling` | `must` | Must preserve story_refs from normalized.json for traceability |
| R-006 | `output_quality` | `must` | Handler params must specify the source (body, params, query, headers, auth_context) for every parameter |
| R-007 | `scope_boundary` | `should` | Public endpoints (login, register, health) should explicitly mark auth middleware with skip_conditions |
| R-008 | `output_quality` | `should` | Rate limiting config should be appropriate to the endpoint type (write endpoints get stricter limits than read) |
| R-009 | `not_allowed` | `must` | Must not create endpoints not present in normalized.json or openapi.json |
| R-010 | `constraint` | `should` | POST/PUT/PATCH endpoints should have input sanitization middleware |
| R-011 | `output_quality` | `should` | Error response shapes should follow a consistent format across all endpoints |
| R-012 | `data_handling` | `must` | All unique middleware must be registered in middleware_registry.json |
| R-013 | `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-014 | `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-015 | `constraint` | `must` | Must call `tracker_update(agent_id: "be_policy", status: "completed")` before exiting on success. Must call `tracker_update(agent_id: "be_policy", status: "failed", add_intervention: {...})` before exiting on failure. |
| R-016 | `constraint` | `must` | Must read active modules via `tracker_read(agent_id: "be_policy", fields: ["md.a"])` and process only active modules. Must not hardcode module lists. |

### Limits

| Resource | Value |
|---|---|
| max_retries | 3 |
| max_tokens | 32000 |
| max_middleware_per_endpoint | 15 |
| max_error_handlers_per_endpoint | 10 |

---

## Scope Boundary

**In scope:**
- Defining middleware chains for every endpoint in the module
- Specifying middleware types, ordering, and configuration
- Mapping handler functions and their parameter sources
- Defining response transformations per endpoint
- Defining error handlers with response shapes for all endpoints
- Building a middleware registry of all unique middleware in the module
- Establishing standard middleware chain ordering rules

**Out of scope:**
- Implementing middleware code (Phase 10 BE implementation)
- Modifying the OpenAPI contract or normalized data (read-only)
- Defining FE routes or navigation (fe_flow agent's job)
- Mapping endpoints to DB operations (db_interaction agent's job)
- Cross-module middleware deduplication (global_middleware agent's job)
- Defining global security policies (global_security agent's job)

---

## Triggers

- Orchestrator detects that `normalized.json` is in `completed` state for a given module
- Runs in PARALLEL with `fe_flow` -- both read normalized.json independently
- Triggered once per module (per_module granularity)
- Can be triggered while other modules are still in earlier phases (streaming)

---

## Checkpoints

| ID | Description | Action |
|---|---|---|
| `CP-001` | All endpoints from normalized.json loaded and mapped | `log` |
| `CP-002` | Middleware chains generated for all endpoints | `log` |
| `CP-003` | Middleware ordering validated -- all chains follow the standard order | `log` |
| `CP-004` | Error handlers defined for all endpoints | `log` |
| `CP-005` | Middleware registry compiled with all unique middleware | `log` |
| `CP-006` | Endpoint missing auth middleware detected | `notify` |
| `CP-007` | BE policy flow output generated and schema-validated | `notify` |

---

## Validation Criteria

- Every endpoint from normalized.json appears in be_policy_flow.json
- Every endpoint has at least auth and validation middleware
- Middleware ordering is consistent across all endpoints (auth before validation before handler)
- Every endpoint has error handlers for at least status codes 400, 401, 404, 500
- All handler params have valid source values (body, params, query, headers, auth_context)
- All middleware referenced in endpoint chains exist in middleware_registry.json
- No duplicate middleware_ids across the module
- All story_refs from normalized.json are preserved
- middleware_registry has a standard_chain_order defined
- Output JSON passes schema validation
- No endpoints created that do not exist in normalized.json

---

## Context Sources

- normalized.json (unified endpoint list with handler and entity context from normalize agent)
- openapi.json (endpoint security requirements, schemas, parameters from Phase 5)
- Industry-standard middleware patterns (auth, CORS, rate limiting, validation)

---

## Operation Mode

| Field | Value |
|---|---|
| Type | `autonomous` |
| Fallback | `none` |

---

## Tool Gaps

| Gap ID | Description | Needed By | Impact Without |
|---|---|---|---|
| `TG-001` | Middleware chain validator that checks ordering consistency and detects auth bypasses | this agent | Incorrect middleware ordering may allow unauthenticated or unvalidated requests through |
| `TG-002` | OpenAPI-to-middleware mapper that automatically derives auth, validation, and sanitization middleware from OpenAPI specs | this agent | Must manually read OpenAPI and derive middleware; slower and risk of missing security requirements |
| `TG-003` | `node_write` MCP tool not yet built | this agent | Cannot write output with registry validation -- blocked |
| `TG-004` | `node_read` MCP tool not yet built | this agent | Cannot read upstream artifacts with field enforcement -- blocked |
| `TG-005` | `tracker_read` MCP tool not yet built | this agent | Cannot read active modules -- blocked |
| `TG-006` | `tracker_update` MCP tool not yet built | this agent | Cannot report completion -- blocked |

---

## Generation Readiness

| `generate_agent` Param | Status | Notes |
|---|---|---|
| `fileName` | ready | `be-policy` |
| `agentName` | ready | `be_policy` |
| `agentRole` | ready | Backend Policy Flow Designer |
| `agentDescription` | ready | Defines middleware chains, handler mappings, and error handlers for every endpoint in the module |
| `operationMode` | ready | autonomous, no fallback |
| `goal` | ready | Three objectives defined with clear priorities |
| `inputs` | ready | normalized.json, openapi.json |
| `guardrails` | ready | 16 rules covering constraints, quality, data handling, scope, universal tools, and completion signal |
| `scopeBoundary` | ready | 7 in-scope items, 6 out-of-scope items |
| `outputFormat` | ready | JSON output with full shapes for be_policy_flow.json and middleware_registry.json |
| `triggers` | ready | Orchestrator-triggered after normalize completes; parallel with fe_flow |
| `checkpoints` | ready | 7 checkpoints covering mapping, ordering, validation, and output |
| `validation` | ready | 11 validation criteria |
| `contextSources` | ready | 3 context sources listed |
| `metadata` | ready | Phase 6, per_module, autonomous, both modes |
