ContextLab / ContextLab/orchestrator

Validation rejects {{ $item }} as a syntax error; the runtime rewrites it

Open
#474 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
3
Forks
2
Avg merge
13m
Merged PRs (30d)
1

Description

## The runtime accepts `{{ $item }}`; validation calls it a syntax error

`UnifiedTemplateResolver._preprocess_dollar_variables` ([unified_template_resolver.py:545](src/orchestrator/core/unified_template_resolver.py#L545)) rewrites `{{ $variable }}` to `{{ variable }}` before rendering, because "Jinja2 doesn't support variables starting with $". It does the same inside `{% %}` blocks.

`TemplateValidator._validate_syntax` parses the **raw** text, so it reports:

```
syntax_error
```

for a template the runtime handles correctly.

## Reproduction

```python
TemplateValidator().validate_pipeline_templates(
{"id": "p", "steps": [{"id": "s", "for_each": "{{ rows }}",
"parameters": {"t": "{{ $item }}"}}]},
{"rows": [1]},
)
# -> is_valid=False, ['syntax_error']
```

## Scope

32 uses across the catalogue — `$item` (18), `$iteration` (10), `$index` (2), `$is_first` (2) — in files including:

- `examples/control_flow_for_loop.yaml`
- `examples/iterative_fact_checker.yaml`
- `examples/control_flow_advanced.yaml`
- `examples/enhanced_until_conditions_demo.yaml`
- `examples/original_research_report_pipeline.yaml`

All of these currently **fail validation**, and this is at least one of the reasons.

## Same class as #465, #469 and #472

The compiler/runtime accepts a spelling the validator does not. Each time, the validator's private notion of the language disagreed with the runtime's:

| issue | disagreement |
|-|-|
| #465 | inferred dependencies rejected rather than used |
| #469 | bare loop names unknown to the template validator |
| #472 | one binding set for every loop construct; source validated in loop scope |
| this | `$`-prefixed spelling rejected as a syntax error |

## Fix

Validation should apply the same preprocessing the runtime applies, from a **shared** implementation rather than a second regex — a reimplementation would be the fourth mechanism problem #466 removed for dependencies.

Once `{{ $item }}` is normalised to `{{ item }}` before parsing, the `DOLLAR_LOOP_VARIABLES` raw-text scan in `_validate_variables` becomes redundant: the names appear in the AST like any other. That scan exists only because `$item` cannot be parsed.

## Tests

- `{{ $item }}` inside a `for_each` validates and renders to the item
- `{{ $item }}` outside a loop is still rejected, as `{{ item }}` is
- `$`-names in `{% if %}` / `{% for %}` blocks are handled
- the preprocessing has one implementation, asserted by identity
- a pipeline using `$item` compiles **and runs**, producing the expected artifact
- the affected catalogue examples move into the validating baseline

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.