Skip to content

Return the output node message as a named output entry - #64

Open
pedroigorjs wants to merge 2 commits into
mainfrom
f/normalize-message-as-output-entry
Open

Return the output node message as a named output entry#64
pedroigorjs wants to merge 2 commits into
mainfrom
f/normalize-message-as-output-entry

Conversation

@pedroigorjs

Copy link
Copy Markdown
Contributor

What

The message field of Output and MultipleOutputs nodes now shows up as a regular entry in the normalized outputs list, using message as its name.

Before:

"outputs": [
  { "name": "output", "value": "1", "message": "first" }
]

After:

"outputs": [
  { "name": "output", "value": "1", "message": "first" },
  { "name": "message", "value": "first", "message": "first" }
]

Why

Consumers of Execution.to_normalized_dict() read the outputs list as a flat collection of named values. The message was only reachable as an extra key inside each value entry, so anyone treating the list uniformly never saw it. Exposing it as its own named entry makes the message available through the same access pattern as every other output.

How

The change lives in normalize_execution_for_debug_iter in retrack/utils/transformers.py. For each terminal node we now count how many entries it contributed and append a single message entry right after them.

Rules applied:

  1. A null message produces no entry at all.
  2. A terminal node that produced no value, meaning it was not the path taken for that record, produces neither a value nor a message. This keeps the message scoped to the branch that actually ran, which matters for graphs with several Output nodes.
  3. MultipleOutputs emits one message entry after all of its keys instead of repeating the message on every key.

Backwards compatibility

The inline message key stays on the value entries, so existing readers keep working. The new entry also carries a message key with the same content, which means every dict in outputs still has the same shape and code that reads entry["message"] across the whole list will not raise a KeyError.

Released as 3.8.0a0 so the new shape can be validated by a consumer before the final minor.

Testing

Five expectations in tests/test_transformers/test_normalize_debug.py were updated and two cases were added, one covering a filled message on a node without a value and one covering a graph where only the executed Output emits its message. The tests/resources/executions/multiple-ifs.json fixture was regenerated. Full suite passes with 139 tests.

The message of Output and MultipleOutputs nodes is now appended to the
normalized outputs list as an entry named message, so consumers reading
the list uniformly can reach it.

A null message emits nothing, and a terminal node that produced no value
emits neither value nor message, which keeps the message scoped to the
branch that actually ran. MultipleOutputs emits one message entry after
all of its keys instead of repeating it on every key.

The inline message key stays on the value entries and the new entry
carries it too, so every dict in outputs keeps the same shape.
@pedroigorjs pedroigorjs self-assigned this Aug 21, 2026
@pedroigorjs pedroigorjs added the enhancement New feature or request label Aug 21, 2026
@github-actions

Copy link
Copy Markdown

coverage

Coverage Report
FileStmtsMissCoverMissing
retrack/engine
   base.py70593%48, 62–64, 152
   executor.py1311092%62, 74–75, 153, 225, 271, 289, 293, 305, 313
   request_manager.py80791%16, 35, 54, 69–70, 149, 152
   rule.py50394%87, 109, 116
retrack/nodes
   check.py41393%23, 26, 89
   constants.py93397%123, 126, 171
   math.py43198%75
retrack/nodes/dynamic
   base.py16194%26
   csv_table.py44295%60, 63
   flow.py44198%18
   flow_connector.py251252%24–48
retrack/utils
   component_registry.py1051883%77–78, 81–82, 85–86, 91–92, 101, 112–123
   exceptions.py28582%17–18, 106–127
   graph.py60788%35, 46, 59, 61, 63, 84, 86
   registry.py34682%23–26, 38, 43, 51
   transformers.py1681690%20, 40–41, 55, 60–61, 66, 69, 72, 75, 78, 112, 172, 181, 230, 386
retrack/validators
   base.py4175%14
   node_exists.py15287%36, 38
   node_validator.py33391%31, 56–57
TOTAL169410694% 

Tests Skipped Failures Errors Time
139 0 💤 0 ❌ 0 🔥 4.858s ⏱️

@github-actions

Copy link
Copy Markdown

coverage

Coverage Report
FileStmtsMissCoverMissing
retrack/engine
   base.py70593%48, 62–64, 152
   executor.py1311092%62, 74–75, 153, 225, 271, 289, 293, 305, 313
   request_manager.py80791%16, 35, 54, 69–70, 149, 152
   rule.py50394%87, 109, 116
retrack/nodes
   check.py41393%23, 26, 89
   constants.py93397%123, 126, 171
   math.py43198%75
retrack/nodes/dynamic
   base.py16194%26
   csv_table.py44295%60, 63
   flow.py44198%18
   flow_connector.py251252%24–48
retrack/utils
   component_registry.py1051883%77–78, 81–82, 85–86, 91–92, 101, 112–123
   exceptions.py28389%106–127
   graph.py60788%35, 46, 59, 61, 63, 84, 86
   registry.py34682%23–26, 38, 43, 51
   transformers.py1681690%20, 40–41, 55, 60–61, 66, 69, 72, 75, 78, 112, 172, 181, 230, 386
retrack/validators
   base.py4175%14
   node_exists.py15287%36, 38
   node_validator.py33391%31, 56–57
TOTAL169410494% 

Tests Skipped Failures Errors Time
139 0 💤 0 ❌ 0 🔥 3.829s ⏱️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant