Rewrite thirteen shorter pages in plain English
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lxo4MXbp6VPoDkUrTBNXJ1
952: a BPMN process belongs to one workflow aggregate
Workflow tasks gets a section on the rule and on how to decide what a
process is: a workflow of its own (a call activity may still call it,
the mappings of the call activity in the BPMS set up its data, messages
are usually better) or a step of one workflow. Starting workflows and
Migrating from version 1 point at it: version 1 logged a warning,
version 2 stops the start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lxo4MXbp6VPoDkUrTBNXJ1
949: a called process is not a workflow of its own
Its start and its end do not reach the application; the id a renamed
process left behind keeps both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lxo4MXbp6VPoDkUrTBNXJ1
Say that aggregateChanged inside the start of a workflow does nothing
Story 896.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RVEfP4rFpf8XUVXB9CFuL7
Blueprints 12: injected beans are named after their role
Code examples now call the ProcessService bpms and the use case
service loanApproval, the names the blueprints use from now on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RVEfP4rFpf8XUVXB9CFuL7
Say where the moment of a start can be read, and where it cannot
The page told the reader to fill a process variable by an expression and read
it as a @TaskParam. It did not say of which method. On Camunda 8 the method
which builds the aggregate runs on a listener job of the start event, and such
a job sees only the variables the instance was created with. A timer start
creates none, so the value is not there yet. The value has to be read at a task
behind the start event.
Measured while building the blueprint: the same expression writes different
text on the two engines, an ISO instant on Camunda 7 and a FEEL moment with a
zone region on Camunda 8. The page says so now.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: the application names the workflow it did not start
Starting workflows described the state before stories 504 and 653. It said VanillaBP
builds the aggregate of a workflow the BPMS started, that the process instance key or the
trigger time becomes its id, and that a workflow can arrive with a business key of
somebody else's choosing. None of that is true any more.
The page now says what the code does. A @WorkflowStartedByBpms method returns the
workflow aggregate, and that aggregate names the workflow. The BPMS holds the name
afterwards: Camunda 7 as the business key, Camunda 8 and the Process-Engine-API as the
process variable named after the id attribute. Every start is then read from the state of
the workflow: a name with an aggregate is our own start, no name is a start past
VanillaBP, and a name no aggregate carries is refused.
The trigger carries no time, and the section which recommended taking one is gone. The
method is required where the BPMS fires a start event by itself; a plain or message start
event is judged when somebody uses it, not at boot.
Timers and Migrating from version 1 said the same old thing in one sentence each and
follow along, the first one also to the renamed section.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: cancel means two different things
Separates our cancel from BPMN's. WorkflowEnd.Kind.CANCELED and cancelTask keep
their meaning and now say what they are not, and each adapter says what it does
with a transaction sub-process, which is nothing. Camunda 7 runs the construct,
measured against the pinned engine 7.24.0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: which modelled paths end a workflow as canceled is the BPMS' business
Measured for stories 357 and 360: a terminate end event and an interrupting
event subprocess are reported as completed by both Camunda engines. On
Camunda 7 the id reported with such an end is the element the instance ended
at, which is not always an end event.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: a workflow end is canceled, not terminated
Story 360. The kind reported to a `@WorkflowEnded` method is called
`CANCELED` now. The Camunda 8 column also said the kind never arrives there,
which stopped being true with story 370: from the 8.10 release line on the
cluster reports a canceled instance.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: what a business key has to carry, and what happens when it says something else
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs(start): a process runs in the present
Story 329 asked whether the aggregate changing between a delayed start and
the first gateway needs handling. Measured: no BPMS reads the live aggregate,
VanillaBP writes the shared values at every sync point from a fresh load, and
the window is milliseconds unless an entry stays behind. So there is nothing
to build, only something to say.
The start page says which state the process starts with. The aggregates page
says what follows for an attribute a gateway reads, and that the choice
belongs in the aggregate.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs(outbox): a start which never happens is blocked and visible
Observability gains vanillabp.outbox.blocked, the counter of entries a store gave up
on. It needs a row of its own because vanillabp.outbox.pending falls at that very
moment: a blocked entry stops waiting, so the gauge an operator watches moves as if
the backlog had drained.
Starting workflows now says that on a remote BPMS the start finishes after the
caller's commit, that the second half can fail with nobody in the application
listening, and where to look when it does. The retry curve stays on the platform
pages, which the section links to.
Both platform pages point the operations duty at the new counter and say which
values the error of a blocked entry names.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Re2yjHbaFRvnHyW61E3sao
docs: the page is called integration SPI
The artifact is io.vanillabp:vanillabp-integration-spi, so the wiki calls the
thing what its coordinate calls it instead of inventing a second name. Page
renamed, all links and the glossary entry follow.
The adapter SPI is gone from the wiki: it is nothing a reader of these pages
implements. Where the start instant explains its own name, the reason is now
VanillaBP's rather than an SPI the page never introduces.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjxJNwTRcKzTmXCwLU7Wi4
docs: every page opens with what to do and carries a table of contents
A reader who has never used VanillaBP met the reasoning for a rule before the rule
itself, and had no way of telling how far to read before writing a first workflow.
The pages now start with the sentence somebody can act on and keep the background
where it belongs, further down. Nothing was deleted; what explains a rule moved
behind it.
Every page gained a numbered table of contents in the shape Home and the Spring Boot
page already used, so a reader sees the sections and what each of them answers before
scrolling. Where a first heading only repeated the title GitHub shows above the page,
it is gone and the page starts with its first sentence.
Home is now ordered the way a newcomer needs it, and what VanillaBP is sized for
became a page of its own: it answers a question somebody asks before they start, not
one they trip over in the middle of the introduction. The architecture picture from
the repository's diagrams folder is embedded there, linking to its Excalidraw source.
The horizontal rules of the workflow-module pages are gone, the heading is the
separator everywhere else. Hints are written as sentences rather than marked with a
label, headings sit at one depth per page, and the paragraphs written by hand over
the last months were brought to the tone of the rest without changing a single
statement they make.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs: an adapter which can only guess is refused, and nothing waits in your transaction
Three pages still described the state before stories 157, 159 and 163.
BPMS-migration said what a guessing adapter costs in a migration and left the reader to
avoid it. VanillaBP refuses such a setup at startup now, so the page says that, and shows
'election.guessing-adapters: ACCEPTED' for whoever wants the routing anyway. The same
section still claimed the election waits inside the caller's transaction and told
operators to size their connection pool for it; the waiting moved to the dispatch, so
that advice is gone and what replaces it says where the waiting happens now.
Workflow-aggregates said a pre-commit check is a thing remote BPMS ask for; it is a thing
any adapter may ask for, and it never waits. Starting-workflows names why the SPI calls
the value a start instant rather than a trigger time.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvgyhjwTEh834mwbptZZxh
docs: why FULL is the default, what the stores differ in, and what the trigger time is
Three gaps the review found on these pages.
Workflow-aggregates stated the default and not its reason, so a reader minimising with
@NoSyncWithBPMS could not tell which side to minimise. The reasons are portability and an
upgrade from version 1 which must not touch code, and neither of them says that sharing
everything is right: what to aim for is as little as possible and as much as needed, which
means the class annotated @NoSyncWithBPMS and @SyncWithBPMS on the attributes the process
decides by plus the ones an operator has to see in Operate or Cockpit. The page also names
what ignoring it costs, payload per command on Camunda 8 and a serialization format on
Camunda 7.
The same page says when the values arrive, which differs: inside the engine transaction on
Camunda 7, with the completing command on the other two, so only there can a failure leave
the aggregate ahead of the BPMS.
The outbox guarantees were stated for every store, and "DONE, not deleted" does not hold for
the gruelbox store of a JPA application: it deletes a dispatched row to free the key, and it
counts an attempt only when one failed, so a hard crash re-dispatches without the probe which
mitigates a duplicate start. The Spring Boot page carries a table per store now, says what
follows for a JPA application, and says that a future version replaces that default with the
JDBC store Quarkus uses. The Quarkus page points there for whoever runs both.
Starting-workflows called the aggregate's id the timer's trigger time. No engine reports the
scheduled time, so what an embedded engine answers is the moment the instance was created,
which costs nothing because both are written in one transaction.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvgyhjwTEh834mwbptZZxh
docs(tasks): one workflow service class per generation of a model
`@BpmnProcess(version = ...)` is the fallback of the three method annotations, so a class
holding the handlers of one generation declares the range once. Says which range wins
where both are present, that every declaration carries its own version, and that a method
which inherits a range is restricted like any other - so a BPMS reporting no version
reaches it no more than it reaches a method naming a range itself.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Story 48: what the version attribute matches against
Workflow tasks gained a section on the versions of a process: what a version is (the
deployed definition's version as the BPMS counts it), version tags, the formats, the
overlap rule, what the feature costs and which BPMS can tell what. Starting workflows
says the same rule holds for the methods serving a BPMS-initiated start and the end of a
workflow, and the migration guide names the three flips for applications which already
carry the attribute.
docs: when a workflow ends, and that a signal is not buffered
Names what each BPMS can honestly report about the end of a workflow, and adds
the property a Camunda 8 test uncovered: a broadcast reaches whoever waits at
that moment, nobody else.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs: how workflows are started, by you and by the BPMS
New page describing both ways a workflow comes into being: your application
handing over the aggregate, and the BPMS starting a process on its own by a
timer, signal or conditional start event. The latter names the ID rules, the
optional @WorkflowStartedByBpms method and what each BPMS can serve.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>