Skip to main content
← Back to list
01Issue
BugShippedSwamp CLIPublic
Assigneesstack72

Relationships

↔ sibling #3178

#3179 Lazy hydration: expressions reading another model's data get empty attributes; hydrate a step's read set before evaluation

Opened by zack · 10/8/2026· Shipped 10/8/2026

Summary

Under hydrationStrategy: lazy, a workflow expression that reads another model's data gets empty attributes when that model's content is not in the local cache. design/enablers/datastores.md records this as the getContentSync limitation. It blocks swamp-club#2435: making swamp serve hydrate lazily would expose every serve-run workflow to it.

Where

  • model.<name>.resource.<spec>.<name>.attributes is loaded by a synchronous getter during CEL evaluation: findAllForModelSync → populateFromItems → dataToRecord → getContentSync in src/domain/expressions/model_resolver.ts. A synchronous read cannot download, so attributes is {}.
  • data.latest() builds its record with the same dataToRecord before materializePath() downloads the file, and the attributes are not re-read afterwards.
  • The only pull before a step runs covers the step's own model: createStepLockHook in src/serve/deps.ts, and acquireModelLocks for the CLI.

Example

A step evaluates an expression reading model.vpc.resource.state.main.attributes.vpcId. The vpc data was written by another host, so only its metadata is local. The expression fails with a missing key, or silently takes a default branch.

Proposed change

Ensure a step's read set is local before its expressions are evaluated: widen the scoped pull from the step's own model to that model plus the models its expressions reference. analyzeExpression already computes those targets for authorization. Synchronous readers then stay synchronous and correct.

Open points:

  • Expressions analyzeExpression reports as wide (for example data.query() over everything) need a defined fallback: pull in full, or keep the documented null-content behaviour.
  • Whether analyzeExpression covers every reference form has not been checked.
  • data.latest() can also re-read attributes after materialising the path, as a smaller independent fix.
02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 2 MOREISSUE_LINKED+ 14 MOREREVIEW+ 13 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

10/8/2026, 8:30:21 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack7210/8/2026, 6:46:21 PM
stack72 linked sibling of #317810/8/2026, 6:47:10 PM

Sign in to post a ripple.