Skip to content

Conversation

@dmytro-gundartsev
Copy link

@dmytro-gundartsev dmytro-gundartsev commented Dec 2, 2025

The DMN 1.6 standard and Camunda 8 implementation handles single-output result in an unanimous way (no-named value). So the contract with Map<String, Any> for the EvaluationResultOutput is noncompliant. Proposing fix for it.

@dmytro-gundartsev
Copy link
Author

dmytro-gundartsev commented Dec 3, 2025

@zambrovski can you please check the fix? I want to have that discrepancy against DMN 1.6 settled, before creating PR for C8 implementation. Thank you in advance

@zambrovski
Copy link
Contributor

Will do ASAP...

@dmytro-gundartsev dmytro-gundartsev force-pushed the fix/evaluate_decision branch 2 times, most recently from c0c33f5 to 1d45049 Compare December 3, 2025 14:59
@dmytro-gundartsev
Copy link
Author

@zambrovski please also check the last commit in this PR.

After long reflection on the DMN 1.6 specification and analysis of Camunda 8 decision evaluation results there was a pittiy discovery: there is no way how we can guarantee derivation of the decision evaluation result returned by the engine from both perspective:

  • from number of returned values (single - for single-rule hit policies + aggregations, multiple - for collect, order order, output order).
  • from number of outputs in each value (anonymous single output or multiple outputs).
    The example of it 'null' output, which can be interpreted as anything.
    At this point the proposal is to let the caller to decide how to interpret the decision evaluation result, as expected that it will know the exact contract of the evaluated decision (list of inputs needed, collection or single value expected and the number or outputs and their names).
    Theoretically we might be able to derive it if the engine(s) returned in the response to decision: number or rules tested positive (C8 does it), hit policy (C8 doesn't), structure of the output (single or multiple) (C8 does it partially, not for nulls);

@zambrovski
Copy link
Contributor

Ok... This is then a sign for us that it is generally a good idea to let the user receive the evaluation result as a multi-value or a single value result...

I'll create a PR for this - let's discuss on that further...

To make life easier, I would add you to this repository / org, so you can commit directly..

@zambrovski zambrovski added the Prio: MUST Feature is essential for the milestone. label Dec 4, 2025
@zambrovski zambrovski changed the title fix: Introduced unanimous single valued output in decision evaluation… Redesign decision evaluation result Dec 4, 2025
@zambrovski
Copy link
Contributor

My proposal is still to keep the Map<String, Any> there as a generic form... If we don't have the output name, we might put a column index there... Like 0 -> value1, 1 -> value2...

@zambrovski
Copy link
Contributor

My proposal is - if you comply with my changes to your PR, let adopt them and merge in. Then you implement C8 and I implement C7 in a meantime based on the snapshot... If everything works we will release API 1.5 and corresponding adapter versions.

@zambrovski zambrovski added this to the 1.next milestone Dec 4, 2025
@dmytro-gundartsev
Copy link
Author

dmytro-gundartsev commented Dec 4, 2025

My proposal is still to keep the Map<String, Any> there as a generic form... If we don't have the output name, we might put a column index there... Like 0 -> value1, 1 -> value2...

I would disagree. Let's imagine I'm a developer and have a decision table I designed in Camunda 8. In the decision table I have named the single output as 'offer'. Then when calling the api of the adapter I would expect that when I use result.asSingle?.asMap["offer"] to return me correct output value instead of index - 0.
The point of separation into withSingleOutput and withMultipleOutputs was not to let the developer to misread those methods and make such mistake

@zambrovski
Copy link
Contributor

In my propose you get the result, and on it you call single / list to get one or list of output...

On those there might be be asType() or asMap... the methods might fail

@zambrovski
Copy link
Contributor

zambrovski commented Dec 4, 2025

Let us focus on the example use case and experiment there ...

In theory the asType() might be used for either a single value conversion with asType(Double.class) or as a complex multivalue to type conversion with asType(Offer.class) and the implementation might use Jackson or so to deserialize

@dmytro-gundartsev
Copy link
Author

Let us focus on the example use case and experiment there ...

In theory the asType() might be used for either a single value conversion with asType(Double.class) or as a complex multivalue to type conversion with asType(Offer.class) and the implementation might use Jackson or so to deserialize

I agree. So the proposal is to stick to your proposal (with the last commit I just slightly adjusted asType(type: Class).
Small remark on asMap() method: "If names are not available, use digits as fallbacks.". The names are part of 'output components' for compound output, so there will be no situation of having compound output without names (e.g. "[1,2]" instead {"price":1, "position": 2}.Only single value output (e.g. "1") won't contain the name (e.g. evaluation of the decision table with a single output entry with name "price", will never return "{"price": 1}", but "1" instead)

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

Labels

Prio: MUST Feature is essential for the milestone.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants