Skip to main content
← Back to list
01Issue
BugClosedSwamp CLIPublic
AssigneesNone

Relationships

#2455 self.globalArguments.X returns the unevaluated expression text when the global argument is itself an expression

Opened by stack72 · 9/23/2026

Description

When a global argument is itself a CEL expression, referencing it from a method argument with self.globalArguments.<field> yields the global argument's unevaluated ${{ ... }} text, not its evaluated value, even when that expression is valid. The literal text is then handed to the method.

Found while planning swamp-club#2397.

Steps to Reproduce

  1. command/shell model producer with run: echo hello, run it once.
  2. command/shell model globalvalid:
    • globalArguments.target: ${{ data.latest('producer', 'log').name }}
    • method execute, argument run: echo "[${{ self.globalArguments.target }}]"
  3. swamp model method run globalvalid execute
  4. Output: /bin/sh: [${{ data.latest('producer', 'log').name }}]: bad substitution, then Command exited with code 1. Expected: [log].

Cause (suspected)

ExpressionEvaluationService.evaluateDefinition (src/domain/expressions/expression_evaluation_service.ts) sets ctx.self.globalArguments from the original, unevaluated definition.globalArguments and evaluates every expression in the definition in a single pass. So self.globalArguments.X resolves to the raw expression string. The workflow path (src/domain/workflows/execution_service.ts, where ctx.expressionContext.self is built from originalDefinition.globalArguments before DefinitionExpressionEvaluator.evaluate) has the same shape. Literal global arguments work; only expression-valued ones are affected.

Expected Behavior

self.globalArguments.X resolves to the evaluated value of the global argument, as the swamp skill's expression reference documents (.claude/skills/swamp/references/model/references/expressions.md, examples.md).

Environment

  • swamp 20260923.203315.0-sha.4ae1cfd9
  • macOS
02Bog Flow
✓OPEN○TRIAGED○IN PROGRESS◉CLOSED

Closed

9/23/2026, 10:59:06 PM

No activity in this phase yet.

03Sludge Pulse
Editable. Press Enter to edit.

stack72 commented 9/23/2026, 10:59:06 PM

Fixed in https://github.com/swamp-club/swamp/pull/2598 (merged), shipped together with swamp-club#2397.

Cause: definition evaluation built self.globalArguments from the original, unevaluated global arguments and evaluated the whole definition in a single pass. So ${{ self.globalArguments.X }} in a method argument returned X's raw ${{ ... }} source whenever X was itself an expression.

Fix: the CLI and workflow paths now share one definition pass (evaluateDefinitionExpressions) that evaluates global arguments first, then evaluates everything else with self.globalArguments bound to the result.

  • A valid expression-valued global argument now resolves. The repro's globalvalid model prints [log].
  • A runtime (vault/env) global argument is still copied as its raw text and resolved by the runtime pass, so secret handling is unchanged.
  • A global argument that fails to evaluate is copied raw and caught by the new #2397 check, so the method fails with the CEL error instead of receiving literal text.

Not covered: a global argument that references another global argument still sees the raw values (no dependency ordering between global arguments).

Tests: unit tests on both evaluators, plus a workflow-step test through the real step executor.

Sign in to post a ripple.