Skip to content

Fixing invisible workflow statuses throughout - #6848

Merged
delchev merged 14 commits into
eclipse-dirigible:masterfrom
TIVMOF:fix/invisible-workflow-statuses
Aug 19, 2026
Merged

Fixing invisible workflow statuses throughout#6848
delchev merged 14 commits into
eclipse-dirigible:masterfrom
TIVMOF:fix/invisible-workflow-statuses

Conversation

@TIVMOF

@TIVMOF TIVMOF commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

This PR:

onTransition: the -updated half of the DSL was deaf to every status the system writes

-transitioned and -updated are fully disjoint channels. The three publishers of the former —
SetField.java.template:61, Transition.java.template:76, Generate.java.template:176 — never
publish the latter, deliberately, so a system write cannot re-fire the onUpdate reactions meant for a
person's edit.

But onTransition existed only in PostingIntent#event and GeneratesIntent#event. Everything else
was locked to the lifecycle vocabulary, so:

  • You could not declaratively send an email when a workflow set a status. A notification bound to
    onUpdate listened on the other channel and never fired — with nothing anywhere to say so.
  • A wait could be aborted by a transition but never resumed by one. abortOn: binds
    -transitioned (Abort.java.template:34) while ProcessWaitSupport.EVENT_KINDS was
    {onCreate, onUpdate}, so the instance parked forever, silently.

The reported cases, both verified against the source:

# never fires - the status is set by a setRelationField step, which publishes -transitioned
notifications:
  - { event: { onUpdate: Fine }, to: driver.email, subject: "Fine {number} attributed" }

# never resumes - same reason; the instance parks forever
- { name: awaitIdentification, kind: wait, args: { onUpdate: Fine, when: "Status == 2", next: declare } }

The fix

onTransition is now in the event vocabulary of notifications:, integrations:, outbound:,
a process trigger: and a wait step.

No template changed at all. Every handler already interpolates ${topicSuffix} into its
destination(), and the topic already existed and already carried the full entity payload — so this
is a vocabulary change, not a new mechanism.

outbound: is included beyond the issue's list: it shares validateEventBinding and
GLUE_EVENT_KEYS with the other two, so excluding it would have cost extra code to withhold a
capability that arrives for free.

The when: guard stays optional on all five ("on any status change" is a legitimate ask), unlike
postings: and generates, which mandate one because they create a document per transition. That
difference is now stated in both guides rather than left to be inferred.

The fifth enumeration — the one that would have shipped broken

The issue named four places to widen. There are five. StatusSymbolResolver.triggerEntityOf keeps
its own list because it runs on the raw YAML tree before the typed mapping and therefore cannot
read EventBinding. My own test caught it: trigger: { onTransition: Fine } was refused with

step [attribute] setRelationField [Status] value names the status [IDENTIFIED] but no
`function: EntityStatus` relation resolves the nomenclature to look it up in

— a message about the status nomenclature, pointing nowhere near the trigger. Any process using
symbolic status names would have broken the moment its trigger moved to onTransition.

All five now agree, and each carries a comment saying so:

Site Role
EventBinding.KINDS + topicSuffix the generator choke point every glue builder funnels through
IntentParser.EVENT_KINDS notifications / integrations / outbound / trigger
ProcessWaitSupport.EVENT_KINDS the wait — validateWaitSteps now reads this list instead of its own copy, so validation and emission cannot drift
UnknownKeyValidator.GLUE_EVENT_KEYS + ProcessIntent#trigger the unknown-key vocabularies
StatusSymbolResolver.triggerEntityOf raw-tree symbol resolution, before typed mapping

Adding the kind to EventBinding does not widen resolves: — its own vocabulary is still
onCreate/onUpdate and is checked first.

Verification

  • GlueTransitionAxisTest (new) — notification, integration, departure and trigger each resolve
    -transitioned, driven through the real parser and glue generator.
  • GlueWaitsTest.aWaitCanParkOnATransition — the wait half.
  • NotificationSupportTesttopicSuffix("onTransition").
  • Red-first verified: 1 failure + 1 error with the main sources stashed.
  • engine-intent 696/696, formatter:validate clean.
  • OutboundIntentTest asserted the old message verbatim; updated to the widened text.

Reviewer note

onTransition on an entity nothing ever transitions is still a silent no-op — the same as binding
onUpdate to an entity nobody updates. A publisher-existence check is computable (a setter step, a
transitions: entry, or a generates sourceStatus: on that entity) but would risk false
rejections on cross-model sources and hand-written delegates, so it is deliberately out of scope.
Happy to add it as a generate-time warning if that's wanted.

@delchev

delchev commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Merged current master into the branch to clear the conflict (pushed to TIVMOF:fix/invisible-workflow-statuses — the PR is mergeable again).

Only one file actually conflicted: components/engine/engine-intent/CLAUDE.md, the single-line "Status of the catalog" paragraph. Master had rewritten its inbound ingest entry (the accept: gate and map:/lookup: projection, #6769/ArrivalSupport) while this branch had added onTransition to the lifecycle triggers entry. Both edits are kept; nothing else in the paragraph changed. Everything else auto-merged.

Verified on the merged tree before pushing: engine-intent unit suite green (746 tests, your GlueTransitionAxisTest / GlueWaitsTest additions included) and formatter:validate clean on engine-intent + tests-integrations. CI is re-running the rest.

@delchev
delchev merged commit 6cd968e into eclipse-dirigible:master Aug 19, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants