Repository navigation
intent: one setter step writes several members of one record in one statement - set: { slotKey: null, Status: DONE } (#8042) - #8055
Merged
Conversation
…tatement - set: { slotKey: null, Status: DONE } (#8042)
A process setter wrote one member per step, and every generated step is
flowable:async - its own job and transaction - so a change that is one fact
(a job releasing its slot as it completes) passed through a half-written
state another job could observe, published one -transitioned per column,
and stayed half done when an instance stopped between the two steps.
A step may now declare a set: map (serviceTask, or relations-only on a
userTask). Each key is what a single-member setter accepts - a field or a
to-one relation, of the trigger record or one hop away - and its value
follows that setter's rule and message: a literal, "{error}" or null (the
clearField erasure) on a string/text field, "{now}" on a timestamp/date
field, a seed name or id on a to-one relation. All keys must address one
record, and set: is exclusive with every other step action.
- SetFieldSupport.Setter carries an ordered List<Assignment>; status-write
readers ask relationValue(), raw-args readers use relationWrites(), and
isSetterStep() is the single "is this a setter step" test.
- The generated delegate builds one LinkedHashMap and calls
updateProperties once, so lifecycle, stampOn and label judge the whole
change and one event is published. GlueGenerator renders each member's
Java value; a one-key map projects the single-member descriptor, so it
renders the existing delegate, and models without set: are unchanged.
- StatusSymbolResolver resolves a seed name on each relation key.
- IntentParser.restoreSetMaps puts each step's raw set: map back after the
Gson round trip, which drops null map values - the erasure.
Verified: engine-intent (1779) and ide-template (309) unit suites green,
existing setter tests unchanged; IntentSetManyIT, IntentOneHopSetterIT,
IntentClearFieldIT, IntentSetFieldNowIT, IntentEngineIT green;
formatter:validate with the cache wiped; release-profile javadoc build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
iliyan-velichkov
force-pushed
the
issue-8042-set-many
branch
from
October 22, 2026 12:34
61195bf to
8daa3fc
Compare
…, not key/value varargs (#8042) CodeQL (java/index-out-of-bounds) flagged the test helper's pairwise flags[i + 1] read: an odd number of varargs would overrun the array. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
iliyan-velichkov
added a commit
that referenced
this pull request
Oct 22, 2026
… start event's id (#8058) (#8060) BpmnIntentGenerator gave every start event the fixed id `start`, and every step becomes an element whose id is its name. A step named `start` therefore produced two elements with one id: Generate succeeded, and publish failed with `cvc-id.2: There are multiple occurrences of ID value 'start'`, leaving the .bpmn FAILED and the process never started. The start event's id is now chosen per process: `start` unless an element of the process already carries it, then `startEvent` (numbered if that is taken too). The chain, the start event, its outgoing flow and the diagram layout all use the chosen id - nodeSize no longer draws a step named `start` as the event's circle. Only a colliding process changes; every other generated .bpmn stays byte-identical, and authors get no new naming rule. Verified: StartEventIdBpmnTest (fails on master with duplicate id [start], passes here), the engine-intent unit suite (1796 tests), and IntentEngineIT, IntentEmissionCoverageIT and IntentSetManyIT - whose trigger step is named `start` again (it had been renamed to `begin` to dodge this, #8055) and now deploys and runs. formatter:validate green with the cache wiped. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cause
A process setter (
setField/setRelationField/clearField) writes one member per step, and every generated step isflowable:async: its own job, its own transaction. A change that is one fact therefore passed through visible half-written states. For example, a job released its slot while still readingRUNNING. Each column also published its own-transitionedevent, and an instance that stopped between two steps kept the half-written state.Change
A step may declare a
set:map:"{error}"ornull(theclearFielderasure) on astring/textfield;"{now}"on atimestamp/datefield;StatusSymbolResolver.setField/clearField/setRelationField/value/delegate/call/javaHandler/notify. An empty map is refused.serviceTask, and on auserTaskfor relation keys only (the same rulesetRelationFieldfollows there).LinkedHashMapin the authored order and callsupdatePropertiesonce, so the lifecycle edge, thestampOnstamps and the label judge the whole change, and one-transitionedis published.Implementation notes:
SetFieldSupport.Setternow carries an orderedList<Assignment>.Setter.relationValue(...):CheckSupport,NumberingSupport,EdmIntentGenerator.writesStatus,BpmnIntentGenerator.gatesACheck.SetFieldSupport.relationWrites(...): lifecycle reachability,StatusStepsSupport.isSetterStep(...)replaces the three-arg checks in the BPMN generator,ServiceTaskHandlerGeneratorand the abortOnthen:validation.GlueGenerator.setterAssignmentsrenders each member's Java value.SetField.java.templategains an#if($assignments)branch; the single-member branches are untouched.set:projects exactly the single-member descriptor (same delegate), and models withoutset:produce unchanged descriptors and sources. No existing test was modified.IntentParser's Gson round trip of the YAML tree dropsnullmap values, which would silently delete every erasure.restoreSetMapsputs each step's rawset:map back after the typed mapping.set:whenever several members change as one fact;intent-dsl-features.mdand the engine-intentCLAUDE.mddescribe the construct.Verification
SetManyIntentTest(14) and 4 newGlueSettersTestcases;GlueGeneratorTestcase for the rendered values.IntentSetManyIT(generate → publish → compile → run):set: { job.slotKey: null, job.Status: DONE }releases the slot, moves the status and stampsfinishedAtin one write;IntentOneHopSetterIT,IntentClearFieldIT,IntentSetFieldNowIT,IntentEngineIT(83 tests).mvn -T 1C formatter:validatewith the formatter cache wiped; release-profile javadoc build on engine-intent and ide-template.Found on the way (not fixed here)
A process step named
start, of any kind, collides with the BPMN start event's idstart, and Flowable refuses the deployment ("multiple occurrences of ID value 'start'"). This predates the change, and the issue's own example uses that name. The IT and the guide's example name the stepbegininstead. It deserves its own issue: the parser could reserve the name, or the generator could prefix the start event's id.Fixes #8042
🤖 Generated with Claude Code