# FE Flow Agent

> **Greek:** Rheuma (Rheuma) -- "stream/current"
> **Sanskrit:** Pravaha (Pravaha) -- "flow/stream"
> **Tagline:** *"Every click has a destination"*

---

## Agent Identity

| Field | Value |
|---|---|
| ID | `fe_flow` |
| Name | FE Flow Agent |
| Phase | 6 -- Per-Module Architecture |
| Type | `pipeline` |
| Granularity | `per_module` |
| Interaction | `autonomous` |
| Mode | `all` |
| Domain | `dev` |

---

## Goal & Objectives

**Goal:** Build a complete screen/route/action graph for the module that maps every user interaction to its destination, ensuring every screen is reachable, every form has a corresponding endpoint, and every error state is handled.

| Priority | Objective |
|---|---|
| primary | Produce a fe_flow.json containing a directed graph of all screens, modals, redirects, and error states with edges describing every navigation trigger, action, and data flow |
| secondary | Define data fetching strategies for every screen -- what data loads on mount and what data loads on user action -- linked to specific API endpoints |
| tertiary | Identify and define route guards (authentication, role-based, conditional) ensuring protected screens are inaccessible without proper authorization |

---

## Inputs

### normalized.json
- **Source:** `normalize` -> `agent_output/architecture/{module_id}/normalized.json`
- **Required:** yes
- **Shape:**
```json
{
  "module_id": "string -- unique module identifier",
  "entities": [
    {
      "entity_name": "string -- canonical entity name",
      "fe_fields": [
        {
          "field_name": "string -- FE field name",
          "screen_refs": ["string -- screen_ids where this field appears"]
        }
      ],
      "field_mapping": [
        {
          "fe_field": "string | null",
          "be_field": "string | null",
          "db_field": "string | null",
          "mapping_status": "string"
        }
      ]
    }
  ],
  "endpoints": [
    {
      "path": "string -- API path",
      "method": "string -- HTTP method",
      "fe_screen_refs": [
        {
          "screen_id": "string",
          "action_id": "string",
          "trigger": "string"
        }
      ],
      "story_refs": ["string"]
    }
  ],
  "screens": [
    {
      "screen_id": "string",
      "screen_name": "string",
      "route": "string",
      "be_cross_refs": [
        {
          "endpoint_path": "string",
          "endpoint_method": "string",
          "usage": "string"
        }
      ],
      "story_refs": ["string"]
    }
  ]
}
```

### fe_details.json
- **Source:** `fe_contract` -> `agent_output/contracts/{module_id}/fe_details.json`
- **Required:** yes
- **Shape:**
```json
{
  "module_id": "string -- module identifier",
  "screens": [
    {
      "screen_id": "string -- unique screen ID in format SCR-{MODULE}-{NNN}",
      "name": "string -- human-readable screen name",
      "description": "string -- what this screen does and why it exists",
      "route": "string -- URL route for this screen",
      "story_refs": ["string -- story IDs this screen serves"],
      "components": [
        {
          "name": "string -- component name in PascalCase",
          "type": "string -- 'form' | 'display' | 'navigation' | 'layout' | 'feedback' | 'modal' | 'list' | 'chart' | 'action'",
          "props": {
            "description": "object -- expected props with types (key: prop name, value: type signature)"
          }
        }
      ],
      "dataDisplayed": [
        {
          "field": "string -- field name as displayed",
          "source": "string -- 'api' | 'local_state' | 'global_state' | 'derived' | 'url_param' | 'static'",
          "format": "string | null -- display format if applicable"
        }
      ],
      "dataCaptured": [
        {
          "field": "string -- field name as captured",
          "type": "string -- 'string' | 'number' | 'boolean' | 'date' | 'file' | 'select' | 'multi-select' | 'rich-text'",
          "validation_rules": ["string -- validation rules (e.g., 'required', 'email_format', 'max_length:255')"]
        }
      ],
      "endpointProposals": [
        {
          "method": "string -- 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'",
          "path": "string -- proposed endpoint path",
          "purpose": "string -- what this endpoint is for",
          "request_shape": "object -- proposed request body structure with field types",
          "response_shape": "object -- expected response body structure with field types",
          "story_ref": "string -- story ID this endpoint proposal traces to"
        }
      ],
      "state_requirements": {
        "local_state": "object -- component-level state fields with types",
        "global_state": "object -- app-level state fields this screen reads or writes",
        "derived_state": "object -- computed state derived from other state"
      },
      "navigation": {
        "links_to": ["string -- screen IDs this screen can navigate to"],
        "back_to": "string | null -- screen ID for back navigation, null if top-level",
        "conditional_routes": [
          {
            "condition": "string -- condition expression",
            "target": "string -- target screen ID"
          }
        ]
      }
    }
  ]
}
```

