# Formatter, flow-control & misc blocks

Category dirs: `inference/core/workflows/core_steps/formatters/**`, `.../flow_control/**`, `.../math/**` (+ misc utilities). See the universal invariants section in `SKILL.md` first.

**What / when.** The grab-bag of non-model blocks: reshape/extract data (formatters), gate or throttle execution (flow-control), and small analytical utilities (math, sampling). Reach here when you're routing/branching a workflow, turning one kind into another (VLM text → detections, dict → CSV), extracting a scalar for a downstream `Continue If`, or doing per-frame stateful bookkeeping.

**Mental model.** Every block subclasses `WorkflowBlock` + `WorkflowBlockManifest` from `inference/core/workflows/prototypes/block.py`. Two sub-shapes:
- **Formatters / math** — pure functions. Consume some kind(s), produce a transformed kind. Most declare a single generic output (`OutputDefinition(name="output")`, no `kind=` → wildcard) and lean on the UQL operations engine (`build_operations_chain` / `build_eval_function`) rather than hand-written logic. See `formatters/property_definition/v1.py` and `formatters/expression/v1.py`.
- **Flow-control** — return `FlowControl` (from `execution_engine/v1/entities`), NOT a data dict. `describe_outputs` returns `[]`; the block's job is to emit `FlowControl(mode="select_step", context=next_steps)` or `FlowControl(mode="terminate_branch")`. `block_type="flow_control"` and they take a `next_steps: List[StepSelector]`. See `flow_control/continue_if/v1.py`.

Statefulness splits the category: formatters/math are stateless; flow-control and sampling blocks (`rate_limiter`, `delta_filter`, `identify_outliers`, `continue_if` with `stop_delay`) carry `__init__` instance state across `run` calls.

**Nuances an author MUST know.**
- **Flow-control returns `FlowControl`, not outputs.** `describe_outputs()` MUST be `[]`. Terminating a branch is `FlowControl(mode="terminate_branch")`; continuing is `mode="select_step", context=next_steps`. Guard the empty-`next_steps` case (`continue_if/v1.py`).
- **Statefulness is broken behind HTTP.** Instance state (`self._last_executed_at`, `self.cache`, `self.start_time`) only persists in a long-lived video pipeline; behind stateless HTTP each request is a fresh instance so throttling/delta silently no-op. Declare this via `get_restrictions()` returning `RuntimeRestriction` constants — `COOLDOWN_HTTP_SOFT_RESTRICTION` (`rate_limiter/v1.py`), `STATEFUL_VIDEO_HTTP_SOFT_RESTRICTION` + `STILL_IMAGE_INPUT_SOFT_RESTRICTION` (`delta_filter/v1.py`).
- **Per-video state must be keyed + evicted.** `delta_filter` caches by `image.video_metadata.video_identifier` so multiple streams don't cross-contaminate (`delta_filter/v1.py`); `rate_limiter` derives video-time from `1/fps * frame_number` instead of wall-clock so throttling is correct under faster-than-realtime playback (`rate_limiter/v1.py`). If you keep per-stream state, key it and think about growth.
- **Merging conditional branches needs `accepts_empty_values`.** By default a block is skipped when any input is `None`. `first_non_empty_or_default/v1.py` overrides `accepts_empty_values() -> True` so it actually runs on the `None`s it's meant to coalesce — and its `data` param arrives as a `Batch[Any]` to iterate.
- **Dynamic output keys.** `json_parser` declares a wildcard `OutputDefinition(name="*")` in `describe_outputs`, then resolves real keys per-config via `get_actual_outputs(self)` from `self.expected_fields` (`json_parser/v1.py`). Use this pattern when output keys depend on manifest config; `error_status` is a reserved key both here and in `vlm_as_detector`.
- **Batch/scalar + dimensionality collapse.** `csv_formatter` opts one param into batch delivery via `get_parameters_accepting_batches_and_scalars() -> ["columns_data"]`, then aggregates a whole batch into ONE csv string — returning `None` for all rows but the last (`formatters/csv/v1.py`). This is the idiom for a batch→scalar reducer.
- **VLM→detections is a manual kind constructor.** `vlm_as_detector/v2.py` builds an `sv.Detections` by hand: scales normalized 0–1 coords to pixels via `image.numpy_image.shape[:2]`, maps class names→ids, stuffs `IMAGE_DIMENSIONS_KEY`/`DETECTION_ID_KEY`/`INFERENCE_ID_KEY`/`PREDICTION_TYPE_KEY` into `.data`, and finishes with `attach_parents_coordinates_to_sv_detections(...)` so crop-offset coordinates stay correct. If you emit `OBJECT_DETECTION_PREDICTION_KIND`, you owe the same coordinate-system + metadata contract.
- **Give real `kind=` on typed outputs.** Analytical blocks pin their output kind so the graph validates downstream: `math/cosine_similarity/v1.py` → `FLOAT_KIND`; `sampling/identify_outliers/v1.py` → `BOOLEAN_KIND`/`FLOAT_ZERO_TO_ONE_KIND` from `EMBEDDING_KIND` inputs. Only fall back to a bare wildcard `output` when the type genuinely depends on user operations (expression, property_definition).

**Example blocks to pattern-match (simplest → representative).**
- `math/cosine_similarity/v1.py` — the minimal pure formatter: two typed inputs, one `FLOAT_KIND` output, no state, no UQL. Start here.
- `formatters/property_definition/v1.py` — delegating all logic to the UQL operations chain (`build_operations_chain`) and emitting a generic wildcard `output`. Sibling `formatters/expression/v1.py` layers `build_eval_function` on top for switch/case results.
- `flow_control/continue_if/v1.py` — the canonical flow-control shape: `FlowControl` returns, empty `describe_outputs`, `next_steps`, plus optional `stop_delay` state. Pair with `flow_control/rate_limiter/v1.py` (video-time throttling + `RuntimeRestriction`) and `flow_control/delta_filter/v1.py` (per-`video_identifier` cache) for the stateful variants.
- `formatters/first_non_empty_or_default/v1.py` — `accepts_empty_values()` + `Batch[Any]` iteration (branch-merge semantics).
- `formatters/json_parser/v1.py` — config-driven dynamic outputs (`get_actual_outputs` + wildcard `"*"`). `formatters/csv/v1.py` is the batch→scalar reducer counterpart (`get_parameters_accepting_batches_and_scalars`).
- `formatters/vlm_as_detector/v2.py` — the most involved: hand-constructing an `sv.Detections`, coordinate scaling, metadata keys, and `attach_parents_coordinates_to_sv_detections`. The reference for producing a detection kind from raw text.
