# Reserved Names in FlowDrop

This document lists all reserved names in FlowDrop that cannot be used by plugins for custom parameters, outputs, or configuration keys.

## Overview

FlowDrop reserves certain names for system functionality. Plugin developers should avoid using these names in their `getParameterSchema()` and `getOutputSchema()` methods to prevent conflicts.

## Reserved Port Names

### Input Ports

| Name | Purpose | Status |
|------|---------|--------|
| `input` | Unified input port - accepts all connectable parameters as a single JSON object | Active |
| `config` | Reserved for unified config port - will accept all configurable parameters as JSON | Future |
| `trigger` | Flow control signal - triggers node execution | Active |

### Output Ports

| Name | Purpose | Status |
|------|---------|--------|
| `output` | Unified output port - provides all exposed outputs as a single JSON object | Active |
| `trigger` | Flow control signal - emitted when node completes execution | Active |
| `active_branches` | Gateway output - specifies which branch(es) should be executed (see below) | Active |

### `active_branches` Output

The `active_branches` output is a **magic output name** that gateway node processors must return. It indicates which branch(es) the orchestrator should activate for downstream execution.

**Type:** `string` (single branch) or comma-separated string (multiple branches)

**Example:**
```php
return [
  "active_branches" => "true",  // Single branch
  // or
  "active_branches" => "a,b",   // Multiple branches (parallel gateway)
];
```

The orchestrator performs **case-insensitive matching** between `active_branches` and the branch `name` values from the `branches` input parameter.

See [Gateway Nodes and Branching](gateway-nodes.md) for complete documentation.

## Reserved Configuration Keys

These keys are reserved in the node's `configSchema` and cannot be used by plugins:

| Name | Purpose | Status |
|------|---------|--------|
| `instanceTitle` | Override the default node title for a specific instance | Active |
| `instanceDescription` | Override the default node description for a specific instance | Active |
| `branches` | Gateway node conditional output paths (see below) | Active |
| `nodeType` | Visual type selection when multiple types are supported | Active |
| `dynamicInputs` | User-defined dynamic input ports | Active |
| `dynamicOutputs` | User-defined dynamic output ports | Active |
| `maxRetries` | Per-instance retry budget (injected on every executable node) | Active |
| `ports` | Per-instance port order + exposure (see below) | Active |

### `ports` Configuration Key

The `ports` key is injected on every executable node. It stores a per-direction
ordered list of the node's ports, carrying both display order and exposure:

```json
{
  "ports": {
    "inputs":  [{ "id": "value" }, { "id": "trigger", "exposed": false }],
    "outputs": [{ "id": "result" }, { "id": "error", "exposed": true }]
  }
}
```

- **Array index = display order**, relative to the metadata default order. Ports
  carry a default sort weight (`displayOrder`); reserved injected ports
  (`trigger`, `tool`, `error`) default to the bottom.
- **`exposed`** is stored on an entry only when it diverges from the port's
  metadata `exposedByDefault`. A port the author never touched is absent from
  the list; an untouched node stores no `ports` key at all.

Order is **cosmetic** — the engine never reads it. Exposure is **semantic** in
v2 and **enforced by the engine**, not just the editor: a not-exposed port is
hidden on the canvas, not wireable, and not runtime-overridable. The reserved
`error` output ships `exposedByDefault: false`, so wiring it requires first
exposing it here.

Enforcement reads exposure through one accessor,
`\Drupal\flowdrop\Utility\PortExposure::isExposed()` (the PHP mirror of fdnpm's
`isPortExposed`):

- **`WorkflowValidator` (R7)** rejects, at save/import, any edge into a
  not-exposed input port or out of a not-exposed output port — closing the
  hand-edited/stale-JSON gap the editor's no-handle rule can't.
- **`ParameterResolver`** ignores a runtime/LLM value for a not-exposed
  connectable param, so the author's config value wins.
- **`ToolParameterScope`** treats a not-exposed connectable input as pinned:
  it is projected out of the model-facing tool schema and stripped from model
  args. Exposure — not value presence — is the pin signal, so pinning a param
  to empty and exposing a param that carries a default both work.

See [`.claude/plans/exposed-ports.md`](../../.claude/plans/exposed-ports.md).

### `branches` Configuration Key

The `branches` key is special for gateway-type nodes (`visual_type: gateway`). It defines the available conditional output paths:

```json
{
  "branches": [
    { "name": "True", "value": true },
    { "name": "False", "value": false }
  ]
}
```

- **`name`**: Display name that becomes the output port name (e.g., "True" → `{nodeId}-output-True`)
- **`value`**: The value to match against when determining which branch is active

The frontend dynamically generates output ports based on this configuration. The processor must return `active_branches` output indicating which branch(es) were activated.

See [Gateway Nodes and Branching](gateway-nodes.md) for complete documentation.

## Reserved Internal Parameters

Parameters with names starting with double underscore (`__`) are reserved for internal system use. These bypass normal validation and are injected by the orchestrator:

| Name | Purpose |
|------|---------|
| `__state__` | Graph state for stategraph orchestrator |
| `__messages__` | Message history for chat workflows |
| `__data__` | Shared data store |
| `__iterator__` | Iterator state for ForEach loops |
| `__current_item__` | Current item in ForEach iteration |
| `__interrupt_id__` | Interrupt ID for human-in-the-loop resume |

## Validation

During plugin discovery, FlowDrop will log a warning if a plugin defines:

- A parameter with a reserved input port name (`input`, `config`, `trigger`)
- An output with a reserved output port name (`output`, `trigger`)

This helps plugin developers identify potential conflicts early.

## Unified Ports Feature

The unified `input` and `output` ports are optional features that site builders can enable per node type:

### Unified Input Port (`input`)

When enabled via `unified_input_exposed: true`:

- Appears as an additional input port with type `json`
- Accepts all connectable parameters as a single JSON object
- Individual port connections take precedence over values in the unified input
- Non-connectable parameters are filtered out (security)

### Unified Output Port (`output`)

When enabled via `unified_output_exposed: true`:

- Appears as an additional output port with type `json`
- Provides all exposed outputs as a single JSON object
- Non-exposed outputs are filtered out (security)
- Coexists with individual output ports

### Example Usage

```
# Simple data pass-through
upstream.output → processor.input → downstream.input

# Selective override
data_source.output → calculator.input (provides base data)
config_node.precision → calculator.precision (overrides precision)
```

## Best Practices for Plugin Developers

1. **Avoid reserved names** - Do not use `input`, `output`, `config`, `trigger`, `branches`, or `active_branches` as parameter or output names.

2. **Use descriptive names** - Instead of generic names, use specific names like `text_input`, `result_data`, `api_response`.

3. **Check for conflicts** - Review the reserved names list when designing new plugins.

4. **Internal parameters** - Never define parameters starting with `__` (double underscore) as these are reserved for system use.

## See Also

- [FlowDrop Node Processor Development](flowdrop-node-processor.md)
- [Internal Parameters](internal-parameters.md)
- [Gateway Nodes and Branching](gateway-nodes.md)
- [Port Configuration](./port-configuration.md)