---

## Outputs

### fe_flow.json
- **Path:** `agent_output/architecture/{module_id}/fe_flow.json`
- **Format:** `json`
- **Consumers:** `global_navigation`, `architect_reconcile`
- **Shape:**
```json
{
  "module_id": "string -- unique module identifier",
  "generated_at": "string -- ISO-8601 timestamp",
  "nodes": [
    {
      "node_id": "string -- unique node identifier (e.g., 'FN-AUTH-001')",
      "type": "string -- 'screen' | 'modal' | 'redirect' | 'error' | 'loading' | 'terminal'",
      "screen_ref": "string | null -- screen_id from fe_details (null for synthetic nodes like error/redirect)",
      "route": "string | null -- URL route (null for modals and synthetic nodes)",
      "label": "string -- human-readable node label",
      "is_entry_point": "boolean -- whether this is an initial route users can land on",
      "requires_auth": "boolean -- whether authentication is required",
      "required_roles": ["string -- roles allowed to access this node (empty = any authenticated user)"]
    }
  ],
  "edges": [
    {
      "edge_id": "string -- unique edge identifier (e.g., 'FE-AUTH-E001')",
      "from": "string -- source node_id",
      "to": "string -- target node_id",
      "trigger": "string -- 'click' | 'submit' | 'navigate' | 'auto' | 'error' | 'timeout' | 'redirect'",
      "action": "string -- 'navigate' | 'open_modal' | 'close_modal' | 'submit_form' | 'fetch_data' | 'redirect' | 'show_error'",
      "data_flow": {
        "carries": ["string -- data fields passed from source to target"],
        "via": "string -- 'route_params' | 'query_params' | 'state' | 'context' | 'props' | 'none'"
      },
      "condition": "string | null -- condition that must be true for this edge to activate (e.g., 'form_valid', 'is_authenticated')"
    }
  ],
  "entry_points": [
    {
      "node_id": "string -- entry point node_id",
      "route": "string -- URL route",
      "is_default": "boolean -- whether this is the module's default/landing route",
      "auth_required": "boolean -- whether auth is needed to access this entry"
    }
  ],
  "guards": [
    {
      "guard_id": "string -- unique guard identifier (e.g., 'GRD-AUTH-001')",
      "type": "string -- 'auth' | 'role' | 'condition' | 'feature_flag'",
      "applies_to": ["string -- node_ids this guard protects"],
      "config": {
        "auth_required": "boolean -- whether authentication check is needed",
        "role_required": ["string -- roles that pass this guard (empty = any authenticated)"],
        "condition": "string | null -- custom condition expression",
        "redirect_on_fail": "string -- node_id or route to redirect to on guard failure"
      }
    }
  ],
  "data_fetching": [
    {
      "screen_id": "string -- screen this fetching config belongs to",
      "on_mount": [
        {
          "endpoint_path": "string -- API endpoint to call",
          "endpoint_method": "string -- HTTP method",
          "purpose": "string -- what data this fetches (e.g., 'load user profile')",
          "params_from": "string -- 'route_params' | 'query_params' | 'state' | 'none'",
          "loading_node": "string | null -- node_id of loading state to show"
        }
      ],
      "on_action": [
        {
          "action_id": "string -- action that triggers this fetch",
          "endpoint_path": "string -- API endpoint to call",
          "endpoint_method": "string -- HTTP method",
          "purpose": "string -- what this action does",
          "on_success": "string -- node_id to navigate to on success",
          "on_error": "string -- node_id to show on error"
        }
      ]
    }
  ],
  "error_states": [
    {
      "error_id": "string -- unique error state identifier",
      "type": "string -- 'network_failure' | 'auth_failure' | 'validation_failure' | 'not_found' | 'server_error' | 'timeout'",
      "node_id": "string -- error node in the graph",
      "recovery_edges": [
        {
          "action": "string -- 'retry' | 'navigate_back' | 'redirect_login' | 'show_fallback'",
          "target_node": "string -- where recovery leads"
        }
      ]
    }
  ]
}
```

