Skip to content

feat: Emit effects for assignments to program rule variables backed by a field [DHIS2-21730]#186

Draft
enricocolasante wants to merge 2 commits into
masterfrom
DHIS2-21730
Draft

feat: Emit effects for assignments to program rule variables backed by a field [DHIS2-21730]#186
enricocolasante wants to merge 2 commits into
masterfrom
DHIS2-21730

Conversation

@enricocolasante

@enricocolasante enricocolasante commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Emit effects for assignments to program rule variables backed by a field DHIS2-21730

Why

ASSIGN actions targeting a program rule variable (via content) were handled entirely inside the engine: the variable was updated in the value map and no RuleEffect was emitted. When the variable was backed by a data element or tracked entity attribute, the assigned value was invisible to consumers and never applied to the underlying field.

In addition, the two ASSIGN modes (assign to field vs. assign to variable) were dispatched implicitly on whether field was empty, so a misconfigured action — neither field nor content, or a malformed variable reference — failed mid-evaluation with raised an unexpected exception: null.

What

Variable assignments now emit effects for their backing field

  • Assigning to a program rule variable still updates the value map (rule chaining is unchanged), but now also emits a RuleEffect when the variable is backed by a data element or tracked entity attribute. The backing field and attributeType are injected into a copy of the action, so the effect is self-contained and consumers can apply it exactly like a direct field assignment (e.g. dhis2-core reads ruleAction.field() when building ValidationEffect). The original content is preserved on the action.
  • Emission is matched to the evaluation context — data-element-backed variables emit during event evaluation, attribute-backed variables during enrollment evaluation — mirroring how direct field assigns are routed via attributeType, and ensuring evaluateAll emits each assignment exactly once instead of once per pass.
  • Calculated-value variables are unchanged (silent value-map update only): their field is the variable's own uid, not an assignable data element or attribute.

Explicit ASSIGN target dispatch

  • New sealed type AssignTarget (Variable(name) / Field(field)) and RuleAction.assignTarget(), which resolves the target of an ASSIGN action and throws a descriptive IllegalArgumentException for malformed actions.
  • Content accepts both #{variableName} and A{variableName} notations.
  • New constants RuleAction.ASSIGN and RuleAction.ERROR replace magic strings; configuration errors are reported as raised an error with an actionable message instead of raised an unexpected exception: null.

Compatibility

  • Behavior change for consumers: clients now receive ASSIGN effects for assignments to variables backed by a data element or attribute, which were previously silent. Consumers that apply ASSIGN effects (tracker importer, Android SDK, web apps) will start applying these values.

enricocolasante and others added 2 commits July 13, 2026 16:46
…y a field [DHIS2-21730]

ASSIGN actions targeting a program rule variable now emit a RuleEffect
when the variable is backed by a data element or tracked entity
attribute, with the backing field and attributeType injected into the
effect action so consumers can apply it like a direct field assignment.
Emission is matched to the evaluation context (data elements in the
event pass, attributes in the enrollment pass) so evaluateAll emits
each assignment exactly once. Calculated values keep their silent
value-map-only behavior, and rule chaining is unchanged.

The two ASSIGN modes are now dispatched through the new sealed
AssignTarget type (RuleAction.assignTarget()), which accepts both
#{variableName} and A{variableName} content notations and reports
malformed actions with actionable error messages instead of
"unexpected exception: null".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@enricocolasante enricocolasante marked this pull request as draft July 13, 2026 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant