# https://github.com/mova-compact/mova-flat-runner 项目说明书

生成时间：2026-05-15 07:59:21 UTC

## 目录

- [Project Overview](#page-project-overview)
- [Core MCP Tools](#page-core-tools)
- [Installation and Setup](#page-installation-setup)
- [System Architecture](#page-architecture)
- [Security Guards](#page-security-guards)
- [Transport Layer](#page-transport-layer)
- [Domain Validators](#page-validators)
- [Data Schemas and Types](#page-data-schemas)
- [Deployment and Operations](#page-deployment)
- [Extensibility and Customization](#page-extensibility)

<a id='page-project-overview'></a>

## Project Overview

### 相关页面

相关主题：[Core MCP Tools](#page-core-tools), [Installation and Setup](#page-installation-setup), [System Architecture](#page-architecture)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/mova-compact/mova-flat-runner/blob/main/README.md)
- [package.json](https://github.com/mova-compact/mova-flat-runner/blob/main/package.json)
- [src/index.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)
- [src/transports/local_seam_bridge.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
- [src/security/step_mode_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/step_mode_guard.ts)
- [src/package_support.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/package_support.ts)
- [server.json](https://github.com/mova-compact/mova-flat-runner/blob/main/server.json)
</details>

# Project Overview

## Introduction

**mova-flat-runner** (`@leryk1981/mova-flat-runner`) is an MCP (Model Context Protocol) server that provides governed AI workflows with human approval gates and audit trails. It enables AI-powered contract execution with built-in compliance controls for workflows such as invoice OCR, AML (Anti-Money Laundering) triage, credit review, and custom contract management. 资料来源：[package.json:1-15]()

The project serves as the authoritative native MCP connection for the MOVA Operator platform, allowing MCP clients like Claude Desktop and Codex to interact with governed AI workflows through a standardized interface. 资料来源：[README.md:1-30]()

## High-Level Architecture

The mova-flat-runner implements a layered architecture that bridges MCP clients with the MOVA API backend, providing both remote execution through the MOVA cloud and local execution capabilities.

```mermaid
graph TD
    subgraph "MCP Clients"
        Claude["Claude Desktop"]
        Codex["Codex IDE"]
    end

    subgraph "Mova Flat Runner"
        MCPServer["MCP Server Entry Point<br/>dist/index.js"]
        ToolExecutor["Tool Executor<br/>executeTool()"]
        RemoteAPI["Remote API Transport<br/>movaRequest()"]
        LocalSeamBridge["Local Seam Bridge<br/>local_seam_bridge.ts"]
        StepModeGuard["Step Mode Guard<br/>step_mode_guard.ts"]
    end

    subgraph "MOVA Backend"
        API["MOVA API<br/>api.mova-lab.eu"]
        ContractDB["Contract Registry"]
        RunEngine["Run Engine"]
    end

    Claude --> MCPServer
    Codex --> MCPServer
    MCPServer --> ToolExecutor
    ToolExecutor --> RemoteAPI
    ToolExecutor --> LocalSeamBridge
    RemoteAPI --> API
    LocalSeamBridge --> RunEngine
    API --> ContractDB
```

## Project Structure

| Directory | Purpose |
|-----------|---------|
| `cmd/` | Application entry points (publisher CLI) |
| `internal/api/` | HTTP handlers and routing |
| `internal/auth/` | Authentication (GitHub OAuth, JWT, namespace blocking) |
| `internal/config/` | Configuration management |
| `internal/database/` | Data persistence (PostgreSQL) |
| `internal/service/` | Business logic layer |
| `internal/telemetry/` | Metrics and monitoring |
| `internal/validators/` | Input validation |
| `pkg/` | Public packages |
| `src/` | Main application source code |

资料来源：[README.md:30-50]()

## Core Source Files

### Entry Point: `dist/index.js`

The binary entry point is defined in `package.json`:

```json
{
  "bin": {
    "mova-mcp": "dist/index.js"
  }
}
```

资料来源：[package.json:22-24]()

The server is started using `npx` with the npm package `@leryk1981/mova-flat-runner`:

```bash
npx -y @leryk1981/mova-flat-runner@3.3.3
```

资料来源：[README.md:15-20]()

### Main Server Implementation: `src/index.ts`

The core implementation handles tool execution through a switch-based `executeTool()` function that routes requests to the appropriate handler. 资料来源：[src/index.ts:200-300]()

#### Tool Categories

The server exposes the following tool categories:

| Tool Prefix | Purpose |
|-------------|---------|
| `mova_run` | Execute built-in contract workflows |
| `mova_contract` | Register and manage custom contracts |
| `mova_query` | Query contract status and audit trails |
| `mova_decide` | Handle decision points |
| `mova_connector` | External system integration |
| `mova_health` | Health check operations |

资料来源：[README.md:55-65]()

#### Key Tool Handlers

**`mova_run` Handler** (`src/index.ts`)
- Validates contract type against built-in manifests
- Bridges to either remote API or local execution
- Returns structured JSON responses

**`mova_contract` Actions**:
- `register`: `POST /api/v1/contracts/register`
- `run`: `POST /run/{contract_id}`
- `run_status`: `GET /run/{run_id}/status`

资料来源：[src/index.ts:100-200]()

**`mova_query` Views**:
- `status`: Returns bridged run status
- `audit`: Returns audit trail (backend-dependent for custom contracts)
- `audit_compact`: Returns structured unavailability for custom IDs

资料来源：[tasks/task061.md:1-30]()

### HTTP Transport: `movaRequest()`

All API communication uses a unified transport layer:

```typescript
export const movaGet = (config, path) => movaRequest(config, "GET", path);
export const movaPut = (config, path, body) => movaRequest(config, "PUT", path, body);
export const movaDelete = (config, path) => movaRequest(config, "DELETE", path);
export const movaPost = (config, path, body) => movaRequest(config, "POST", path, body);
```

资料来源：[dist-test/src/transports/remote_api.js:80-85]()

### Local Seam Bridge: `src/transports/local_seam_bridge.ts`

The local seam bridge enables local execution of contract steps without requiring remote API calls. It handles:

- **Execution Modes**: `AI_ATOMIC`, `HUMAN_GATE`, `DETERMINISTIC`, `CONTRACT_CALL`
- **State Management**: Bridge state references and terminal outcomes
- **Verification**: Pass/fail verification payloads with invariant checks

```typescript
const producedOutput =
  request.step.execution_mode === "AI_ATOMIC"
    ? CANONICAL_STRATEGY
    : request.stepResult ?? null;
```

资料来源：[src/transports/local_seam_bridge.ts:1-50]()

#### Bridge Response Structure

| Field | Description |
|-------|-------------|
| `status` | `"completed"`, `"advanced"`, or `"human_gate_required"` |
| `execution_mode` | Step execution mode |
| `produced_output` | Output data for AI_ATOMIC steps |
| `gate_required` | Boolean indicating human approval needed |
| `next_phase` | `"EXECUTION"` or `"WAIT_HUMAN"` |
| `verification_payload` | Pass/fail verification checks |

资料来源：[src/transports/local_seam_bridge.ts:15-30]()

### Security: `src/security/step_mode_guard.ts`

The step mode guard validates that contract step definitions conform to their declared execution modes:

| Violation Type | Condition |
|----------------|-----------|
| `deterministic_with_model` | DETERMINISTIC step has a `model` field |
| `ai_atomic_without_model` | AI_ATOMIC step missing `model` field |
| `contract_call_without_contract_id` | CONTRACT_CALL step missing `contract_id` |
| `human_gate_without_decisions` | HUMAN_GATE step missing `decision_options` |

```typescript
export function findStepModeViolations(flow): Violation[] {
  // Validates each step's execution_mode against its required fields
}

export function assertStepModesValid(flow, requestId): FlatRunnerResult | null {
  // Returns error result if violations found
}
```

资料来源：[src/security/step_mode_guard.ts:1-80]()

### Package Support: `src/package_support.ts`

Contract packages are validated for structural integrity before execution:

```typescript
function validateGlobalShape(value: unknown): string | null {
  // Validates global file structure:
  // - schema_id: "contract_package_global_v1"
  // - version: required string
  // - semantic_roles: non-empty array
  // - non_authority_rules: non-empty array
}

function validatePackageManifestShape(value: unknown): string | null {
  // Validates manifest structure:
  // - Allowed keys: schema_id, package_id, version, flow_ref, etc.
  // - Required strings: package_id, version, flow_ref
}
```

资料来源：[src/package_support.ts:1-50]()

## Configuration

### Required Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `MOVA_API_URL` | MOVA API base URL | `https://api.mova-lab.eu` |
| `MOVA_API_KEY` | MOVA API authentication key | — |
| `LLM_KEY` | OpenRouter API key for LLM analysis | — |
| `LLM_MODEL` | OpenRouter model ID | `openai/gpt-4o-mini` |

### Optional Local HTTP Mode Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `MOVA_API_TIMEOUT_MS` | API request timeout | `30000` |
| `MOVA_HTTP_PORT` | Local HTTP server port | `3796` |
| `MOVA_INVOKE_TOKEN` | Local invoke authentication token | — |

### Local Sandbox Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `MOVA_SANDBOX_PACKAGE_PATH` | Contract package location | `D:\Projects_MOVA\mova-intent\contracts\dockerfile-nodejs-v1` |
| `MOVA_SANDBOX_PROJECT_PATH` | Project directory | (required) |
| `MOVA_SANDBOX_STATE_FILE` | State persistence file | System temp directory |

资料来源：[README.md:35-60]()

## MCP Server Configuration

### Claude Desktop Example

```json
{
  "mcpServers": {
    "mova": {
      "command": "npx",
      "args": ["-y", "@leryk1981/mova-flat-runner@3.3.3"],
      "env": {
        "MOVA_API_URL": "https://api.mova-lab.eu",
        "MOVA_API_KEY": "__SET_MOVA_API_KEY__",
        "LLM_KEY": "__SET_LLM_KEY__",
        "LLM_MODEL": "openai/gpt-4o-mini"
      }
    }
  }
}
```

### Codex Config Example (TOML)

```toml
[mcp_servers.mova]
command = "npx"
args = ["-y", "@leryk1981/mova-flat-runner@3.3.3"]
startup_timeout_sec = 90.0

[mcp_servers.mova.env]
MOVA_API_URL = "https://api.mova-lab.eu"
MOVA_API_KEY = "__SET_MOVA_API_KEY__"
LLM_KEY = "__SET_LLM_KEY__"
LLM_MODEL = "openai/gpt-4o-mini"
```

资料来源：[README.md:60-100]()

## Build System

### Available Make Targets

| Target | Purpose |
|--------|---------|
| `make publisher` | Build the MCP publisher CLI |
| `make check` | Run lint, unit tests, and integration tests |
| `make help` | Display all available commands |

资料来源：[README.md:10-20]()

### Build Scripts (package.json)

| Script | Description |
|--------|-------------|
| `npm run build` | Compile TypeScript and add shebang |
| `npm run test:build` | Validate built output |
| `npm run smoke:custom-bridge` | Smoke test for custom contract bridge |

资料来源：[package.json:25-30]()

### Server Registry Configuration

The `server.json` file defines the MCP server schema for the Model Context Protocol registry:

```json
{
  "name": "io.github.mova-compact/mova-flat-runner",
  "version": "2.0.6",
  "description": "Governed AI workflows with human approval gates and audit trails"
}
```

资料来源：[server.json:1-15]()

## Workflow Execution Modes

The system supports four execution modes for contract steps:

```mermaid
graph LR
    subgraph "Execution Modes"
        AI["AI_ATOMIC<br/>LLM-driven step"]
        DET["DETERMINISTIC<br/>Local JS validation"]
        CALL["CONTRACT_CALL<br/>Cross-contract invocation"]
        GATE["HUMAN_GATE<br/>Human approval required"]
    end

    AI --> Output1["Produces structured output"]
    DET --> Output2["Validation result"]
    CALL --> Output3["Sub-contract result"]
    GATE --> Output4["Awaiting decision"]
```

| Mode | Model Field | Additional Fields | Use Case |
|------|-------------|-------------------|----------|
| `AI_ATOMIC` | Required | Output schema path | LLM analysis and decision-making |
| `DETERMINISTIC` | Forbidden | — | Local validation logic |
| `CONTRACT_CALL` | Optional | `contract_id` | Invoke another contract |
| `HUMAN_GATE` | Optional | `decision_options` | Manual approval checkpoints |

资料来源：[src/security/step_mode_guard.ts:30-70]()

## Custom Contract Bridge

The mova-flat-runner implements a **Custom Query Bridge** to handle custom contract visibility across different API namespaces:

```mermaid
sequenceDiagram
    participant Client as MCP Client
    participant MFR as mova-flat-runner
    participant Bridge as Custom Run Bridge
    participant API as MOVA API

    Note over Client,MFR: Contract Registration & Run
    Client->>MFR: mova_contract register
    MFR->>API: POST /api/v1/contracts/register
    API-->>MFR: contract_id
    MFR->>MFR: rememberCustomRun(contract_id, run_id)

    Note over Client,MFR: Custom Query Flow
    Client->>MFR: mova_query (404 from API)
    MFR->>Bridge: Check CUSTOM_RUN_BRIDGE
    Bridge-->>MFR: run_id mapping exists
    MFR->>API: GET /api/v1/contracts/my
    API-->>MFR: contract metadata
    MFR-->>Client: Bridged status response
```

**Bridge Behavior**:
- On `mova_contract run` and `run_status`: captures `contract_id -> run_id` mapping
- On `mova_query status` (404): probes `/api/v1/contracts/my` and returns bridged status
- On `mova_query audit` (404): returns honest `AUDIT_UNAVAILABLE` envelope

资料来源：[tasks/task061.md:1-60]()

## Security Considerations

### API Key Management

> **Security Note**: Do not commit real `MOVA_API_KEY`, `LLM_KEY`, or `MOVA_INVOKE_TOKEN`. 资料来源：[README.md:70-75]()

### Step Mode Validation

The step mode guard enforces strict validation before execution:
- Prevents DETERMINISTIC steps from using LLM models
- Ensures AI_ATOMIC steps have model configuration
- Validates HUMAN_GATE steps have decision options

### Human Gate Protection

```typescript
const gateGuard = await assertNotHumanGate(config, run_id, step_id, requestId);
if (gateGuard) return gateGuard;
```

Human gate steps cannot be completed via generic `step_complete` — they require the dedicated `gate_approve` / `gate_reject` path. 资料来源：[src/index.ts:200-250]()

## References

- **Repository**: https://github.com/mova-compact/mova-flat-runner
- **npm Package**: `@leryk1981/mova-flat-runner`
- **Current Version**: `3.3.4` 资料来源：[package.json:3]()
- **MCP Registry**: https://registry.modelcontextprotocol.io
- **API Health Check**: `https://api.mova-lab.eu/health`

---

<a id='page-core-tools'></a>

## Core MCP Tools

### 相关页面

相关主题：[Project Overview](#page-project-overview), [Transport Layer](#page-transport-layer), [System Architecture](#page-architecture)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/index.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)
- [src/schemas.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/schemas.ts)
- [src/security/step_mode_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/step_mode_guard.ts)
- [src/transports/local_seam_bridge.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
- [src/transports/remote_api.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/remote_api.ts)
- [server.json](https://github.com/mova-compact/mova-flat-runner/blob/main/server.json)
</details>

# Core MCP Tools

## Overview

The MOVA Flat Runner is an MCP (Model Context Protocol) server that provides governed AI workflow execution for Claude and MCP-compatible clients. The Core MCP Tools are the primary interface through which clients interact with the system to execute business workflows such as invoice OCR, AML triage, credit review, and custom contracts.

The tool executor is implemented in `executeTool()` within `src/index.ts` and handles all incoming tool requests via the MCP protocol. Each tool maps to a specific workflow action or API operation, with built-in validation, error handling, and security guards.

资料来源：[src/index.ts:1-50]()

## Architecture Overview

```mermaid
graph TD
    subgraph "MCP Client"
        A[Claude / Cursor / Codex]
    end
    
    subgraph "MOVA Flat Runner"
        B[executeTool dispatcher]
        C[mova_run]
        D[mova_contract]
        E[mova_query]
        F[mova_health]
        G[mova_decide]
        H[mova_connector]
        I[mova_calibrate_intent]
        J[step_complete / gate_approve / gate_reject]
    end
    
    subgraph "Backend Services"
        K[MOVA API]
        L[OpenRouter LLM]
        M[Local Sandbox]
    end
    
    A --> B
    B --> C
    B --> D
    B --> E
    B --> F
    B --> G
    B --> H
    B --> I
    B --> J
    
    C --> K
    D --> K
    E --> K
    C --> L
    I --> L
    J --> K
    I --> M
    
    style B fill:#f9f,stroke:#333
```

## Available Tools Summary

| Tool | Purpose | Primary API Endpoint |
|------|---------|---------------------|
| `mova_run` | Execute built-in contract workflows | `POST /api/v1/contracts/{id}/run` |
| `mova_contract` | Register and run custom contracts | `POST /api/v1/contracts/register` |
| `mova_query` | Query contract status, audit, and audit_compact | `GET /api/v1/contracts/{id}` |
| `mova_health` | Health check for MOVA API | `GET /health` |
| `mova_decide` | Submit human decision at approval gate | `POST /run/{run_id}/decision` |
| `mova_connector` | Connect to external data sources | Internal service routing |
| `mova_calibrate_intent` | Convert natural language to contract | LLM + local sandbox |
| `step_complete` | Mark a step as complete | `POST /run/{run_id}/step/{step_id}/complete` |
| `gate_approve` | Approve human gate | `POST /run/{run_id}/gate/approve` |
| `gate_reject` | Reject human gate | `POST /run/{run_id}/gate/reject` |
| `run_status` | Check run status | `GET /run/{run_id}/status` |

资料来源：[src/index.ts:180-220]()

## Tool Execution Flow

```mermaid
sequenceDiagram
    participant Client
    participant MCP as MOVA Flat Runner
    participant API as MOVA Backend API
    participant LLM as OpenRouter LLM
    participant Sandbox as Local Sandbox

    Client->>MCP: executeTool(name, args)
    MCP->>MCP: validateArgs(args)
    
    alt Built-in Contract
        MCP->>MCP: resolveManifest(contract_type)
        MCP->>API: movaRunStepsRemote()
        API-->>MCP: step results
    end
    
    alt Custom Contract
        MCP->>API: mova_contract register/run
        API-->>MCP: run_id
        MCP->>MCP: rememberCustomRun()
    end
    
    alt Human Gate Required
        MCP-->>Client: {status: "waiting_human", options: [...]}
        Client->>MCP: mova_decide / gate_approve / gate_reject
        MCP->>API: POST /run/{run_id}/decision
    end
    
    alt AI Atomic Step
        MCP->>LLM: analyze(inputs)
        LLM-->>MCP: analysis result
    end
    
    MCP-->>Client: final result
```

## Core Tools Detail

### mova_run

Executes built-in contract workflows using predefined manifests. Built-in contracts include invoice OCR, AML triage, credit review, and supplier screening.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `contract_type` | string | Yes | The type of contract to execute (e.g., "invoice_ocr", "aml_triage") |
| `inputs` | object | Yes | Initial inputs for the contract workflow |

**Workflow:**

1. Resolves the contract manifest from `CONTRACT_MANIFESTS`
2. Initializes the contract via `POST /api/v1/contracts/{id}/run`
3. Executes steps remotely via `movaRunStepsRemote()`
4. Returns structured response with status and outputs

**Security Validation:**

The `step_mode_guard.ts` validates that:
- `AI_ATOMIC` steps have a `model` field defined
- `DETERMINISTIC` steps do NOT have a `model` field
- `CONTRACT_CALL` steps have a `contract_id` field
- `HUMAN_GATE` steps have `decision_options` array

资料来源：[src/index.ts:200-280]()

### mova_contract

Handles custom contract registration and execution. Custom contracts can be created via natural language using `mova_calibrate_intent` or by registering existing contract definitions.

**Actions:**

| Action | Description | API Endpoint |
|--------|-------------|---------------|
| `register` | Register a new contract definition | `POST /api/v1/contracts/register` |
| `run` | Execute a custom contract | `POST /run/{contract_id}` |
| `run_status` | Check custom contract run status | `GET /run/{run_id}/status` |

**Custom Run Bridge:**

When a custom contract is run, the system captures and persists a `contract_id -> run_id` mapping in `CUSTOM_RUN_BRIDGE`:

```typescript
const ref = { run_id: runId, updated_at: new Date().toISOString() };
if (typeof sourceUrl === "string" && sourceUrl.length > 0)
    ref.source_url = sourceUrl;
CUSTOM_RUN_BRIDGE.set(contractId, ref);
```

This bridge enables `mova_query` to return status for custom contracts that may not exist in the standard contracts API namespace.

资料来源：[src/index.ts:280-350]()

### mova_query

Queries contract status, audit records, and compact audit information. This tool provides visibility into contract execution state and historical audit trails.

**Views:**

| View | Description | Response Format |
|------|-------------|-----------------|
| `status` | Current contract/run status | Bridged status with `bridge_mode=custom_contract_run_namespace_bridge_v1` for custom contracts |
| `audit` | Full audit record | Returns `AUDIT_UNAVAILABLE` envelope when backend namespace is absent |
| `audit_compact` | Compact audit summary | Structured unavailable object with `ok=false, status=424` |

**On 404 Response:**

When the API returns 404, `mova_query` probes `/api/v1/contracts/my` to check if the contract exists in the user's contract list. If found via `CUSTOM_RUN_BRIDGE`, it returns bridged status rather than a 404 error.

资料来源：[src/index.ts:350-420]()

### mova_health

Performs a health check on the MOVA API backend.

**Endpoint:** `GET /health`

**Response:** Returns health status of the MOVA API service.

资料来源：[server.json:1-50]()

### mova_decide

Submits human decision at an approval gate. This is the primary mechanism for human-in-the-loop (HITL) interactions.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `run_id` | string | Yes | The run identifier |
| `option_id` | string | Yes | The selected decision option |

**Flow:**

1. Fetches decision point from `GET /api/v1/contracts/{contractId}/decision`
2. Presents `question` and `options` to the human
3. Human selects an `option_id`
4. Submits via `POST /run/{run_id}/decision`

资料来源：[src/transports/remote_api.ts:1-80]()

### mova_calibrate_intent

Converts natural language descriptions into structured contract definitions using LLM processing and local sandbox validation.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `description` | string | Yes | Natural language description of the business process |
| `package_path` | string | No | Path to contract package for sandbox execution |
| `project_path` | string | No | Path to project files |

**Process:**

1. Sends description to OpenRouter LLM for structured extraction
2. Validates the generated contract in local sandbox via `resolveLocalSeamLocator()`
3. Returns validated contract definition ready for registration

资料来源：[src/transports/local_seam_bridge.ts:1-100]()

### step_complete, gate_approve, gate_reject

Management tools for contract execution state.

**step_complete:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `run_id` | string | Yes | The run identifier |
| `step_id` | string | Yes | The step to complete |
| `outcome` | string | No | Outcome identifier (default: "default") |
| `output` | object | No | Step output data |

**Security Guard:** `assertNotHumanGate()` prevents generic `step_complete` from being used on `HUMAN_GATE` steps. Human gates must use the dedicated `gate_approve` / `gate_reject` paths.

**gate_approve:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `run_id` | string | Yes | The run identifier |
| `step_id` | string | Yes | The gate step |
| `notes` | string | No | Approval notes |

**gate_reject:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `run_id` | string | Yes | The run identifier |
| `step_id` | string | Yes | The gate step |
| `reason` | string | No | Rejection reason |

资料来源：[src/index.ts:420-500]()

## Step Execution Modes

The MOVA system supports multiple step execution modes for different workflow requirements:

| Mode | Description | Required Fields |
|------|-------------|-----------------|
| `AI_ATOMIC` | Single LLM call that must complete atomically | `model`, `prompt` |
| `DETERMINISTIC` | Local JavaScript evaluation, no LLM | No `model` field |
| `HUMAN_GATE` | Requires human decision before proceeding | `decision_options` |
| `CONTRACT_CALL` | Calls another contract | `contract_id` |

资料来源：[src/security/step_mode_guard.ts:1-80]()

## Local Seam Bridge

For workflows requiring local execution, the `local_seam_bridge.ts` provides an interface to sandboxed contract execution:

```typescript
async function resolveLocalSeamLocator(initialInputs) {
    const packagePath = process.env.MOVA_SANDBOX_PACKAGE_PATH 
        ?? "D:\\Projects_MOVA\\mova-intent\\contracts\\dockerfile-nodejs-v1";
    const projectPath = process.env.MOVA_SANDBOX_PROJECT_PATH ?? "";
    // ...
}
```

The bridge produces standardized output conforming to the canonical strategy pattern:

```typescript
return {
    ok: true,
    bridge: {
        ok: true,
        bridge_source: "mova_flat_runner_canonical_bridge",
        status: "completed" | "advanced" | "human_gate_required",
        execution_mode: request.step.execution_mode,
        next_phase: { phase: status === "human_gate_required" ? "WAIT_HUMAN" : "EXECUTION" },
        verification_payload: { status: "PASS", checks: [...] }
    }
};
```

资料来源：[src/transports/local_seam_bridge.ts:100-180]()

## Remote API Transport

The remote API transport (`remote_api.ts`) handles communication with the MOVA backend:

```typescript
export const movaGet = (config, path) => movaRequest(config, "GET", path);
export const movaPut = (config, path, body) => movaRequest(config, "PUT", path, body);
export const movaDelete = (config, path) => movaRequest(config, "DELETE", path);
```

**Key endpoints:**

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/api/v1/contracts/{contractId}/step` | POST | Execute a step |
| `/api/v1/contracts/{contractId}/steps/{stepId}/output` | GET | Get step output |
| `/api/v1/contracts/{contractId}/decision` | GET | Get decision point |
| `/run/{runId}/decision` | POST | Submit decision |
| `/run/{runId}/status` | GET | Get run status |

资料来源：[src/transports/remote_api.ts:80-150]()

## Error Handling

All tools return structured error responses using `flatErr()`:

```typescript
function flatErr(
    code: string,
    message: string,
    context?: Record<string, unknown>,
    retryable?: boolean,
    requestId?: string
): FlatRunnerResult
```

**Error Codes:**

| Code | Description |
|------|-------------|
| `UNKNOWN_CONTRACT_TYPE` | Contract type not found in manifests |
| `API_REQUEST_FAILED` | Backend API request failed |
| `STEP_MODE_FIELD_MISMATCH` | Step execution mode doesn't match required fields |
| `LOCAL_VALIDATION_FAILED` | Local input validation failed |

资料来源：[src/index.ts:500-560]()

## Configuration

### Required Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `MOVA_API_KEY` | MOVA API authentication key | Required |
| `LLM_KEY` | OpenRouter API key for LLM steps | Required |
| `LLM_MODEL` | OpenRouter model ID | `openai/gpt-4o-mini` |
| `MOVA_API_URL` | Override API base URL | `https://api.mova-lab.eu` |

### Optional Local HTTP Mode Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `MOVA_API_TIMEOUT_MS` | API request timeout | `30000` |
| `MOVA_HTTP_PORT` | Local HTTP server port | `3796` |
| `MOVA_INVOKE_TOKEN` | Local invoke authentication | Required for HTTP mode |

资料来源：[server.json:1-50]()

## Resource Schema

The MCP server exposes resources via `mova://` URI scheme:

| URI | Description |
|-----|-------------|
| `mova://registry` | Lists all available contract manifests |
| `mova://schemas/envelopes` | Envelope schema definitions |
| `mova://contracts/{type}/manifest` | Individual contract manifest |

资料来源：[src/schemas.ts:1-50]()

## Security Considerations

### Step Mode Validation

The `step_mode_guard.ts` enforces strict validation on step execution modes:

- Prevents `AI_ATOMIC` steps without a defined model
- Prevents `DETERMINISTIC` steps from declaring a model
- Prevents `HUMAN_GATE` steps without decision options
- Prevents `CONTRACT_CALL` steps without a contract_id

### Human Gate Protection

The `assertNotHumanGate()` guard prevents generic step completion from bypassing human approval requirements:

```typescript
// SECURITY (CFV-3): HUMAN_GATE cannot be completed by generic step completion.
// Human confirmation requires the dedicated gate path (gate_approve / gate_reject).
```

### Output Sanitization

The `sanitizePublicShape()` function filters internal bridge metadata from public responses, excluding fields like `bridge_anchors`, `last_terminal_bridge`, `trace`, `outputs`, and `context`.

资料来源：[src/transports/local_seam_bridge.ts:60-90]()

## Quick Reference

### Execute Built-in Contract
```
tool: mova_run
args: { contract_type: "invoice_ocr", inputs: { document: "..." } }
```

### Register and Run Custom Contract
```
tool: mova_contract
args: { action: "register", contract_def: {...} }

tool: mova_contract
args: { action: "run", contract_id: "custom-123", inputs: {...} }
```

### Query Contract Status
```
tool: mova_query
args: { contract_id: "ctr-abc", view: "status" }
```

### Handle Human Approval
```
tool: mova_decide
args: { run_id: "run-xyz", option_id: "approve" }

---

<a id='page-installation-setup'></a>

## Installation and Setup

### 相关页面

相关主题：[Project Overview](#page-project-overview), [Deployment and Operations](#page-deployment)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this documentation page:

- [README.md](https://github.com/mova-compact/mova-flat-runner/blob/main/README.md)
- [package.json](https://github.com/mova-compact/mova-flat-runner/blob/main/package.json)
- [smithery.yaml](https://github.com/mova-compact/mova-flat-runner/blob/main/smithery.yaml)
- [server.json](https://github.com/mova-compact/mova-flat-runner/blob/main/server.json)
- [src/index.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)
- [src/transports/local_seam_bridge.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
</details>

# Installation and Setup

## Overview

The **mova-flat-runner** is an MCP (Model Context Protocol) server that provides governed AI workflow execution with human approval gates and audit trails. It enables clients like Claude Desktop, Cursor, and Codex to interact with MOVA's contract execution engine for invoice OCR, AML triage, credit review, supplier screening, and custom contract workflows.

资料来源：[README.md:1-20]()

## Package Information

| Property | Value |
|----------|-------|
| npm Package | `@leryk1981/mova-flat-runner` |
| Package Version | `3.3.4` |
| MCP Server Name | `io.github.mova-compact/mova-flat-runner` |
| Server Registry Version | `2.0.6` |
| Binary | `mova-mcp` |
| License | `MIT-0` |
| Runtime | Node.js (ES Module) |

资料来源：[package.json:2-12](), [server.json:2-8]()

## Prerequisites

### System Requirements

- **Node.js**: Required for running the MCP server
- **npm** or **npx**: For package installation and execution
- Network access to `api.mova-lab.eu` (or custom MOVA API endpoint)

### Required API Keys

Before setup, obtain the following credentials:

| Environment Variable | Required | Description |
|---------------------|----------|-------------|
| `MOVA_API_KEY` | Yes | MOVA API key for authentication. Use `test-key-001` for initial testing without registration. |
| `LLM_KEY` | Yes | OpenRouter API key (`sk-or-v1-...`) for LLM analysis steps |
| `LLM_MODEL` | No | OpenRouter model ID (default: `openai/gpt-4o-mini`) |

资料来源：[smithery.yaml:35-45](), [server.json:15-28](), [README.md:35-42]()

## Installation Methods

### Method 1: Direct npx Execution

The simplest installation method uses npx to run the package directly without global installation:

```bash
npx -y @leryk1981/mova-flat-runner@3.3.3
```

This downloads and executes the specified version on-demand.

资料来源：[README.md:19-20]()

### Method 2: Global npm Installation

Install the package globally for persistent access:

```bash
npm install -g @leryk1981/mova-flat-runner
```

After installation, the `mova-mcp` command becomes available system-wide.

资料来源：[package.json:13-14]()

### Method 3: Building from Source

For development or custom modifications:

```bash
# Clone the repository
git clone https://github.com/mova-compact/mova-flat-runner.git
cd mova-flat-runner

# Install dependencies
npm install

# Build the TypeScript source
npm run build
```

The build process compiles TypeScript and adds the shebang header to the output binary:

```bash
#!/usr/bin/env node
```

资料来源：[package.json:16-21]()

## Client Configuration

### Claude Desktop Configuration

Add the MOVA MCP server to your Claude Desktop configuration file:

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`

**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "mova": {
      "command": "npx",
      "args": ["-y", "@leryk1981/mova-flat-runner@3.3.3"],
      "env": {
        "MOVA_API_URL": "https://api.mova-lab.eu",
        "MOVA_API_KEY": "__SET_MOVA_API_KEY__",
        "LLM_KEY": "__SET_LLM_KEY__",
        "LLM_MODEL": "openai/gpt-4o-mini"
      }
    }
  }
}
```

资料来源：[README.md:57-70]()

### Codex Configuration

For Codex (Cursor) integration, add to your configuration:

```toml
[mcp_servers.mova]
command = "npx"
args = ["-y", "@leryk1981/mova-flat-runner@3.3.3"]
startup_timeout_sec = 90.0

[mcp_servers.mova.env]
MOVA_API_URL = "https://api.mova-lab.eu"
MOVA_API_KEY = "__SET_MOVA_API_KEY__"
LLM_KEY = "__SET_LLM_KEY__"
LLM_MODEL = "openai/gpt-4o-mini"
```

资料来源：[README.md:81-93]()

## Environment Variables Reference

### Core Configuration

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `MOVA_API_URL` | No | `https://api.mova-lab.eu` | Base URL for MOVA API |
| `MOVA_API_KEY` | Yes | — | API authentication key |
| `LLM_KEY` | Yes | — | OpenRouter API key |
| `LLM_MODEL` | No | `openai/gpt-4o-mini` | LLM model identifier |

资料来源：[README.md:35-48](), [server.json:19-32]()

### Local HTTP Mode (Optional)

For local execution mode without external API calls:

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `MOVA_API_TIMEOUT_MS` | No | `30000` | HTTP request timeout in milliseconds |
| `MOVA_HTTP_PORT` | No | `3796` | Local HTTP server port |
| `MOVA_INVOKE_TOKEN` | Conditional | — | Security token for local invocation |

资料来源：[README.md:44-48]()

### Local Seam Sandbox (Advanced)

For local seam bridge execution:

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `MOVA_SANDBOX_PACKAGE_PATH` | No | (project-specific) | Path to sandbox package |
| `MOVA_SANDBOX_PROJECT_PATH` | No | — | Path to project directory |
| `MOVA_SANDBOX_STATE_FILE` | No | (temp file) | Path to state file |

资料来源：[src/transports/local_seam_bridge.ts:1-20]()

## Health Check

Verify the MOVA API connectivity before running workflows:

```bash
curl -sS https://api.mova-lab.eu/health
```

资料来源：[README.md:52-53]()

## Available MCP Tools

Once installed, the following tools are available:

| Tool | Description |
|------|-------------|
| `mova_health` | Check API connectivity |
| `mova_registry` | List available contract types |
| `mova_run` | Execute built-in contract workflows |
| `mova_query` | Query contract status, audit, or audit_compact |
| `mova_decide` | Submit human decisions at approval gates |
| `mova_connector` | Connect external data sources |
| `mova_contract` | Register and run custom contracts |

资料来源：[README.md:54-55]()

## Build and Test Commands

For development, the following commands are available:

```bash
# Run lint, unit tests, and integration tests
make check

# View all available make targets
make help

# Build the publisher CLI
make publisher

# Run smoke tests
npm run smoke:custom-bridge
```

资料来源：[README.md:22-29]()

## Security Notes

> **Important**: Never commit real API keys to version control.

- Replace placeholders (`__SET_MOVA_API_KEY__`, `__SET_LLM_KEY__`, `__SET_MOVA_INVOKE_TOKEN__`) with actual credentials only in local configuration files
- The MCP registry provides server listings but does not transmit secrets
- Local invocation tokens should be used for secure local HTTP mode

资料来源：[README.md:49-51](), [README.md:56-57]()

## Architecture Overview

```mermaid
graph TD
    A[Claude Desktop / Codex] -->|MCP Protocol| B[mova-mcp Server]
    B --> C{Execution Mode}
    C -->|Remote API| D[MOVA API]
    C -->|Local HTTP| E[Local Seam Bridge]
    D --> F[Contract Execution Engine]
    E --> G[Local Sandbox]
    F --> H[(PostgreSQL)]
    G --> H
    D --> I[OpenRouter LLM]
    E --> I
```

## Troubleshooting

### Common Issues

| Issue | Solution |
|-------|----------|
| `404 contract not found` | Use `mova_contract` with `action=run` for custom contracts instead of `mova_run` |
| LLM analysis fails | Verify `LLM_KEY` is set to a valid OpenRouter key |
| Connection timeout | Increase `MOVA_API_TIMEOUT_MS` or check network connectivity |
| Human gate not advancing | Use `mova_decide` tool to submit decisions at approval gates |

资料来源：[tasks/task061.md:1-30](), [src/index.ts:150-180]()

## Next Steps

After installation:

1. Verify connectivity with `mova_health`
2. Explore available contracts using `mova_registry`
3. Run a built-in contract: `mova_run complaint`
4. Create custom contracts with `mova_contract register`

---

<a id='page-architecture'></a>

## System Architecture

### 相关页面

相关主题：[Project Overview](#page-project-overview), [Security Guards](#page-security-guards), [Transport Layer](#page-transport-layer)

<details>
<summary>Relevant Source Files</summary>

以下源码文件用于生成本页说明：

- [src/index.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)
- [src/package_support.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/package_support.ts)
- [src/transports/local_seam_bridge.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
- [src/transports/remote_api.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/remote_api.ts)
- [src/security/step_mode_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/step_mode_guard.ts)
- [README.md](https://github.com/mova-compact/mova-flat-runner/blob/main/README.md)
</details>

# System Architecture

## Overview

The **mova-flat-runner** is a Model Context Protocol (MCP) server that provides governed AI workflow execution with human approval gates and audit trails. It acts as an intermediary layer between MCP clients (such as Claude Desktop, Codex, or other compatible tools) and the MOVA backend API.

资料来源：[README.md](https://github.com/mova-compact/mova-flat-runner/blob/main/README.md)

The architecture follows a transport-agnostic design that supports both local seam execution and remote API integration, enabling flexible deployment scenarios from local development to production environments.

## High-Level Architecture

```mermaid
graph TD
    subgraph "MCP Client Layer"
        A[Claude Desktop] --> B[MCP Protocol]
        C[Codex] --> B
        D[Other MCP Clients] --> B
    end

    subgraph "mova-flat-runner"
        E[MCP Server Entry Point<br/>dist/index.js] --> F[Tool Executor<br/>executeTool]
        F --> G[Built-in Contracts<br/>CONTRACT_MANIFESTS]
        F --> H[Custom Contract Bridge<br/>CUSTOM_RUN_BRIDGE]
        F --> I[Security Layer<br/>step_mode_guard]
    end

    subgraph "Transport Layer"
        J[Local Seam Bridge<br/>local_seam_bridge.ts] 
        K[Remote API Transport<br/>remote_api.ts]
    end

    subgraph "External Services"
        L[MOVA API<br/>api.mova-lab.eu]
        M[OpenRouter LLM<br/>gpt-4o-mini]
    end

    E --> J
    E --> K
    J --> M
    K --> L
    L --> M
```

## Core Components

### MCP Server Entry Point

The MCP server is implemented as a stdio-based transport server that conforms to the Model Context Protocol specification. The server binary is located at `dist/index.js` and is invoked via the `mova-mcp` command.

资料来源：[package.json](https://github.com/mova-compact/mova-flat-runner/blob/main/package.json)

### Tool Executor (`executeTool`)

The central dispatch mechanism routes incoming tool requests to appropriate handlers based on the tool name. The executor supports the following tool categories:

| Tool Category | Tools | Purpose |
|--------------|-------|---------|
| Workflow Execution | `mova_run`, `mova_contract` | Launch contract execution |
| Query & Status | `mova_query`, `run_status` | Retrieve status and audit |
| Human Gates | `gate_approve`, `gate_reject` | Human decision handling |
| System | `mova_health`, `mova_registry` | Health checks and registry |

资料来源：[src/index.ts:168-450](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)

The executor follows a request-response pattern:

```typescript
async function executeTool(name: string, args: Args): Promise<string> {
  const requestId = shortId();
  switch (name) {
    case "mova_run": {
      const contractType = args.contract_type as string;
      const manifest = CONTRACT_MANIFESTS[contractType];
      // ... dispatch logic
    }
    // ... other cases
  }
}
```

### Contract Manifests (`CONTRACT_MANIFESTS`)

Built-in contracts are registered as manifests containing metadata such as:

- `contract_type`: Unique identifier
- `version`: Contract version
- `execution_mode`: Runtime behavior (AI_ATOMIC, DETERMINISTIC, HUMAN_GATE, CONTRACT_CALL)
- `dataspec`: Input field definitions
- `decision_options`: Available choices for HUMAN_GATE steps

资料来源：[src/index.ts:450-550](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)

## Transport Layer Architecture

### Remote API Transport

The remote transport handles communication with the MOVA backend API at `https://api.mova-lab.eu`. It provides HTTP methods for all contract operations.

```typescript
export const movaGet  = (config, path) => movaRequest(config, "GET", path);
export const movaPost = (config, path, body) => movaRequest(config, "POST", path, body);
export const movaPut  = (config, path, body) => movaRequest(config, "PUT", path, body);
export const movaDelete = (config, path) => movaRequest(config, "DELETE", path);
```

资料来源：[src/transports/remote_api.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/remote_api.ts)

The transport layer performs step execution through a sequential pipeline:

```mermaid
graph LR
    A[Start Contract] --> B[analyze step]
    B --> C[verify step]
    C --> D[decide step]
    D --> E[Execute Validators]
    E --> F[Return Result]
```

### Local Seam Bridge

The local seam bridge enables execution of contracts in a local sandbox environment without requiring remote API connectivity. It constructs a canonical bridge response format.

Key features include:
- Local project path resolution from environment variables
- State file management for persistent execution state
- Sanitization of public shape to filter sensitive fields

```typescript
function sanitizePublicShape(value: unknown): boolean {
  const excludedKeys = ["bridge_anchors", "last_terminal_bridge", 
    "terminal_commit_count", "_state15_bridge", "trace", "outputs", "context"];
  // ... sanitization logic
}
```

资料来源：[src/transports/local_seam_bridge.ts:80-95](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)

## Security Architecture

### Step Mode Guard (`step_mode_guard.ts`)

The security layer validates that step execution modes are consistent with their declared content fields. This prevents misconfiguration that could lead to security issues.

| Execution Mode | Required Field | Violation If Missing |
|---------------|----------------|----------------------|
| `AI_ATOMIC` | `model` | LLM step without model configuration |
| `DETERMINISTIC` | - (no model allowed) | Model field present in deterministic step |
| `CONTRACT_CALL` | `contract_id` | Call to undefined contract |
| `HUMAN_GATE` | `decision_options` | Gate without user choices |

资料来源：[src/security/step_mode_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/step_mode_guard.ts)

The validation function `assertStepModesValid` returns a structured error when violations are detected:

```typescript
export function assertStepModesValid(flow: unknown, requestId: string): FlatRunnerResult | null {
  const violations = findStepModeViolations(flow);
  if (violations.length === 0) return null;
  return flatErr(ERR.STEP_MODE_FIELD_MISMATCH, message, { violations, http_status_equivalent: 400 });
}
```

### Human Gate Protection

The `step_complete` tool includes a guard that prevents completion of HUMAN_GATE steps through the generic completion path, enforcing the dedicated gate approval/rejection flow.

资料来源：[src/index.ts:220-235](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)

## Custom Contract Bridge

A specialized bridge mechanism handles custom contract execution when the contract ID may not exist in the standard query namespace. This resolves the "custom contract audit identity gap."

```mermaid
graph TD
    A[mova_contract register] --> B[POST /api/v1/contracts/register]
    B --> C[mova_contract run]
    C --> D[POST /run/{contract_id}]
    D --> E[rememberCustomRun<br/>Map<contractId, runRef>]
    E --> F[run_status]
    F --> G[GET /run/{run_id}/status]
    G --> H[CUSTOM_RUN_BRIDGE<br/>In-Memory Map]
    H --> I[mova_query on 404]
    I --> J{Contract in Bridge?}
    J -->|Yes| K[Return bridged status]
    J -->|No| L[Return 404]
```

The bridge uses an in-memory `CUSTOM_RUN_BRIDGE` Map to track the relationship between custom contract IDs and their corresponding run IDs.

资料来源：[src/index.ts:100-140](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)

## Configuration

### Environment Variables

| Variable | Required | Default | Purpose |
|----------|----------|---------|---------|
| `MOVA_API_URL` | Yes | `https://api.mova-lab.eu` | Backend API endpoint |
| `MOVA_API_KEY` | Yes | - | Authentication key |
| `LLM_KEY` | Yes | - | OpenRouter API key |
| `LLM_MODEL` | No | `openai/gpt-4o-mini` | LLM model identifier |
| `MOVA_API_TIMEOUT_MS` | No | `30000` | HTTP request timeout |
| `MOVA_HTTP_PORT` | No | `3796` | Local HTTP mode port |
| `MOVA_INVOKE_TOKEN` | No | - | Local invoke authentication |

资料来源：[README.md](https://github.com/mova-compact/mova-flat-runner/blob/main/README.md)

### Configuration Object (`MovaConfig`)

The runtime configuration aggregates environment variables and validates required fields:

```typescript
interface MovaConfig {
  apiUrl: string;
  apiKey: string;
  llmKey: string;
  llmModel: string;
  invokeToken?: string;
}
```

## Data Flow

### Contract Execution Flow

```mermaid
sequenceDiagram
    participant Client as MCP Client
    participant Server as mova-flat-runner
    participant API as MOVA API
    participant LLM as OpenRouter

    Client->>Server: mova_run(contract_type, inputs)
    Server->>API: POST /run/{contract_id}
    API->>LLM: Analysis request
    LLM-->>API: Analysis result
    API-->>Server: Step result
    alt AI_ATOMIC step
        Server->>API: GET /steps/{step_id}/output
        API-->>Server: Validated output
    end
    alt HUMAN_GATE step
        Server-->>Client: waiting_human status
        Client->>Server: gate_approve/gate_reject
        Server->>API: POST /decision
    end
    Server-->>Client: Final result
```

### Local Seam Execution Flow

For local execution without remote API:

1. Resolve `package_path` and `project_path` from inputs or environment
2. Execute steps in the local sandbox environment
3. Apply output sanitization to remove internal fields
4. Construct canonical bridge response with verification payload

资料来源：[src/transports/local_seam_bridge.ts:95-150](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)

## Package Support and Validation

The `package_support.ts` module handles contract package validation including:

- Global file structure validation
- Semantic roles verification
- Non-authority rules checking
- Schema path validation

资料来源：[src/package_support.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/package_support.ts)

## Build and Deployment

The project uses TypeScript with a custom build script that:
1. Compiles TypeScript to JavaScript
2. Injects a shebang for Unix execution
3. Sets executable permissions on the output binary

```bash
npm run build
```

The server is published as an npm package `@leryk1981/mova-flat-runner` version `3.3.4` and can be invoked via `npx mova-mcp`.

资料来源：[package.json](https://github.com/mova-compact/mova-flat-runner/blob/main/package.json)

---

<a id='page-security-guards'></a>

## Security Guards

### 相关页面

相关主题：[System Architecture](#page-architecture), [Domain Validators](#page-validators)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/security/class_definition_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/class_definition_guard.ts)
- [src/security/determinism_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/determinism_guard.ts)
- [src/security/flow_schema_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/flow_schema_guard.ts)
- [src/security/gate_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/gate_guard.ts)
- [src/security/graph_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/graph_guard.ts)
- [src/security/step_mode_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/step_mode_guard.ts)
- [src/security/system_contract_guard.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/security/system_contract_guard.ts)
</details>

# Security Guards

## Overview

Security Guards are a defensive layer in the mova-flat-runner that enforce strict validation rules on MOVA flows before they enter execution. They operate on the principle of **deny-by-default**: any flow containing unknown or potentially dangerous fields is rejected at registration time, preventing malicious or malformed data from persisting into runtime state.

The guard system addresses specific vulnerability categories identified through security audits (CFV-9, CFV-10, and others), ensuring that privilege-elevation hints, inline class definitions, and execution mode mismatches cannot be smuggled into the system. 资料来源：[src/security/flow_schema_guard.ts:1-15]()

```mermaid
graph TD
    A[Flow Registration] --> B[Security Guards]
    B --> C{flow_schema_guard<br/>CFV-9}
    B --> D{class_definition_guard<br/>CFV-10}
    B --> E{step_mode_guard}
    B --> F{gate_guard}
    B --> G{graph_guard}
    B --> H{determinism_guard}
    B --> I{system_contract_guard}
    C --> J{All Guards Pass?}
    D --> J
    E --> J
    F --> J
    G --> J
    H --> J
    I --> J
    J -->|Yes| K[Flow Accepted]
    J -->|No| L[Rejection with<br/>FlatRunnerResult]
```

## Guard Architecture

### Core Principles

| Principle | Description |
|-----------|-------------|
| **Strict-by-default** | Any unknown field causes rejection |
| **Side-effect free at import** | Guards can be imported without triggering validation |
| **Compositable** | Multiple guards run in sequence, each checking a specific concern |
| **Audit trail** | Rejections return structured error payloads with remediation hints |

### Guard Registry

Each guard exports two key functions:

1. **Finder function** — Scans the flow and returns a list of violations (returns `string[]` or violation objects)
2. **Assert function** — Calls the finder, and if violations exist, returns a `FlatRunnerResult` error; otherwise returns `null`

```typescript
// Standard guard interface pattern
export function findXXXViolations(flow: unknown): Violation[] // Finder
export function assertXXXValid(flow: unknown, requestId: string): FlatRunnerResult | null // Assert
```

## Flow Schema Guard (CFV-9)

**File:** `src/security/flow_schema_guard.ts`

### Purpose

The flow schema guard enforces a strict allow-list of top-level keys in MOVA flow definitions. During a security audit, flows containing `__admin_override`, `__privilege_grant`, and `__debug_mode` were accepted at registration. If these fields were persisted—even silently—an attacker could smuggle privilege-elevation hints into the runtime for future code paths to read. 资料来源：[src/security/flow_schema_guard.ts:1-20]()

### Allowed Top-Level Keys

| Key | Purpose |
|-----|---------|
| `version` | Flow schema version |
| `description` | Human-readable description |
| `entry` | Entry point step reference |
| `steps` | Step definitions map |
| `parallel_steps` | Parallel step definitions |
| `notes` | Developer notes |
| `audit_mode` | Audit configuration |
| `audit_mode_note` | Audit mode explanation |
| `class_definition_ref` | Reference to registry class |
| `CONTRACT_CALL_instructions` | Contract invocation instructions |
| `input_schema` | Input validation schema |
| `output_schema` | Output validation schema |
| `metadata` | Additional metadata |

### Implementation

```typescript
export const ALLOWED_FLOW_TOP_LEVEL_KEYS: ReadonlySet<string> = new Set([
    "version",
    "description",
    "entry",
    "steps",
    "parallel_steps",
    "notes",
    "audit_mode",
    "audit_mode_note",
    "class_definition_ref",
    "CONTRACT_CALL_instructions",
    "input_schema",
    "output_schema",
    "metadata",
]);

export function findUnknownFlowFields(flow: unknown): string[] {
    if (!flow || typeof flow !== "object" || Array.isArray(flow)) return [];
    const f = flow as Record<string, unknown>;
    const out: string[] = [];
    for (const key of Object.keys(f)) {
        if (!ALLOWED_FLOW_TOP_LEVEL_KEYS.has(key))
            out.push(key);
    }
    return out;
}
```

### Rejection Response

When unknown fields are detected:

```json
{
    "ok": false,
    "code": "FLOW_SCHEMA_VIOLATION",
    "message": "Flow body contains unknown top-level key(s): __admin_override, __debug_mode",
    "details": {
        "unknown_fields": ["__admin_override", "__debug_mode"],
        "http_status_equivalent": 400
    }
}
```

## Class Definition Guard (CFV-10)

**File:** `src/security/class_definition_guard.ts`

### Purpose

The class definition guard prevents inline class definitions within flow bodies. Class definitions define severity bands and noise control parameters that must be resolved from the registry by `class_id`. Embedding them inline creates a vector for policy tampering and bypasses the centralized authority on these security-sensitive values. 资料来源：[src/security/class_definition_guard.ts:1-35]()

### Forbidden Keys

```typescript
const FORBIDDEN_FLOW_KEYS: readonly string[] = Object.freeze([
    "class_definition",
    "class_definition_ref",
    "class_definition_inline",
    "class_def_override",
    "class_def",
]);
```

### Implementation

```typescript
export function findInlineClassDefinitionFields(flow: unknown): string[] {
    if (!flow || typeof flow !== "object") return [];
    const f = flow as Record<string, unknown>;
    return FORBIDDEN_FLOW_KEYS.filter((k) => Object.prototype.hasOwnProperty.call(f, k));
}

export function assertNoInlineClassDefinition(
    flow: unknown,
    requestId: string,
): FlatRunnerResult | null {
    const found = findInlineClassDefinitionFields(flow);
    if (found.length === 0) return null;
    return flatErr(
        ERR.INLINE_CLASS_DEFINITION_FORBIDDEN,
        `Flow body contains inline class-definition field(s): ${found.join(", ")}. ` +
        "Class definitions must be resolved from the registry by class_id.",
        {
            forbidden_fields: found,
            remediation: "Remove these fields and reference the class via class_id",
            http_status_equivalent: 400,
        },
        false,
        requestId,
    );
}
```

### Defense in Depth

The flow schema guard (CFV-9) catches any `class_definition*` keys not yet covered by this stricter rule, providing layered protection:

> CFV-10's `class_definition*` keys are blocked specifically by `class_definition_guard.ts`; this guard catches everything else not yet covered by a stricter rule. 资料来源：[src/security/flow_schema_guard.ts:17-20]()

## Step Mode Guard

**File:** `src/security/step_mode_guard.ts`

### Purpose

The step mode guard validates that each step's `execution_mode` agrees with the fields it contains. MOVA supports multiple execution modes, and each mode has specific field requirements. Mismatches can indicate configuration errors or attempts to bypass intended behavior.

### Execution Mode Requirements

| Mode | Required Field | Forbidden Field |
|------|---------------|-----------------|
| `DETERMINISTIC` | — | `model` |
| `AI_ATOMIC` | `model` | — |
| `CONTRACT_CALL` | `contract_id` | — |
| `HUMAN_GATE` | `decision_options` array | — |

### Violation Types

```typescript
interface StepModeViolation {
    kind: string;
    step_id: string | undefined;
    execution_mode: string;
    message: string;
}
```

1. **deterministic_with_model** — DETERMINISTIC steps run local JS checks, not LLMs
2. **ai_atomic_without_model** — AI_ATOMIC requires a model field
3. **contract_call_without_contract_id** — CONTRACT_CALL requires contract_id
4. **human_gate_without_decisions** — HUMAN_GATE requires decision_options array

### Implementation

```typescript
export function findStepModeViolations(flow: unknown): StepModeViolation[] {
    const f = flow as Flow;
    if (!f?.steps) return [];
    const out: StepModeViolation[] = [];

    for (const [id, step] of Object.entries(f.steps)) {
        const mode = step.execution_mode ?? "DETERMINISTIC";

        if (mode === "DETERMINISTIC" && step.model !== undefined) {
            out.push({
                kind: "deterministic_with_model",
                step_id: id,
                execution_mode: mode,
                message: `step '${id}' is DETERMINISTIC but declares a 'model' field`,
            });
        }

        if (mode === "AI_ATOMIC" && asStr(step.model) === null) {
            out.push({
                kind: "ai_atomic_without_model",
                step_id: id,
                execution_mode: mode,
                message: `step '${id}' is AI_ATOMIC but has no 'model' field`,
            });
        }

        if (mode === "CONTRACT_CALL" && asStr(step.contract_id) === null) {
            out.push({
                kind: "contract_call_without_contract_id",
                step_id: id,
                execution_mode: mode,
                message: `step '${id}' is CONTRACT_CALL but has no 'contract_id'`,
            });
        }

        if (mode === "HUMAN_GATE" && !Array.isArray(step.decision_options)) {
            out.push({
                kind: "human_gate_without_decisions",
                step_id: id,
                execution_mode: mode,
                message: `step '${id}' is HUMAN_GATE but has no 'decision_options' array`,
            });
        }
    }
    return out;
}
```

## Additional Guards

### Gate Guard

**File:** `src/security/gate_guard.ts`

The gate guard enforces human gate access control, ensuring that human confirmation requires the dedicated gate path. It prevents generic step completion from bypassing human authorization requirements.

### Determinism Guard

**File:** `src/security/determinism_guard.ts`

The determinism guard ensures deterministic steps produce consistent results and cannot introduce non-deterministic behavior that could compromise reproducibility.

### Graph Guard

**File:** `src/security/graph_guard.ts`

The graph guard validates the structural integrity of the flow graph, ensuring all step references and dependencies are properly defined and no cycles or invalid references exist.

### System Contract Guard

**File:** `src/security/system_contract_guard.ts`

The system contract guard monitors system contract usage, preventing unauthorized access to privileged operations.

## Execution Flow

```mermaid
sequenceDiagram
    participant Client
    participant MCP as MCP Server
    participant Guards as Security Guards
    participant API as MOVA API

    Client->>MCP: mova_contract register(flow)
    MCP->>Guards: validate(flow)
    Guards->>Guards: flow_schema_guard
    Guards->>Guards: class_definition_guard
    Guards->>Guards: step_mode_guard
    Guards->>Guards: gate_guard
    Guards->>Guards: graph_guard
    Guards->>Guards: determinism_guard
    Guards->>Guards: system_contract_guard
    
    alt All Guards Pass
        Guards-->>MCP: null (valid)
        MCP->>API: POST /api/v1/contracts/register
        API-->>MCP: registration response
        MCP-->>Client: success
    else Guard Violation
        Guards-->>MCP: FlatRunnerResult (error)
        MCP-->>Client: rejection with details
    end
```

## Error Codes

| Code | Guard | Description |
|------|-------|-------------|
| `FLOW_SCHEMA_VIOLATION` | flow_schema_guard | Unknown top-level keys |
| `INLINE_CLASS_DEFINITION_FORBIDDEN` | class_definition_guard | Inline class definition present |
| `STEP_MODE_FIELD_MISMATCH` | step_mode_guard | Execution mode doesn't match fields |
| `GATE_ACCESS_DENIED` | gate_guard | Unauthorized gate access attempt |
| `DETERMINISM_VIOLATION` | determinism_guard | Non-deterministic behavior detected |
| `GRAPH_STRUCTURE_INVALID` | graph_guard | Invalid flow graph structure |
| `SYSTEM_CONTRACT_VIOLATION` | system_contract_guard | Unauthorized system contract use |

## Integration Points

### Local Seam Bridge

The local seam bridge integrates security guards into the transport layer:

> SECURITY (CFV-3): HUMAN_GATE cannot be completed by generic step completion. Human confirmation requires the dedicated gate path (gate_approve / gate_reject). Guard runs BEFORE forwarding so run state is not advanced on rejection. 资料来源：[src/index.ts:1-25]()

### Custom Contract Bridge

Security considerations are applied when bridging custom contract runs to ensure audit integrity:

> Safety: Built-in path untouched. No fake audit records introduced. Bridge only activates on 404 in `mova_query`. 资料来源：[tasks/task061.md:1-40]()

## Testing

Security guards are validated through:

```bash
# Run all security checks
make check

# Smoke test for custom contract bridge
npm run smoke:custom-bridge

# Build validation
npm run build
npm run test:build
```

## Best Practices

1. **Never disable guards** — Guards exist to prevent exploitation
2. **Keep allow-lists updated** — Review `ALLOWED_FLOW_TOP_LEVEL_KEYS` when adding new features
3. **Report unknown fields** — Fields that legitimately need to pass through should be explicitly allow-listed
4. **Maintain separation** — Built-in and custom contract paths should have distinct security requirements
5. **Audit on change** — Any schema change should trigger a security review

---

<a id='page-transport-layer'></a>

## Transport Layer

### 相关页面

相关主题：[System Architecture](#page-architecture), [Core MCP Tools](#page-core-tools), [Deployment and Operations](#page-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/transports/local_seam_bridge.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
- [src/transports/remote_api.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/remote_api.ts)
- [src/index.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)
- [src/package_support.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/package_support.ts)
- [dist-test/src/transports/local_seam_bridge.js](https://github.com/mova-compact/mova-flat-runner/blob/main/dist-test/src/transports/local_seam_bridge.js)
- [dist-test/src/transports/remote_api.js](https://github.com/mova-compact/mova-flat-runner/blob/main/dist-test/src/transports/remote_api.js)
</details>

# Transport Layer

The Transport Layer in mova-flat-runner provides the communication infrastructure for executing contract workflows across different execution environments. It abstracts the underlying HTTP communication with the MOVA backend API and provides a local seam bridge for sandboxed contract execution.

## Overview

The transport layer handles two primary communication patterns:

| Transport Mode | Purpose | Use Case |
|----------------|---------|----------|
| **Remote API** | HTTP-based communication with `api.mova-lab.eu` | Production deployments, remote contract execution |
| **Local Seam Bridge** | In-process contract execution via local sandbox | Development, testing, isolated execution |

The layer is responsible for:
- Managing HTTP requests to the MOVA backend
- Routing contract step execution to appropriate handlers
- Bridging between local execution context and remote API namespace
- Sanitizing data shapes for public consumption
- Handling execution modes (AI_ATOMIC, HUMAN_GATE, DETERMINISTIC, CONTRACT_CALL)

资料来源：[src/transports/local_seam_bridge.ts:1-50](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
资料来源：[src/transports/remote_api.ts:1-30](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/remote_api.ts)

## Architecture

```mermaid
graph TD
    subgraph "Client Layer"
        MCP[MCP Client]
        CLI[CLI Tools]
    end

    subgraph "Transport Layer"
        RemoteAPI[Remote API Transport]
        LocalBridge[Local Seam Bridge]
    end

    subgraph "Backend Services"
        MOVAAPI[MOVA API<br/>api.mova-lab.eu]
        LocalSandbox[Local Sandbox]
    end

    MCP --> |HTTP| RemoteAPI
    CLI --> |HTTP| RemoteAPI
    
    LocalBridge --> |Internal| LocalSandbox
    RemoteAPI --> |HTTP| MOVAAPI

    RemoteAPI -.-> |fallback| LocalBridge
```

## Remote API Transport

The Remote API transport provides HTTP-based communication with the MOVA backend service.

### Core Functions

| Function | Method | Purpose |
|----------|--------|---------|
| `movaRequest` | Core | Base HTTP request handler with error wrapping |
| `movaGet` | GET | Retrieve data from API endpoints |
| `movaPost` | POST | Submit data to create or trigger actions |
| `movaPut` | PUT | Update existing resources |
| `movaDelete` | DELETE | Remove resources |

资料来源：[src/transports/remote_api.ts:50-80](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/remote_api.ts)

### Request Configuration

The remote API uses a `MovaConfig` object for authentication and endpoint configuration:

```typescript
interface MovaConfig {
  baseUrl: string;       // API base URL (default: api.mova-lab.eu)
  apiKey: string;        // API authentication key
  timeout?: number;       // Request timeout in milliseconds
  headers?: Record<string, string>;
}
```

### API Endpoints

The transport layer integrates with the following MOVA API endpoints:

| Endpoint Pattern | Method | Usage |
|-----------------|--------|-------|
| `/api/v1/contracts/{contractId}` | GET | Query contract metadata |
| `/api/v1/contracts/{contractId}/step` | POST | Execute a contract step |
| `/api/v1/contracts/{contractId}/steps/{stepId}/output` | GET | Retrieve step output |
| `/api/v1/contracts/{contractId}/decision` | GET | Get human decision point |
| `/api/v1/contracts/my` | GET | List user's contracts |
| `/run/{runId}/status` | GET | Get run execution status |
| `/run/{contractId}` | POST | Initiate a contract run |

资料来源：[dist-test/src/transports/remote_api.js:1-60](https://github.com/mova-compact/mova-flat-runner/blob/main/dist-test/src/transports/remote_api.js)

## Local Seam Bridge

The Local Seam Bridge provides an internal bridge for sandboxed contract execution when the local seam backend is available.

### Bridge Invoker

The `createInternalBridgeInvoker()` function creates a bridge invoker that handles step execution within the local environment:

```typescript
function createInternalBridgeInvoker() {
  return async function bridgeInvoker(request) {
    bridgeSequence += 1;
    const suffix = `${request.step.id}:${bridgeSequence}`;
    
    const status =
      request.step.execution_mode === "HUMAN_GATE" && request.humanDecision == null
        ? "human_gate_required"
        : request.terminalOutcome
          ? "completed"
          : "advanced";

    return {
      ok: true,
      bridge: {
        ok: true,
        bridge_source: "mova_flat_runner_canonical_bridge",
        status,
        execution_mode: request.step.execution_mode,
        next_phase: { phase: status === "human_gate_required" ? "WAIT_HUMAN" : "EXECUTION" },
        // ... additional bridge fields
      },
    };
  };
}
```

资料来源：[src/transports/local_seam_bridge.ts:50-90](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)

### Execution Modes

The bridge handles different execution modes defined by the contract:

| Execution Mode | Behavior | Bridge Output |
|----------------|----------|---------------|
| `AI_ATOMIC` | LLM-powered atomic execution | Canonical strategy output with full validation metadata |
| `HUMAN_GATE` | Requires human decision | Returns `human_gate_required` status, awaits confirmation |
| `DETERMINISTIC` | Local JavaScript execution | Passes through step result |
| `CONTRACT_CALL` | Calls another contract | Forwards to referenced contract |

资料来源：[dist-test/src/security/step_mode_guard.js:1-50](https://github.com/mova-compact/mova-flat-runner/blob/main/dist-test/src/security/step_mode_guard.js)

### Status Handling

```mermaid
graph TD
    A[Step Execution Request] --> B{Execution Mode}
    
    B -->|AI_ATOMIC| C[Generate Canonical Output]
    B -->|HUMAN_GATE| D{Human Decision?}
    B -->|DETERMINISTIC| E[Pass Through Result]
    B -->|CONTRACT_CALL| F[Forward to Contract]
    
    D -->|No| G[Status: human_gate_required<br/>Phase: WAIT_HUMAN]
    D -->|Yes| H[Status: advanced<br/>Phase: EXECUTION]
    
    C --> I[Return Bridged Response]
    E --> I
    F --> I
    G --> I
    H --> I
```

## Data Sanitization

The transport layer includes a `sanitizePublicShape` function to filter sensitive or internal fields from response data:

```typescript
function sanitizePublicShape(value: unknown): boolean {
  if (Array.isArray(value)) {
    return value.every((item) => sanitizePublicShape(item));
  }
  
  const FORBIDDEN_KEYS = [
    "bridge_anchors",
    "last_terminal_bridge", 
    "terminal_commit_count",
    "_state15_bridge",
    "trace",
    "outputs",
    "context"
  ];

  for (const [key, child] of Object.entries(value)) {
    if (FORBIDDEN_KEYS.includes(key)) {
      return false;
    }
    if (!sanitizePublicShape(child)) {
      return false;
    }
  }
  return true;
}
```

资料来源：[src/transports/local_seam_bridge.ts:120-145](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)

## Package Locator Resolution

The Local Seam Bridge includes logic to resolve package references for contract execution:

```typescript
async function resolveLocalSeamLocator(initialInputs) {
  const packagePath = initialInputs.package_path 
    ?? process.env.MOVA_SANDBOX_PACKAGE_PATH 
    ?? "D:\\Projects_MOVA\\mova-intent\\contracts\\dockerfile-nodejs-v1";
    
  const projectPath = initialInputs.project_path 
    ?? process.env.MOVA_SANDBOX_PROJECT_PATH 
    ?? "";
    
  if (!projectPath) {
    throw new Error("missing_local_seam_project_path");
  }
  // ... additional resolution logic
}
```

资料来源：[dist-test/src/transports/local_seam_bridge.js:80-100](https://github.com/mova-compact/mova-flat-runner/blob/main/dist-test/src/transports/local_seam_bridge.js)

## Custom Contract Bridge

For custom contracts registered outside the standard `/api/v1/contracts` namespace, the transport layer provides a bridge mechanism:

### Bridge Map

The system maintains an in-memory mapping of custom contracts:

```typescript
CUSTOM_RUN_BRIDGE: Map<contract_id, {
  run_id: string,
  updated_at: string,
  source_url?: string
}>
```

资料来源：[src/index.ts:1-50](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)

### Custom Query Handling

When a contract is not found in the standard namespace, the bridge checks:

1. Local `CUSTOM_RUN_BRIDGE` map for run history
2. `/api/v1/contracts/my` for contract metadata
3. `/run/{runId}/status` for execution status

```mermaid
graph LR
    A[mova_query Request] --> B{API 404?}
    
    B -->|Yes| C[Check CUSTOM_RUN_BRIDGE]
    B -->|No| Z[Normal Response]
    
    C --> D{Run Found?}
    D -->|Yes| E[Return Bridged Status]
    D -->|No| F[Query /contracts/my]
    
    F --> G{Record Found?}
    G -->|Yes| H[Return with Contract Record]
    G -->|No| I[Return Error]
```

## Environment Variables

| Variable | Default | Purpose |
|----------|---------|---------|
| `MOVA_API_URL` | `https://api.mova-lab.eu` | MOVA API base URL |
| `MOVA_API_KEY` | - | API authentication key |
| `MOVA_API_TIMEOUT_MS` | `30000` | Request timeout in milliseconds |
| `MOVA_HTTP_PORT` | `3796` | Local HTTP mode port |
| `MOVA_INVOKE_TOKEN` | - | Token for local HTTP invocation |
| `MOVA_SANDBOX_PACKAGE_PATH` | - | Package path for local seam |
| `MOVA_SANDBOX_PROJECT_PATH` | - | Project path for local seam |
| `MOVA_SCHEMA_PATH` | - | Additional schema lookup path |

资料来源：[README.md](https://github.com/mova-compact/mova-flat-runner/blob/main/README.md)

## Remote Step Execution Flow

```mermaid
sequenceDiagram
    participant Client
    participant RemoteAPI
    participant MOVA as MOVA Backend
    
    Client->>RemoteAPI: movaRunStepsRemote(contractId)
    
    loop For each step: analyze, verify, decide
        RemoteAPI->>MOVA: POST /api/v1/contracts/{id}/step
        MOVA-->>RemoteAPI: Step result
        
        alt step === "analyze"
            RemoteAPI->>MOVA: GET /steps/analyze/output
            MOVA-->>RemoteAPI: Analysis output
            Note over RemoteAPI: Apply validators
        end
        
        alt status === "waiting_human"
            RemoteAPI->>MOVA: GET /decision
            MOVA-->>RemoteAPI: Decision point (question, options)
            Note over RemoteAPI: Return for human input
        end
    end
    
    RemoteAPI-->>Client: Aggregated results
```

## Error Handling

The transport layer wraps errors with structured error codes:

| Error Code | Description |
|------------|-------------|
| `API_REQUEST_FAILED` | HTTP request to backend failed |
| `AUDIT_UNAVAILABLE` | Audit endpoint not accessible |
| `CONTRACT_NOT_FOUND` | Contract ID not found in any namespace |
| `LOCAL_VALIDATION_FAILED` | Local input validation failed |
| `UNKNOWN_CONTRACT_TYPE` | Contract type not in manifest registry |

资料来源：[dist-test/src/transports/remote_api.js:40-80](https://github.com/mova-compact/mova-flat-runner/blob/main/dist-test/src/transports/remote_api.js)

## Testing

The compiled test files verify transport behavior:

- **dist-test/src/transports/remote_api.js** - Tests for HTTP transport functions
- **dist-test/src/transports/local_seam_bridge.js** - Tests for local bridge execution
- **dist-test/src/package_support.js** - Tests for package resolution

To run tests:
```bash
npm run build
npm run test:build
npm run smoke:custom-bridge

---

<a id='page-validators'></a>

## Domain Validators

### 相关页面

相关主题：[Data Schemas and Types](#page-data-schemas), [Security Guards](#page-security-guards)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this documentation:

- [src/validators/registry.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/registry.ts)
- [src/validators/aml.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/aml.ts)
- [src/validators/churn.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/churn.ts)
- [src/validators/complaint.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/complaint.ts)
- [src/validators/compliance.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/compliance.ts)
- [src/validators/contract_gen.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/contract_gen.ts)
- [src/validators/credit.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/credit.ts)
- [src/validators/invoice.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/invoice.ts)
- [src/validators/po.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/po.ts)
- [src/validators/supply_chain.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/supply_chain.ts)
- [src/validators/trade.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/trade.ts)
- [src/validators/content_flywheel.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/content_flywheel.ts)
</details>

# Domain Validators

Domain Validators are the core validation layer in MOVA Flat Runner's contract execution engine. They provide domain-specific input validation for each workflow type, ensuring data integrity before contract execution proceeds through subsequent steps.

## Overview

Domain Validators serve as a security boundary and data validation checkpoint within the MOVA contract execution model. Every validator function must be registered in the central `VALIDATOR_REGISTRY` before it can be invoked during contract execution.

资料来源：[src/validators/registry.ts:1-28]()

```mermaid
graph TD
    A[Contract Execution] --> B[ValidatorRef from Manifest]
    B --> C{Registry Lookup}
    C -->|Found| D[Execute ValidatorFn]
    C -->|Not Found| E[VALIDATOR_NOT_ALLOWED Error]
    D --> F[Return Validation Result]
    E --> G[Log Error to Analysis]
    F --> H[Proceed to Next Step]
    G --> H
```

## Architecture

### Validator Function Type

All domain validators conform to the `ValidatorFn` interface defined in the types module:

```typescript
type ValidatorFn = (inputs: Record<string, unknown>) => {
    ok: boolean;
    value: Record<string, unknown>;
    step_id: string;
};
```

资料来源：[dist-test/src/types.d.ts:1-7]()

| Field | Type | Description |
|-------|------|-------------|
| `ok` | `boolean` | Indicates whether validation passed |
| `value` | `Record<string, unknown>` | Validation results and derived fields |
| `step_id` | `string` | Identifier of the step being validated |

### Registry Structure

The registry is implemented as a `Map<string, ValidatorFn>` where keys are validator IDs in the format `{domain}.{validator_name}_v{version}`:

```typescript
export const VALIDATOR_REGISTRY = new Map<string, ValidatorFn>(
  all.map(v => [v.id, v.fn])
);
```

资料来源：[src/validators/registry.ts:25-27]()

## Registered Validator Domains

The validator registry aggregates validators from 10 domain-specific modules:

| Domain | Module | Purpose |
|--------|--------|---------|
| Invoice | `invoice.ts` | Invoice OCR and extraction validation |
| Purchase Order | `po.ts` | PO ID and approver validation |
| Trade | `trade.ts` | Trade finance validation |
| AML | `aml.ts` | Anti-money laundering screening |
| Complaint | `complaint.ts` | Customer complaint processing |
| Compliance | `compliance.ts` | Regulatory framework validation |
| Credit | `credit.ts` | Credit review validation |
| Supply Chain | `supply_chain.ts` | Supplier data validation |
| Churn | `churn.ts` | Customer churn prediction |
| Contract Gen | `contract_gen.ts` | Contract generation validation |

资料来源：[src/validators/registry.ts:3-13]()

## Validator Invocation Flow

During contract execution, validators are invoked through the remote API transport layer when processing the `analyze` step:

```typescript
const validatorContext = { ...initialInputs, ...analysis };
for (const validator of validators) {
    const fn = VALIDATOR_REGISTRY.get(validator.validator_id);
    if (!fn) {
        analysis[`${validator.step_id}_error`] = `VALIDATOR_NOT_ALLOWED: "${validator.validator_id}" not in registry`;
        continue;
    }
    try {
        const resultValue = fn(validatorContext);
        Object.assign(analysis, resultValue.value ?? {});
    } catch (error) {
        analysis[`${validator.step_id}_error`] = `VALIDATOR_FAILED: ${String(error)}`;
    }
}
```

资料来源：[dist-test/src/transports/remote_api.js:1-20]()

### Error Handling

| Error Type | Constant | Description |
|------------|----------|-------------|
| Validator not in registry | `VALIDATOR_NOT_ALLOWED` | Attempted to call unregistered validator |
| Validator execution failed | `VALIDATOR_FAILED` | Validator threw an exception |
| Local validation failed | `LOCAL_VALIDATION_FAILED` | Client-side validation error |

资料来源：[dist-test/src/types.d.ts:18-20]()

## Example Validators

### Supply Chain Validator

Validates supplier array input with country code format checking:

```typescript
{
  id: "supply_chain.validate_inputs_v0",
  fn: (inputs) => {
    const suppliers = Array.isArray(inputs.suppliers) 
      ? inputs.suppliers as Record<string, unknown>[] 
      : [];
    const non_empty    = suppliers.length > 0;
    const valid_items  = suppliers.filter(s =>
      s &&
      typeof s === "object" &&
      String(s["id"]      || "").length > 0 &&
      String(s["name"]    || "").length > 0 &&
      /^[A-Z]{2}$/.test(String(s["country"] || ""))
    );
    const invalid_count = suppliers.length - valid_items.length;
    return {
      ok: true,
      value: {
        inputs_valid:          non_empty && invalid_count === 0,
        supplier_count:        suppliers.length,
        valid_supplier_count:  valid_items.length,
        invalid_supplier_count: invalid_count,
        has_suppliers:         non_empty,
      },
      step_id: "validate_inputs",
    };
  },
}
```

资料来源：[src/validators/supply_chain.ts:1-35]()

### Purchase Order Validator

Validates PO ID and approver employee ID presence:

```typescript
{
  id: "po.validate_inputs_v0",
  fn: (inputs) => {
    const po  = String(inputs.po_id                || "");
    const emp = String(inputs.approver_employee_id || "");
    const po_ok  = po.length  >= 3;
    const emp_ok = emp.length >= 3;
    return {
      ok: true,
      value: { 
        inputs_valid: po_ok && emp_ok, 
        po_id_present: po_ok, 
        approver_present: emp_ok 
      },
      step_id: "validate_inputs",
    };
  },
}
```

资料来源：[src/validators/po.ts:1-20]()

### Compliance Framework Validator

Validates document URL protocol, framework type, and organization name:

```typescript
const VALID_FRAMEWORKS = ["gdpr", "pci_dss", "iso_27001", "soc2"];

{
  id: "compliance.validate_inputs_v0",
  fn: (inputs) => {
    const url = String(inputs.document_url || "");
    const fw = String(inputs.framework || "");
    const url_ok = url.startsWith("https://");
    const fw_ok = VALID_FRAMEWORKS.includes(fw);
    const org_ok = String(inputs.org_name || "").trim().length >= 2;
    return {
      ok: true,
      value: {
        inputs_valid: url_ok && fw_ok && org_ok,
        url_ok,
        framework_ok: fw_ok,
        org_ok,
        document_url: url,
        framework: fw,
      },
      step_id: "validate_inputs",
    };
  },
}
```

资料来源：[dist-test/src/validators/compliance.js:1-30]()

## Adding a New Validator

To add a new domain validator:

1. Create a new file in `src/validators/` (e.g., `new_domain.ts`)
2. Export an array conforming to `Array<{ id: string; fn: ValidatorFn }>`
3. Import and add to the aggregator in `src/validators/registry.ts`
4. Use the naming convention: `{domain}.{validator_name}_v{version}`

资料来源：[src/validators/registry.ts:1-2]()

### Naming Convention

| Component | Format | Example |
|-----------|--------|---------|
| Domain prefix | `{domain}` | `invoice`, `supply_chain` |
| Validator name | `{validator_name}` | `validate_inputs`, `sanity_check` |
| Version | `_v{version}` | `_v0`, `_v1` |

## Security Model

The validator registry enforces a strict allowlist:

- **No dynamic code execution**: Validators must be pre-registered
- **No external function calls**: Only functions in the registry may execute
- **No runtime injection**: Validator IDs must match registry entries exactly

```mermaid
sequenceDiagram
    participant Contract as Contract Manifest
    participant Registry as VALIDATOR_REGISTRY
    participant Executor as Contract Executor
    
    Contract->>Executor: ValidatorRef{validator_id}
    Executor->>Registry: get(validator_id)
    alt ID exists in registry
        Registry-->>Executor: ValidatorFn
        Executor->>Executor: Call fn(inputs)
        Executor-->>Contract: result.value
    else ID not in registry
        Registry-->>Executor: undefined
        Executor-->>Contract: VALIDATOR_NOT_ALLOWED error
    end
```

This security boundary ensures that contract execution can only call explicitly approved validation logic, preventing arbitrary code execution during workflow runs.

## Validation Result Usage

Validation results populate the `analysis` object in contract state:

| Key Pattern | Source | Description |
|-------------|--------|-------------|
| `inputs_valid` | All validators | Boolean pass/fail indicator |
| `{field}_ok` | Domain validators | Individual field validation status |
| `{step_id}_error` | Executor | Error messages on failure |

These values are then available as `validatorContext` for subsequent validators in the same step, enabling cascading validation logic.

---

<a id='page-data-schemas'></a>

## Data Schemas and Types

### 相关页面

相关主题：[Domain Validators](#page-validators), [Core MCP Tools](#page-core-tools)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/schemas.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/schemas.ts)
- [src/types.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/types.ts)
- [src/validation/dataspec.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validation/dataspec.ts)
- [src/package_support.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/package_support.ts)
- [src/index.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)
- [src/validators/supply_chain.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/supply_chain.ts)
- [src/transports/local_seam_bridge.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
- [server.json](https://github.com/mova-compact/mova-flat-runner/blob/main/server.json)
</details>

# Data Schemas and Types

This document describes the core data schemas, type definitions, and validation mechanisms in the mova-flat-runner MCP server. The system uses TypeScript-first type definitions with JSON Schema validation for package manifests and runtime data validation.

## Overview

The mova-flat-runner implements a governed AI workflow execution engine with multiple execution modes, contract-based state management, and human-in-the-loop approval gates. The type system is designed to enforce contract integrity across local and remote execution contexts.

```mermaid
graph TB
    subgraph "Type System Layers"
        JS[TypeScript Types]
        SCH[JSON Schemas]
        VAL[Validators]
    end
    
    subgraph "Runtime Contexts"
        LOCAL[Local Seam Bridge]
        REMOTE[Remote API Bridge]
    end
    
    subgraph "Execution Modes"
        AI[AI_ATOMIC]
        DET[DETERMINISTIC]
        HUM[HUMAN_GATE]
        CTR[CONTRACT_CALL]
    end
    
    JS --> SCH
    JS --> VAL
    SCH --> LOCAL
    SCH --> REMOTE
```

## Core Type Definitions

### MovaConfig

Configuration object for MOVA API connectivity. Required for all MCP tool executions.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `apiUrl` | `string` | Yes | Base URL for MOVA API (default: `https://api.mova-lab.eu`) |
| `apiKey` | `string` | Yes | API authentication key |
| `llmKey` | `string` | No | OpenRouter API key for LLM analysis steps |
| `llmModel` | `string` | No | OpenRouter model ID (default: `openai/gpt-4o-mini`) |
| `timeoutMs` | `number` | No | Request timeout in milliseconds |
| `invokeToken` | `string` | No | Local HTTP mode invocation token |

资料来源：[src/index.ts:MovaConfig]()

### FlatRunnerResult

Standard response envelope for all MCP tool operations.

| Field | Type | Description |
|-------|------|-------------|
| `ok` | `boolean` | Success indicator |
| `error_code` | `string` | Error code on failure |
| `error_message` | `string` | Human-readable error description |
| `http_status` | `number` | HTTP status equivalent |

```typescript
interface FlatRunnerResult {
  ok: boolean;
  error_code?: string;
  error_message?: string;
  http_status?: number;
}
```

资料来源：[src/index.ts:FlatRunnerResult]()

### ValidatorFn

Function signature for custom contract validators.

```typescript
type ValidatorFn = (context: Record<string, unknown>) => {
  ok: boolean;
  value?: Record<string, unknown>;
  step_id?: string;
};
```

资料来源：[src/validators/supply_chain.ts:ValidatorFn]()

## Execution Modes

The system defines four distinct execution modes for contract steps:

| Mode | Description | Required Fields | Validation |
|------|-------------|-----------------|------------|
| `AI_ATOMIC` | LLM-powered single-step execution | `model` | Step must declare a model field |
| `DETERMINISTIC` | Local JavaScript execution | None | Cannot have model field |
| `HUMAN_GATE` | Human approval required | `decision_options` | Must have decision_options array |
| `CONTRACT_CALL` | Cross-contract invocation | `contract_id` | Must specify target contract |

```mermaid
stateDiagram-v2
    [*] --> DETERMINISTIC: Local check
    [*] --> AI_ATOMIC: LLM analysis
    [*] --> HUMAN_GATE: Approval required
    [*] --> CONTRACT_CALL: Cross-contract

    DETERMINISTIC --> [*]: Complete
    AI_ATOMIC --> [*]: Complete
    HUMAN_GATE --> APPROVED: Human approves
    HUMAN_GATE --> REJECTED: Human rejects
    CONTRACT_CALL --> [*]: Complete
```

资料来源：[src/security/step_mode_guard.ts:StepExecutionMode]()

## Step Mode Validation

The `step_mode_guard` module enforces execution mode consistency through the `assertStepModesValid` function:

```typescript
export function assertStepModesValid(
  flow: unknown,
  requestId: string,
): FlatRunnerResult | null {
  const violations = findStepModeViolations(flow);
  if (violations.length === 0) return null;
  return flatErr(
    ERR.STEP_MODE_FIELD_MISMATCH,
    `Step execution_mode does not agree with content fields`,
    { violations, http_status_equivalent: 400 }
  );
}
```

**Violation Types:**

| Kind | Condition |
|------|-----------|
| `ai_atomic_without_model` | AI_ATOMIC mode without `model` field |
| `deterministic_with_model` | DETERMINISTIC mode with `model` field declared |
| `contract_call_without_contract_id` | CONTRACT_CALL without target `contract_id` |
| `human_gate_without_decisions` | HUMAN_GATE without `decision_options` array |

资料来源：[src/security/step_mode_guard.ts:findStepModeViolations]()

## Package Manifest Schema

### Global Package Shape

The `validatePackageGlobalShape` function enforces structure for contract package manifests:

```typescript
export function validatePackageGlobalShape(value: unknown): string | null {
  if (!isObject(value)) return "global file must be a JSON object";
  const allowedKeys = new Set([
    "schema_id", "global_id", "version", "scope",
    "extends", "semantic_roles", "non_authority_rules"
  ]);
  // ... validation logic
}
```

**Required Fields:**

| Field | Type | Constraint |
|-------|------|------------|
| `schema_id` | `string` | Non-empty |
| `global_id` | `string` | Non-empty |
| `version` | `string` | Non-empty |
| `scope` | `string` | Must be `"contract_package"` |
| `semantic_roles` | `array` | Non-empty array of role objects |
| `non_authority_rules` | `array` | Non-empty array |

资料来源：[src/package_support.ts:validatePackageGlobalShape]()

### Semantic Role Structure

```typescript
interface SemanticRole {
  id: string;
  role: string;
  authority: string;
  maturity: string;
  applies_to?: string[];
  allowed_use?: string[];
  forbidden_use?: string[];
  notes?: string;
}
```

**Allowed Keys:** `id`, `role`, `authority`, `maturity`, `applies_to`, `allowed_use`, `forbidden_use`, `notes`

资料来源：[src/package_support.ts:roleKeys]()

## Output Schema Resolution

The `resolveOutputSchema` function locates JSON schemas for contract step outputs:

```typescript
async function resolveOutputSchema(
  schemaRef: string,
  flowDir: string
): Promise<Record<string, unknown> | null> {
  const candidates = [
    path.join(flowDir, "_schemas", `${schemaRef}.json`),
    path.join(flowDir, "..", "_data-schemas", `${schemaRef}.json`),
    path.join(flowDir, "..", "..", "_data-schemas", `${schemaRef}.json`),
    ...(process.env.MOVA_SCHEMA_PATH 
      ? [path.join(process.env.MOVA_SCHEMA_PATH, `${schemaRef}.json`)]
      : []
    ),
  ];
  // ... search logic
}
```

**Search Order (priority):**
1. `{flowDir}/_schemas/{schemaRef}.json`
2. `{flowDir}/../_data-schemas/{schemaRef}.json`
3. `{flowDir}/../../_data-schemas/{schemaRef}.json`
4. `$MOVA_SCHEMA_PATH/{schemaRef}.json` (if set)

资料来源：[src/package_support.ts:resolveOutputSchema]()

## Local Seam Bridge Types

### BridgeRequest

```typescript
interface BridgeRequest {
  contractRef: string;
  packagePath: string;
  step: {
    id: string;
    execution_mode: StepExecutionMode;
  };
  outputSchemaPath?: string;
  taskType?: string;
  stepResult?: unknown;
  terminalOutcome?: string;
  humanDecision?: string;
  routeKey?: string;
}
```

### BridgeResponse

```typescript
interface BridgeResponse {
  ok: boolean;
  bridge: {
    ok: boolean;
    bridge_source: string;
    status: "completed" | "advanced" | "human_gate_required";
    contract_ref: string;
    current_step_id: string;
    execution_mode: StepExecutionMode;
    produced_output: unknown;
    proof_ref: string;
    state_ref: string;
    next_state_ref: string;
    decision_kind: { kind: "Pass" | "Fail" };
    commit_effect: { kind: "Apply" | "Skip" };
    next_phase: { phase: "EXECUTION" | "WAIT_HUMAN" };
  };
}
```

资料来源：[src/transports/local_seam_bridge.ts:BridgeRequest]()

## Contract Manifest

The `CONTRACT_MANIFESTS` registry defines built-in contract types:

```typescript
interface ContractManifest {
  contract_type: string;
  title: string;
  version: string;
  execution_mode: StepExecutionMode;
  template_id?: string;
  policy_id?: string;
  dataspec: {
    inputs: Array<{
      key: string;
      label?: string;
      type: string;
      required?: boolean;
    }>;
  };
  decision_options?: Array<{
    id: string;
    label: string;
    description?: string;
  }>;
}
```

资料来源：[src/index.ts:CONTRACT_MANIFESTS]()

## Validation Utilities

### Required String Validation

```typescript
function validateRequiredString(
  obj: Record<string, unknown>,
  key: string,
  scope: string
): string | null {
  if (typeof obj[key] !== "string" || (obj[key] as string).trim().length === 0) {
    return `${scope} is missing required string field "${key}"`;
  }
  return null;
}
```

### Public Shape Sanitization

The `sanitizePublicShape` function filters internal bridge fields from public responses:

```typescript
function sanitizePublicShape(value: unknown): boolean {
  const BLOCKED_KEYS = [
    "bridge_anchors",
    "last_terminal_bridge",
    "terminal_commit_count",
    "_state15_bridge",
    "trace",
    "outputs",
    "context"
  ];
  // Recursively validates and filters
}
```

资料来源：[src/transports/local_seam_bridge.ts:sanitizePublicShape]()

## MCP Server Configuration Schema

Defined in `server.json` per Model Context Protocol specification:

```json
{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "name": "io.github.mova-compact/mova-flat-runner",
  "version": "2.0.6"
}
```

**Environment Variables:**

| Variable | Required | Description |
|----------|----------|-------------|
| `MOVA_API_KEY` | Yes | API key for MOVA backend |
| `LLM_KEY` | Yes | OpenRouter API key |
| `LLM_MODEL` | No | OpenRouter model ID |
| `MOVA_API_URL` | No | Override default API URL |

资料来源：[server.json:environmentVariables]()

## Error Types

| Error Code | HTTP Status | Description |
|------------|-------------|-------------|
| `UNKNOWN_CONTRACT_TYPE` | 404 | Contract type not found in manifests |
| `LOCAL_VALIDATION_FAILED` | 400 | Input validation failed |
| `STEP_MODE_FIELD_MISMATCH` | 400 | Execution mode conflicts with fields |
| `MOVA_API_ERROR` | 502 | Upstream API failure |
| `MOVA_API_404` | 404 | Resource not found on backend |

资料来源：[src/index.ts:ERR]()

## Type Exports Summary

| File | Primary Exports |
|------|-----------------|
| `src/types.ts` | Core type interfaces (MovaConfig, FlatRunnerResult) |
| `src/schemas.ts` | JSON Schema definitions for validation |
| `src/validation/dataspec.ts` | Data specification validators |
| `src/package_support.ts` | Package manifest validation |
| `src/security/step_mode_guard.ts` | Execution mode validation |

资料来源：[src/types.ts](), [src/schemas.ts](), [src/validation/dataspec.ts]()

---

<a id='page-deployment'></a>

## Deployment and Operations

### 相关页面

相关主题：[Installation and Setup](#page-installation-setup), [Transport Layer](#page-transport-layer), [Extensibility and Customization](#page-extensibility)

<details>
<summary>Relevant Source Files</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/mova-compact/mova-flat-runner/blob/main/README.md)
- [package.json](https://github.com/mova-compact/mova-flat-runner/blob/main/package.json)
- [server.json](https://github.com/mova-compact/mova-flat-runner/blob/main/server.json)
- [src/index.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)
- [src/transports/local_seam_bridge.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
</details>

# Deployment and Operations

## Overview

The MOVA Flat Runner is distributed as an MCP (Model Context Protocol) server package (`@leryk1981/mova-flat-runner`) that provides governed AI workflow capabilities including invoice OCR, AML triage, credit review, and custom contracts with human approval gates and audit trails.

This section covers the deployment architecture, build system, runtime configuration, publishing workflow, and operational considerations for running the MOVA Flat Runner in production and development environments.

## Architecture Overview

```mermaid
graph TD
    subgraph "Client Layer"
        Claude["Claude Desktop"]
        Codex["Codex IDE"]
    end
    
    subgraph "MCP Transport"
        STDIO["STDIO Transport"]
        HTTP["Local HTTP Mode"]
    end
    
    subgraph "MOVA Flat Runner"
        Index["src/index.ts"]
        API["HTTP Handlers"]
        Auth["Authentication"]
        Service["Business Logic"]
    end
    
    subgraph "External Services"
        MOVA_API["MOVA API"]
        LLM["LLM Provider"]
    end
    
    Claude --> STDIO
    Codex --> HTTP
    STDIO --> Index
    HTTP --> Index
    Index --> API
    Index --> Auth
    Index --> Service
    Service --> MOVA_API
    Service --> LLM
```

## Build System

### TypeScript Configuration

The project uses TypeScript with separate configurations for production and testing builds.

**Production Build (`tsconfig.json`)**

| Setting | Value | Purpose |
|---------|-------|---------|
| `target` | `ES2022` | ECMAScript target version |
| `module` | `ES2022` / `NodeNext` | ESM module system |
| `outDir` | `dist` | Compiled output directory |
| `rootDir` | `src` | Source root directory |
| `strict` | `true` | Enable strict type checking |

**Test Build (`tsconfig.test.json`)**

| Setting | Value | Purpose |
|---------|-------|---------|
| `extends` | `./tsconfig.json` | Inherits base config |
| `outDir` | `dist-test` | Separate test output directory |
| `rootDir` | `src` | Source root directory |

### Build Pipeline

```mermaid
graph LR
    A["src/*.ts"] --> B["tsc compiler"]
    B --> C["dist/index.js"]
    C --> D["shebang injection"]
    D --> E["chmod +x"]
    
    F["src/*.ts"] --> G["tsc (test config)"]
    G --> H["dist-test/"]
```

### npm Scripts

| Script | Command | Purpose |
|--------|---------|---------|
| `build` | `tsc && node -e "..."` | Compile TypeScript and make executable |
| `check` | `make check` | Run lint, unit tests, and integration tests |
| `test:build` | `tsc -p tsconfig.test.json` | Build test artifacts |

资料来源：[package.json:18-24]()

## MCP Server Configuration

### Server Metadata

```json
{
  "name": "io.github.mova-compact/mova-flat-runner",
  "version": "2.0.6",
  "description": "Governed AI workflows with human approval gates and audit trails",
  "repository": {
    "url": "https://github.com/mova-compact/mova-flat-runner",
    "source": "github"
  }
}
```

### Runtime Hints

| Property | Value | Notes |
|----------|-------|-------|
| `runtimeHint` | `node` | Requires Node.js runtime |
| `transport` | `stdio` | Primary transport protocol |

资料来源：[server.json:1-15]()

## Environment Variables

### Required Variables

| Variable | Description | Example |
|----------|-------------|---------|
| `MOVA_API_KEY` | MOVA API authentication key | `__SET_MOVA_API_KEY__` |
| `LLM_KEY` | OpenRouter API key for LLM analysis | `__SET_LLM_KEY__` |

### Optional Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `MOVA_API_URL` | `https://api.mova-lab.eu` | MOVA API base URL |
| `LLM_MODEL` | `openai/gpt-4o-mini` | OpenRouter model ID |
| `MOVA_API_TIMEOUT_MS` | `30000` | API request timeout |
| `MOVA_HTTP_PORT` | `3796` | Local HTTP mode port |
| `MOVA_INVOKE_TOKEN` | — | Token for local HTTP invocation |

资料来源：[README.md:40-57]()

## Publishing and Distribution

### Publishing Workflow

The project includes a dedicated CLI tool for publishing servers to the MCP registry.

```bash
# Build the publisher CLI
make publisher

# Publish a server
./bin/mcp-publisher --help
```

### npm Distribution

The package is published to npm as `@leryk1981/mova-flat-runner`:

| Property | Value |
|----------|-------|
| Package Name | `@leryk1981/mova-flat-runner` |
| Current Version | `3.3.4` |
| Binary | `mova-mcp` |
| Entry Point | `dist/index.js` |

资料来源：[package.json:3-6]()

### Client Configuration Examples

**Claude Desktop (JSON)**

```json
{
  "mcpServers": {
    "mova": {
      "command": "npx",
      "args": ["-y", "@leryk1981/mova-flat-runner@3.3.3"],
      "env": {
        "MOVA_API_URL": "https://api.mova-lab.eu",
        "MOVA_API_KEY": "__SET_MOVA_API_KEY__",
        "LLM_KEY": "__SET_LLM_KEY__",
        "LLM_MODEL": "openai/gpt-4o-mini"
      }
    }
  }
}
```

**Codex (TOML)**

```toml
[mcp_servers.mova]
command = "npx"
args = ["-y", "@leryk1981/mova-flat-runner@3.3.3"]
startup_timeout_sec = 90.0

[mcp_servers.mova.env]
MOVA_API_URL = "https://api.mova-lab.eu"
MOVA_API_KEY = "__SET_MOVA_API_KEY__"
LLM_KEY = "__SET_LLM_KEY__"
LLM_MODEL = "openai/gpt-4o-mini"
```

资料来源：[README.md:63-100]()

## Deployment Configuration

### Project Structure

```
mova-flat-runner/
├── cmd/                     # Application entry points
│   └── publisher/           # Server publishing tool
├── deploy/                  # Deployment configuration (Pulumi)
├── internal/                # Private application code
│   ├── api/                 # HTTP handlers and routing
│   ├── auth/                # Authentication (GitHub OAuth, JWT)
│   ├── config/              # Configuration management
│   ├── database/            # Data persistence (PostgreSQL)
│   ├── service/             # Business logic
│   ├── telemetry/           # Metrics and monitoring
│   └── validators/          # Input validation
├── pkg/                     # Public packages
└── tools/                   # Operational tools
```

### Pulumi Deployment

Infrastructure is managed via Pulumi in the `deploy/` directory. This enables repeatable, version-controlled infrastructure deployments.

资料来源：[README.md:12-29]()

## Health Monitoring

### Health Check Endpoint

```bash
curl -sS https://api.mova-lab.eu/health
```

### Available Tools for Monitoring

| Tool | Purpose |
|------|---------|
| `mova_health` | Server health status |
| `mova_registry` | MCP registry information |
| `mova_run` | Contract execution |
| `mova_query` | Query contract status |
| `mova_decide` | Human decision handling |
| `mova_connector` | External system integration |
| `mova_contract` | Contract management |

资料来源：[README.md:58-60]()

## Local HTTP Mode Operations

### Overview

The flat runner supports an optional local HTTP transport mode for environments where STDIO is not suitable.

```mermaid
graph TD
    Client["MCP Client"] --> |HTTP Request| LocalHTTP["Local HTTP Bridge"]
    LocalHTTP --> |STDIO| MOVA_MCP["MOVA MCP Server"]
    MOVA_MCP --> |Response| LocalHTTP
    LocalHTTP --> |HTTP Response| Client
    
    subgraph "Local Environment"
        LocalHTTP
        MOVA_MCP
    end
```

### Configuration

```env
MOVA_HTTP_PORT=3796
MOVA_INVOKE_TOKEN=__SET_LOCAL_INVOKE_TOKEN__
MOVA_API_TIMEOUT_MS=30000
```

### Security Considerations

- `MOVA_INVOKE_TOKEN` must be set to authorize local HTTP requests
- API timeouts prevent hanging requests (default: 30 seconds)
- Health checks should be performed before heavy operations

资料来源：[README.md:50-55]()

## Development Operations

### Makefile Targets

| Target | Purpose |
|--------|---------|
| `make check` | Run lint, unit tests, integration tests |
| `make help` | Display available commands |
| `make publisher` | Build the MCP publisher CLI |

### Validation Workflow

```mermaid
graph LR
    A["npm run build"] --> B["npm run test:build"]
    B --> C["npm run smoke:*"]
    C --> D["Validation Complete"]
```

### Smoke Testing

Custom bridge validation:

```bash
npm run smoke:custom-bridge
```

This validates the custom contract query bridge for handling `mova_query` requests when the backend namespace is absent.

资料来源：[tasks/task061.md:1-50]()

## Operational Data Flows

### Local Seam Bridge Execution

```mermaid
sequenceDiagram
    participant MCP as MCP Client
    participant Bridge as Local Seam Bridge
    participant Machine as State Machine
    participant FS as File System
    
    MCP->>Bridge: Execute step with state
    Bridge->>Machine: Load machine module
    Machine->>FS: Read state file
    FS-->>Machine: State data
    Machine->>Machine: Execute step logic
    Machine->>FS: Write updated state
    Bridge->>MCP: Return result with proofs
```

### Custom Contract Bridge

For custom contract IDs (prefixed with `local-*` or `remote-*`), the system maintains an in-memory bridge map:

```typescript
CUSTOM_RUN_BRIDGE: Map<contract_id, {run_id, updated_at, source_url?}>
```

资料来源：[src/index.ts:1-100]()

## Security Notes

### Environment Variable Security

| Practice | Requirement |
|----------|-------------|
| Placeholders in docs | Use `__SET_*__` format |
| Real secrets | Never commit to repository |
| API keys | Use `MOVA_API_KEY`, `LLM_KEY` |

> **Warning**: Do not commit real `MOVA_API_KEY`, `LLM_KEY`, or `MOVA_INVOKE_TOKEN` to version control.

资料来源：[README.md:37-39]()

### Step Mode Validation

The system validates step execution modes at runtime:

| Mode | Validation Rule |
|------|-----------------|
| `DETERMINISTIC` | Cannot have `model` field |
| `AI_ATOMIC` | Must have `model` field |
| `CONTRACT_CALL` | Must have `contract_id` |
| `HUMAN_GATE` | Must have `decision_options` array |

资料来源：[dist-test/src/security/step_mode_guard.js:1-50]()

## Deployment Environments

### Build Variants

| Branch | Purpose | Build Output |
|--------|---------|--------------|
| `main` | Production builds | `dist/` |
| `main-<date>-<sha>` | Specific commit builds | `dist/` |

### Continuous Integration

```
main branch → Continuous build → Latest stable release
```

资料来源：[README.md:1-5]()

## Troubleshooting

| Issue | Resolution |
|-------|------------|
| Build fails | Run `npm run build` |
| Test failures | Run `make check` |
| MCP connection issues | Verify `MOVA_API_KEY` and `LLM_KEY` |
| Custom contract 404 | Use `mova_contract` for custom IDs |
| Human gate timeout | Check `MOVA_API_TIMEOUT_MS` setting |

## Related Documentation

- [Quickstart Guide](./docs/modelcontextprotocol-io/quickstart.mdx)
- [Live API Docs](https://registry.modelcontextprotocol.io/docs)
- [Ecosystem Vision](./docs/design/ecosystem-vision.md)

---

<a id='page-extensibility'></a>

## Extensibility and Customization

### 相关页面

相关主题：[Domain Validators](#page-validators), [Security Guards](#page-security-guards), [Deployment and Operations](#page-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/validators/registry.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/registry.ts)
- [src/validators/supply_chain.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/validators/supply_chain.ts)
- [src/index.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/index.ts)
- [src/transports/local_seam_bridge.ts](https://github.com/mova-compact/mova-flat-runner/blob/main/src/transports/local_seam_bridge.ts)
- [dist-test/src/package_support.js](https://github.com/mova-compact/mova-flat-runner/blob/main/dist-test/src/package_support.js)
</details>

# Extensibility and Customization

The mova-flat-runner provides multiple layers of extensibility, allowing operators to add custom validators, define new contract types, extend execution modes, and integrate with external systems. This document describes the core extension points and customization mechanisms available in the MCP server.

## 1. Validator Registry System

### 1.1 Architecture Overview

The validator registry is the primary extension point for business logic validation. It implements a **whitelist-based security model** where only explicitly registered validator functions may be invoked during contract execution. Dynamic code execution is prohibited.

```mermaid
graph TD
    A[Contract Execution] --> B{ValidatorRef found?}
    B -->|Yes| C[Lookup in VALIDATOR_REGISTRY]
    B -->|No| D[Return VALIDATOR_NOT_ALLOWED error]
    C --> E{Validator registered?}
    E -->|Yes| F[Execute ValidatorFn]
    E -->|No| D
    F --> G[Return validation result]
    D --> H[Audit log: validator blocked]
```

### 1.2 Registry Implementation

The `VALIDATOR_REGISTRY` is a `Map<string, ValidatorFn>` that maps each validator's unique identifier to its implementation function. All validators must conform to the `ValidatorFn` type signature.

**Type Signature:**
```typescript
type ValidatorFn = (inputs: Record<string, unknown>) => {
    ok: boolean;
    value: Record<string, unknown>;
    step_id: string;
};
```

### 1.3 Registered Validator Modules

| Module | Source File | Validators |
|--------|-------------|------------|
| Invoice | `invoice.ts` | invoice validation validators |
| Purchase Order | `po.ts` | PO validation validators |
| Trade | `trade.ts` | trade validation validators |
| AML | `aml.ts` | AML triage validators |
| Complaint | `complaint.ts` | complaint handling validators |
| Compliance | `compliance.ts` | compliance check validators |
| Credit | `credit.ts` | credit review validators |
| Supply Chain | `supply_chain.ts` | supplier validation validators |
| Churn | `churn.ts` | churn prediction validators |
| Contract Gen | `contract_gen.ts` | contract generation validators |

资料来源：[src/validators/registry.ts:1-28]()

### 1.4 Adding a New Validator

To add a new validator:

1. **Implement the validator function** in a contract-specific file following the `ValidatorFn` signature
2. **Export it** as part of a validator array with a unique `id`
3. **Register it** in `src/validators/registry.ts`

**Example from supply_chain.ts:**
```typescript
export const supplyChainValidators: Array<{ id: string; fn: ValidatorFn }> = [
  {
    id: "supply_chain.validate_inputs_v0",
    fn: (inputs) => {
      const suppliers = Array.isArray(inputs.suppliers) ? inputs.suppliers : [];
      const valid_items = suppliers.filter(s =>
        s && typeof s === "object" &&
        String(s["id"] || "").length > 0 &&
        /^[A-Z]{2}$/.test(String(s["country"] || ""))
      );
      return {
        ok: true,
        value: {
          inputs_valid: valid_items.length === suppliers.length,
          supplier_count: suppliers.length,
        },
        step_id: "validate_inputs",
      };
    },
  },
];
```

资料来源：[src/validators/supply_chain.ts:1-35]()

### 1.5 Security Model

The registry enforces these security constraints:

| Constraint | Description |
|------------|-------------|
| Whitelist-only | Only functions in the registry may execute |
| No dynamic code | Arbitrary code execution is forbidden |
| Type enforcement | All validators must return `{ok, value, step_id}` |
| Step isolation | Validators operate on sanitized input contexts |

During contract execution, the runner checks each `ValidatorRef` against the registry before invocation:

```typescript
const fn = VALIDATOR_REGISTRY.get(validator.validator_id);
if (!fn) {
    analysis[`${validator.step_id}_error`] = `VALIDATOR_NOT_ALLOWED: "${validator.validator_id}" not in registry`;
    continue;
}
```

资料来源：[dist-test/src/transports/remote_api.js:1-25]()

## 2. Contract Manifest System

### 2.1 Manifest Structure

Contract manifests define the metadata, inputs, and behavior of each contract type. Built-in manifests are stored in `CONTRACT_MANIFESTS`:

```typescript
type ContractManifest = {
    contract_type: string;
    title: string;
    version: string;
    execution_mode: "AI_ATOMIC" | "HUMAN_GATE" | "LOCAL_SEAM";
    template_id: string;
    policy_id: string;
    dataspec: { inputs: InputSpec[] };
    decision_options?: DecisionOption[];
};
```

### 2.2 Manifest Registry Resources

The MCP server exposes manifests via the `mova://` URI scheme:

| Resource URI | Description |
|--------------|-------------|
| `mova://registry` | Lists all available contract types |
| `mova://schemas/envelopes` | Returns envelope schema definition |
| `mova://contracts/{type}/manifest` | Returns specific contract manifest |

```typescript
function readResource(uri: string): unknown {
  if (uri === "mova://registry") {
    return {
      schema_version: "1.0",
      contracts: Object.values(CONTRACT_MANIFESTS).map(m => ({
        contract_type: m.contract_type,
        title: m.title,
        version: m.version,
        manifest_resource: `mova://contracts/${m.contract_type}/manifest`,
      })),
    };
  }
  // ...
}
```

资料来源：[src/index.ts:300-350]()

## 3. Custom Contract Bridge

### 3.1 The Namespace Gap Problem

Custom contracts registered via `mova_contract register` use `local-*` or `remote-*` ID prefixes and execute in the `/run/*` namespace. However, `mova_query` operations query the `/api/v1/contracts/*` namespace, resulting in 404 errors for custom contracts.

### 3.2 Bridge Implementation

The custom contract bridge provides a mitigation layer:

```mermaid
graph LR
    A[register] --> B[rememberCustomRun]
    B --> C[CUSTOM_RUN_BRIDGE Map]
    C --> D[mova_query status]
    D --> E{404 from API?}
    E -->|Yes| F[getMyContractRecord]
    F --> G{Bridge entry found?}
    G -->|Yes| H[Return bridged status]
    G -->|No| I[Return error]
```

### 3.3 Bridge Components

| Component | Type | Purpose |
|-----------|------|---------|
| `CUSTOM_RUN_BRIDGE` | `Map<contract_id, {run_id, updated_at, source_url?}>` | In-memory ID mapping |
| `rememberCustomRun()` | Function | Captures and persists contract→run mapping |
| `getMyContractRecord()` | Function | Probes `/api/v1/contracts/my` for metadata |

**Memory Bridge Map:**
```typescript
const CUSTOM_RUN_BRIDGE = new Map<string, CustomRunRef>();

function rememberCustomRun(contractId: string, runId: string, sourceUrl?: string): void {
    if (typeof contractId !== "string" || typeof runId !== "string") return;
    const ref = { run_id: runId, updated_at: new Date().toISOString() };
    if (sourceUrl) ref.source_url = sourceUrl;
    CUSTOM_RUN_BRIDGE.set(contractId, ref);
}
```

资料来源：[src/index.ts:400-420]()

### 3.4 Bridge Response Modes

| View Mode | Behavior |
|-----------|----------|
| `status` | Returns structured bridged status with `bridge_mode=custom_contract_run_namespace_bridge_v1` |
| `audit` | Returns `AUDIT_UNAVAILABLE` envelope (honest unavailability) |
| `audit_compact` | Returns `{ok=false, status=424}` with JSON journal explaining bridge |

资料来源：[tasks/task061.md:1-60]()

## 4. Local Seam Execution Mode

### 4.1 Overview

The `LOCAL_SEAM` execution mode allows contracts to run entirely within the MCP server process, bypassing the remote MOVA API. This is critical for offline development and testing scenarios.

### 4.2 Execution Flow

```mermaid
graph TD
    A[mova_run contract_type] --> B{Is LOCAL_SEAM?}
    B -->|No| C[Remote API execution]
    B -->|Yes| D[Resolve local locator]
    D --> E[Load sandbox package]
    E --> F[Execute steps locally]
    F --> G{Step type?}
    G -->|AI_ATOMIC| H[LLM invocation]
    G -->|HUMAN_GATE| I[Wait for gate decision]
    G -->|Standard| J[Apply step logic]
    H --> K[Validate output schema]
    I --> L[Bridge to human approval]
    J --> K
    K --> M{More steps?}
    M -->|Yes| F
    M -->|No| N[Return FlatRunnerResult]
```

### 4.3 Local Seam Locator Resolution

```typescript
async function resolveLocalSeamLocator(initialInputs: Record<string, unknown>): Promise<SeamLocator> {
    const packagePath = initialInputs.package_path 
        ?? process.env.MOVA_SANDBOX_PACKAGE_PATH 
        ?? "default-contract-path";
    const projectPath = initialInputs.project_path 
        ?? process.env.MOVA_SANDBOX_PROJECT_PATH 
        ?? "";
    // ...
}
```

资料来源：[src/transports/local_seam_bridge.ts:50-80]()

### 4.4 Sandbox Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `MOVA_SANDBOX_PACKAGE_PATH` | Path to contract package | Project-specific |
| `MOVA_SANDBOX_PROJECT_PATH` | Path to project directory | Required |
| `MOVA_SANDBOX_STATE_FILE` | State persistence file | System temp |

## 5. Package Global Support

### 5.1 Package Manifest Validation

Custom contract packages must include a `global` file conforming to the `contract_package` scope. The validation enforces strict schema requirements:

**Required Fields:**

| Field | Type | Constraint |
|-------|------|------------|
| `global_id` | string | Non-empty |
| `version` | string | Non-empty |
| `scope` | string | Must be `contract_package` |
| `extends` | array | Optional, must be array if present |
| `semantic_roles` | array | Non-empty, objects with allowed keys |
| `non_authority_rules` | array | Non-empty |

**Validation Rules for semantic_roles:**
```javascript
const roleKeys = new Set([
    "id", "role", "authority", "maturity", 
    "applies_to", "allowed_use", "forbidden_use", "notes"
]);
for (const key of Object.keys(role)) {
    if (!roleKeys.has(key))
        return `global semantic_roles[${index}] contains unsupported field "${key}"`;
}
```

资料来源：[dist-test/src/package_support.js:1-30]()

### 5.2 Global File Schema

```typescript
interface PackageGlobal {
    global_id: string;
    version: string;
    scope: "contract_package";
    extends?: string[];
    semantic_roles: Array<{
        id: string;
        role: string;
        authority: string;
        maturity: string;
        applies_to?: string;
        allowed_use?: string[];
        forbidden_use?: string[];
        notes?: string;
    }>;
    non_authority_rules: string[];
}
```

## 6. MCP Tool Extensibility

### 6.1 Available Tools

| Tool | Purpose | Extensibility |
|------|---------|---------------|
| `mova_health` | Health check | Fixed |
| `mova_registry` | List contract types | Fixed |
| `mova_run` | Execute built-in contracts | Extend via CONTRACT_MANIFESTS |
| `mova_query` | Query contract status/audit | Bridge extensible |
| `mova_decide` | Submit human decisions | Fixed |
| `mova_connector` | Connect to external systems | Fixed |
| `mova_contract` | Custom contract operations | Core extensibility interface |

### 6.2 Tool Executor Pattern

Tools are registered in a switch-based executor that maps tool names to handler functions:

```typescript
async function executeTool(name: string, args: Args): Promise<string> {
  const requestId = shortId();
  switch (name) {
    case "mova_run": {
      const manifest = CONTRACT_MANIFESTS[contractType];
      if (!manifest) {
        return JSON.stringify(flatErr(
          ERR.UNKNOWN_CONTRACT_TYPE,
          `Unknown contract_type "${contractType}". For custom contracts use mova_contract action=run.`,
          { available: Object.keys(CONTRACT_MANIFESTS) },
          false, requestId
        ));
      }
      // ...
    }
  }
}
```

资料来源：[src/index.ts:450-480]()

## 7. Configuration Extension Points

### 7.1 Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `MOVA_API_URL` | Yes | MOVA API base URL |
| `MOVA_API_KEY` | Yes | API authentication key |
| `LLM_KEY` | Conditional | OpenRouter API key for LLM steps |
| `LLM_MODEL` | No | Model identifier, default: `openai/gpt-4o-mini` |
| `MOVA_API_TIMEOUT_MS` | No | HTTP timeout in milliseconds |
| `MOVA_HTTP_PORT` | No | Local HTTP mode port |
| `MOVA_INVOKE_TOKEN` | No | Local invoke authentication |

### 7.2 Config Merging

The configuration system supports runtime overrides through environment variables, with precedence: CLI args > env vars > defaults.

## 8. Extension Summary

```mermaid
graph TD
    subgraph Extension Points
        A[Validator Registry]
        B[Contract Manifests]
        C[Package Global]
        D[Local Seam Mode]
    end
    
    subgraph Security Layer
        E[Whitelist Enforcement]
        F[Type Validation]
        G[Schema Validation]
    end
    
    subgraph MCP Tools
        H[mova_contract]
        I[mova_run]
        J[mova_query]
    end
    
    A --> E
    B --> G
    C --> G
    D --> F
    H --> A
    H --> B
    I --> A
    J --> C
    J --> D
```

The mova-flat-runner's extensibility model is designed for **operator-controlled customization** while maintaining strict security boundaries. Validators, contracts, and execution modes can be extended without modifying core server code, enabling safe customization in regulated environments.

---

---

## Doramagic 踩坑日志

项目：mova-compact/mova-flat-runner

摘要：发现 8 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：配置坑 - 可能修改宿主 AI 配置。

## 1. 配置坑 · 可能修改宿主 AI 配置

- 严重度：medium
- 证据强度：source_linked
- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。
- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。
- 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。
- 防护动作：涉及宿主配置目录时必须给回滚路径，不能只给安装命令。
- 证据：capability.host_targets | github_repo:1212840167 | https://github.com/mova-compact/mova-flat-runner | host_targets=mcp_host, claude, chatgpt

## 2. 配置坑 · 来源证据：v3.0.0 — Step Enforcement Runtime

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个配置相关的待验证问题：v3.0.0 — Step Enforcement Runtime
- 对用户的影响：可能影响升级、迁移或版本选择。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_10b68dae59184a36b21a563722829aed | https://github.com/mova-compact/mova-flat-runner/releases/tag/v3.0.0 | 来源类型 github_release 暴露的待验证使用条件。

## 3. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | github_repo:1212840167 | https://github.com/mova-compact/mova-flat-runner | README/documentation is current enough for a first validation pass.

## 4. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | github_repo:1212840167 | https://github.com/mova-compact/mova-flat-runner | last_activity_observed missing

## 5. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | github_repo:1212840167 | https://github.com/mova-compact/mova-flat-runner | no_demo; severity=medium

## 6. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | github_repo:1212840167 | https://github.com/mova-compact/mova-flat-runner | no_demo; severity=medium

## 7. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | github_repo:1212840167 | https://github.com/mova-compact/mova-flat-runner | issue_or_pr_quality=unknown

## 8. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | github_repo:1212840167 | https://github.com/mova-compact/mova-flat-runner | release_recency=unknown

<!-- canonical_name: mova-compact/mova-flat-runner; human_manual_source: deepwiki_human_wiki -->