---

## Dependencies

| Depends On | Agent | Artifact | Why |
|---|---|---|---|
| input | `normalize` | `normalized.json` | Provides unified view of screens, endpoints, and entities with cross-references |
| input | `fe_contract` | `fe_details.json` | Provides navigation_graph, state_matrix, and detailed screen/action definitions |

| Blocks | Agent | Why |
|---|---|---|
| output | `global_navigation` | Global navigation agent merges all modules' fe_flow.json into site-wide navigation |
| output | `architect_reconcile` | Architect reconcile reads fe_flow.json to build complete module flow |

---

## Orchestrator Communication

### Agent Identity

This agent's ID is `fe_flow`. 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: "fe_flow", status: "completed")`
- **On failure:** `tracker_update(agent_id: "fe_flow", status: "failed", add_intervention: { id: "...", agent_id: "fe_flow", 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: "fe_flow", fields: ["md.a"])
   → { "md": { "a": ["auth", "billing", ...] } }
2. For each module in active list:
   a. node_read(agent_id: "fe_flow", input_key: "normalized", unit_id: "{module_id}")
   b. node_read(agent_id: "fe_flow", input_key: "fe_details", unit_id: "{module_id}")
   c. Process module → build screen/route/action graph
   d. node_write(agent_id: "fe_flow", output_key: "fe_flow", data: {...}, unit_id: "{module_id}")
3. tracker_update(agent_id: "fe_flow", status: "completed")
```

---

## Compressed Keymap

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

### Output: `fe_flow.json`

| Key | Full Name | Description |
|---|---|---|
| `m` | module_id | Module identifier |
| `ga` | generated_at | ISO-8601 timestamp |
| `nd` | nodes | Array of graph nodes (screens, modals, redirects, etc.) |
| `nd.ni` | node_id | Unique node identifier (e.g., 'FN-AUTH-001') |
| `nd.tp` | type | screen / modal / redirect / error / loading / terminal |
| `nd.sr` | screen_ref | Screen ID from fe_details (null for synthetic nodes) |
| `nd.rt` | route | URL route (null for modals and synthetic nodes) |
| `nd.lb` | label | Human-readable node label |
| `nd.ie` | is_entry_point | Whether this is an initial landing route |
| `nd.ra` | requires_auth | Whether authentication is required |
| `nd.rr` | required_roles | Roles allowed to access this node |
| `ed` | edges | Array of directed edges between nodes |
| `ed.ei` | edge_id | Unique edge identifier (e.g., 'FE-AUTH-E001') |
| `ed.fr` | from | Source node_id |
| `ed.to` | to | Target node_id |
| `ed.tr` | trigger | click / submit / navigate / auto / error / timeout / redirect |
| `ed.ac` | action | navigate / open_modal / close_modal / submit_form / fetch_data / redirect / show_error |
| `ed.df` | data_flow | Data carried along this edge |
| `ed.df.cr` | carries | Data fields passed from source to target |
| `ed.df.vi` | via | route_params / query_params / state / context / props / none |
| `ed.cn` | condition | Condition for edge activation (null if unconditional) |
| `ep` | entry_points | Module entry points with routes |
| `ep.ni` | node_id | Entry point node_id |
| `ep.rt` | route | URL route |
| `ep.id` | is_default | Whether this is the module's default/landing route |
| `ep.ar` | auth_required | Whether auth is needed to access this entry |
| `gd` | guards | Route guards for authentication and roles |
| `gd.gi` | guard_id | Unique guard identifier (e.g., 'GRD-AUTH-001') |
| `gd.tp` | type | auth / role / condition / feature_flag |
| `gd.at` | applies_to | Node IDs this guard protects |
| `gd.cf` | config | Guard configuration |
| `gd.cf.ar` | auth_required | Whether authentication check is needed |
| `gd.cf.rr` | role_required | Roles that pass this guard |
| `gd.cf.cn` | condition | Custom condition expression |
| `gd.cf.rf` | redirect_on_fail | Node_id or route to redirect on failure |
| `dt` | data_fetching | Per-screen data fetching strategies |
| `dt.si` | screen_id | Screen this config belongs to |
| `dt.om` | on_mount | Data fetched on screen mount |
| `dt.om.ep` | endpoint_path | API endpoint to call |
| `dt.om.em` | endpoint_method | HTTP method |
| `dt.om.pp` | purpose | What data this fetches |
| `dt.om.pf` | params_from | route_params / query_params / state / none |
| `dt.om.ln` | loading_node | Node_id of loading state to show |
| `dt.oa` | on_action | Data fetched on user action |
| `dt.oa.ai` | action_id | Action that triggers this fetch |
| `dt.oa.ep` | endpoint_path | API endpoint to call |
| `dt.oa.em` | endpoint_method | HTTP method |
| `dt.oa.pp` | purpose | What this action does |
| `dt.oa.os` | on_success | Node_id to navigate to on success |
| `dt.oa.oe` | on_error | Node_id to show on error |
| `es` | error_states | Error state definitions |
| `es.ei` | error_id | Unique error state identifier |
| `es.tp` | type | network_failure / auth_failure / validation_failure / not_found / server_error / timeout |
| `es.ni` | node_id | Error node in the graph |
| `es.re` | recovery_edges | Recovery actions from this error |
| `es.re.ac` | action | retry / navigate_back / redirect_login / show_fallback |
| `es.re.tn` | target_node | Where recovery leads |

---

## Tools Required

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

---

## Guardrails

### Rules

| ID | Category | Severity | Rule |
|---|---|---|---|
| R-001 | `constraint` | `must` | Every screen from fe_details must appear as a node in the graph |
| R-002 | `constraint` | `must` | Every screen must be reachable from at least one entry point via traversal of edges |
| R-003 | `constraint` | `must` | Every form submit action must have a corresponding endpoint in the data_fetching on_action array |
| R-004 | `constraint` | `must` | Must handle error states for network failure, auth failure, and validation failure at minimum |
| R-005 | `constraint` | `must` | Every entry point must have a valid route |
| R-006 | `output_quality` | `must` | Every edge must have a valid trigger and action; no edges with empty or null triggers |
| R-007 | `data_handling` | `should` | Data flow on edges should specify what data moves and how (route params, state, props) |
| R-008 | `scope_boundary` | `should` | Route guards should be defined for any screen that requires authentication or specific roles |
| R-009 | `output_quality` | `should` | Loading states should be defined for screens that fetch data on mount |
| R-010 | `not_allowed` | `must` | Must not create routes or screens not present in the source fe_details or normalized data |
| R-011 | `constraint` | `should` | Error recovery edges should provide at least one recovery action (retry, navigate back, or redirect) |
| R-012 | `constraint` | `must` | No duplicate node_ids or edge_ids in the output |
| 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: "fe_flow", status: "completed")` before exiting on success. Must call `tracker_update(agent_id: "fe_flow", status: "failed", add_intervention: {...})` before exiting on failure. |
| R-016 | `constraint` | `must` | Must read active modules via `tracker_read(agent_id: "fe_flow", fields: ["md.a"])` and process only active modules. Must not hardcode module lists. |

### Limits

| Resource | Value |
|---|---|
| max_retries | 3 |
| max_tokens | 32000 |
| max_nodes_per_module | 200 |
| max_edges_per_module | 500 |

---

## Scope Boundary

**In scope:**
- Building the screen/route/action directed graph from normalized and fe_details data
- Defining edges with triggers, actions, data flow, and conditions
- Identifying entry points and default routes
- Defining route guards for authentication and role-based access
- Mapping data fetching strategies (on_mount and on_action) per screen
- Defining error states and recovery flows

**Out of scope:**
- Modifying source fe_details.json or normalized.json (read-only)
- Defining middleware chains or BE policy (be_policy agent's job)
- Mapping endpoints to DB operations (db_interaction agent's job)
- Building global/cross-module navigation (global_navigation agent's job)
- Generating component code or UI implementation
- Designing visual layouts or wireframes

---

## Triggers

- Orchestrator detects that `normalized.json` is in `completed` state for a given module
- Runs in PARALLEL with `be_policy` -- 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 screens from fe_details mapped to graph nodes | `log` |
| `CP-002` | Edge generation complete -- all navigation paths and actions mapped | `log` |
| `CP-003` | Graph validation: orphan node detected (screen unreachable from any entry point) | `notify` |
| `CP-004` | Route guard assignment complete -- all auth-required screens have guards | `log` |
| `CP-005` | Data fetching strategies assigned to all screens | `log` |
| `CP-006` | FE flow output generated and schema-validated | `notify` |

---

## Validation Criteria

- Every screen_id from fe_details appears as a node in the nodes array
- Every node is reachable from at least one entry_point via edge traversal
- No orphan nodes (nodes with zero incoming edges that are not entry points)
- Every form submit action has a matching on_action entry in data_fetching
- At least one entry_point is defined with is_default=true
- Error states cover network_failure, auth_failure, and validation_failure at minimum
- Every guard has at least one node in applies_to
- All node_ids and edge_ids are unique
- Every edge references valid from and to node_ids
- Output JSON passes schema validation
- No dead-end nodes except those typed as 'terminal' or 'error'

---

## Context Sources

- normalized.json (unified module descriptor from normalize agent)
- fe_details.json (FE screens, navigation graph, state matrix from Phase 5)
- Unified contract review results (any FE consistency issues already flagged)

---

## Operation Mode

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

---

## Tool Gaps

| Gap ID | Description | Needed By | Impact Without |
|---|---|---|---|
| `TG-001` | Graph validator that checks reachability, orphan nodes, dead ends, and cycle detection in directed graphs | this agent | Unreachable screens or infinite navigation loops may go undetected |
| `TG-002` | Route conflict detector that identifies duplicate or overlapping route patterns | this agent | Route conflicts cause runtime errors; manual review is unreliable for large modules |
| `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 | `fe-flow` |
| `agentName` | ready | `fe_flow` |
| `agentRole` | ready | FE Flow Graph Builder |
| `agentDescription` | ready | Builds screen/route/action directed graph mapping every user interaction to its destination |
| `operationMode` | ready | autonomous, no fallback |
| `goal` | ready | Three objectives defined with clear priorities |
| `inputs` | ready | normalized.json, fe_details.json |
| `guardrails` | ready | 16 rules covering constraints, quality, data handling, scope, universal tools, and completion signal |
| `scopeBoundary` | ready | 6 in-scope items, 6 out-of-scope items |
| `outputFormat` | ready | JSON output with full shape for fe_flow.json |
| `triggers` | ready | Orchestrator-triggered after normalize completes; parallel with be_policy |
| `checkpoints` | ready | 6 checkpoints covering node mapping, edges, guards, and output |
| `validation` | ready | 11 validation criteria |
| `contextSources` | ready | 3 context sources listed |
| `metadata` | ready | Phase 6, per_module, autonomous, both modes |
