968: an aggregate ID over 1024 bytes on Oracle and DB2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lxo4MXbp6VPoDkUrTBNXJ1
Rewrite Home, the platform pages, BPMS migration and Workflow modules in plain English Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lxo4MXbp6VPoDkUrTBNXJ1
Say where a blocked outbox entry keeps its reason Blocked-outbox-entries: the query reads LAST_FAILURE, what the field holds, that every attempt writes it, that opening again leaves it, and that the gruelbox store keeps none. Both platform pages get a short paragraph that links there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RVEfP4rFpf8XUVXB9CFuL7
VanillaBP owns four tables, and decision 16 says so (446) The housekeeping table came with the night window, so Home and the migration page count four now. Observability drops the number. The two links to decision 16 follow its new heading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RVEfP4rFpf8XUVXB9CFuL7
A page for blocked outbox entries How to find a blocked entry, open it again or delete it, on the table and on the MongoDB collection, and what to check about a younger entry of the same key first. The ERROR of every dispatcher links here. The statements move from the two platform pages to this one, and the gruelbox store is linked to its own README section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RVEfP4rFpf8XUVXB9CFuL7
898: waiting for a read model uses no attempts An entry whose BPMS does not report its workflow yet uses none of block-after-attempts any more. It is blocked once vanillabp.outbox.wait-for-visibility-at-most passed since it was written, about four hours by default. The outbox sections of both platform pages, the migration page and the metrics table say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NGP1Z1mjfXKxCgHzecPvuX
882: version 1 had no outbox, so the paragraph about its table goes "Migrating from version 1" told a reader that version 1 already kept its phase-two calls in the gruelbox table TXNO_OUTBOX. It never did: Stephan confirmed on 2026-10-02 that version 1 had no outbox at all and completed the Camunda 8 job from a listener which ran after the commit. The paragraph goes, and the outbox section says what version 1 did instead and that there is nothing to drain. "Spring Boot integration" keeps the description of the store which used to be here, because the bridge in the platform is real. What changes is the audience it names: an application which ran a 2.0 snapshot, not a version-1 one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017T37nXyH8Gc8d3bcyitce2
The key belongs to the artifact which reads it The coordinate is the plain 'io.vanillabp:gruelbox-phase-two-outbox', and the one reference to that store says what the key does: with the artifact, 'false' hands the entries back to VanillaBP's own store, and without the artifact the line reads as nothing at all. VanillaBP does not comment on a key it does not own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
The gruelbox store is named once, and it is named where it lives The store left adapter-platform-integration, so its documentation goes with it. What stays on the Spring Boot page is one section: what gruelbox was, where the artifact is now, and that an application which keeps it changes no configuration. The rows and paragraphs which described how that store differs from the ones VanillaBP writes itself are documented in its own repository. The migration page says the same thing from the version-1 side: entries move to VanillaBP's own table, and what is left in TXNO_OUTBOX is counted at every start. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: an application on UTC is warned about the housekeeping window, not refused Both platform pages said that VanillaBP refuses to start such an application. It starts, and it reads one warning while it does - UTC is the normal case for a container, and a refused start would cost a deployment while a window in the wrong zone costs a sweep at an unexpected hour. The paragraph and the comment in the configuration example follow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: the outbox house-keeps in a window at night, and one node does it Both platform pages get a section of their own about it: when the window is, how VanillaBP works out how much fits into it, that only one node house-keeps a store per night, and that a JVM standing on UTC has to name a time zone or it does not start. The three new meters are in the metrics table and in a section which says how to read them together, because the remainder alone says nothing. The page about running more than one node names the housekeeping as the one piece of work a single node does. The paragraph about the cost of a blocked entry is rewritten. The question which payloads are still needed is one statement in the database now, and on a relational outbox it is a lookup over a column rather than a scan of the table - only gruelbox keeps the scan, because it owns its table. The numbers are the ones measured on 2026-09-25. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: an adapter's retry window is written as it was named, on every store The outbox sections said that a window shorter than the store's own distance wins. Both platforms now say the whole promise: the window replaces the store's distance either way, so an adapter naming thirty seconds gets thirty seconds whichever store the application chose, plus the poll it takes to pick a due entry up. Decision 93 of adapter-platform-integration. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: how an environment variable spells a dash, per platform The blueprints carried this as a note about one Camunda 8 address. It belongs to the platforms and to every key with a dash, so both integration pages now say what their platform reads. Measured, not guessed: Spring Boot 3.2 to 3.5 read VANILLABP_ADAPTERS_CAMUNDA8_RESTADDRESS and VANILLABP_ADAPTERS_CAMUNDA8_REST_ADDRESS alike, but the second form dies where an id has to be read below a dashed section, so VANILLABP_WORKFLOW_MODULES_LOAN_RESOURCES_LOCATION arrives nowhere. SmallRye Config 3.18.3 reads the underscore form and nothing else. Story 590. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: the example block names the table as well as the collection The outbox block showed mongo.delivery-collection and left jdbc.delivery-table out, so the name of the relational store stood only in the prose below it. Both keys are in the block now, the table commented out like the other JDBC names it shares its default with. Story 600. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: the lease is pushed along from the claim, not from the dispatch Both platform pages said the running dispatch pushes the moment along. It has started at the claim for a while, which is what makes an entry waiting for the thread of its aggregate safe: nobody else takes it while it queues. The page about running more than one node carried the same sentence and is pulled along. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: two stores must not carry one name The pages describe the keys which name the outbox table, the payload table and the table of delivered tasks, and they never said that two of them must not name the same place. The startup has refused it for a while, so the rule now stands where somebody reads the keys, together with the way the names are compared: tables in capitals, collections as they were written. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: the adapter order stands on the ladder of levels too vanillabp.prioritized-adapters knows the application, a workflow module and a workflow, and no task below them. The section which explains the levels never mentioned it, while four pages explained it themselves. The levels section now carries it, including the two ways it differs from every other setting: a list replaces the list above it, and a level which names nothing keeps out. The platform pages, the migration page and the version-1 page point there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Fox39crp8dfWkZ9W84Ub
docs: what create-schema false means on MongoDB, and the third table's name Story 449 and 453 of the platform: the section about Liquibase and Flyway spoke of tables only, so an application on MongoDB read a promise which did not exist there. It now says that the same switch is about indexes, with the statements to paste, and it names the runtime key of the delivery table next to the changelog property, plus what the generated Flyway files cannot follow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: the MongoDB store dispatches on lanes too The pages still said that the MongoDB store keeps one dispatching thread and does not read `vanillabp.outbox.dispatch-threads`. It reads it since the store got the lanes, so both stores VanillaBP writes itself answer to that setting, and their dispatch threads stand next to their poller in a thread dump. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: what a blocked entry costs the housekeeping Before a payload is removed by age the entries are asked whether one of them still names it. On MongoDB that question now runs over an index; on a relational database it reads the outbox table, because the reference lies inside a column of text. Both pages say so, with the numbers, next to the paragraph about the payload a blocked entry keeps. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: the outbox table carries a third index The gauge which reports how long the oldest entry has been waiting is answered from an index now, so the paragraph about the indexes of the changelog says three where it said two, with the numbers behind it. The comment at 'create-schema' said "the outbox table" and left open whether the table holding the payloads goes the same way. It does, both when VanillaBP creates the schema and when it checks it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: the payload store is named after its outbox Both platform pages now say which store holds the payloads and how its name is built: the outbox name plus _PAYLOAD for a table and -payloads for a collection. The two keys are in the configuration samples as well, and the Liquibase section warns that a renamed outbox needs the payload table renamed too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: one property names one outbox table vanillabp.outbox.jdbc.table names VanillaBP's own table and no longer renames gruelbox' TXNO_OUTBOX. The page said the opposite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: a dispatch holds its outbox entry until it is done A poll used to claim an entry for one attempt-frequency and count an attempt while doing so. A dispatch which took longer lost its entry to the next poll, so the operation was carried out twice, and a slow BPMS spent the attempt budget which block-after-attempts reads. The claim now names the node which took it and how long the claim lasts, and a running dispatch pushes that moment along. The attempts count what ended. Both platform pages say what block-after-attempts counts, what gruelbox does instead, and that reopening a blocked entry clears the claim as well. The page about running more than one node says what happens to an entry whose node disappeared in the middle of dispatching it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: the delivery log's collection has a name you can set The outbox collection and the payload collection carry a name of their own, the log of processed task deliveries did not. Now it does: `vanillabp.outbox.mongo.delivery-collection`, in the same section, because the store settings of that log are the outbox' ones. Both platform pages show the key in their outbox block and say it next to the collection, and `Workflow-tasks` points at it where it names the collection. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: say what the retention deletes and what stays with a blocked entry The pages tell an operator to watch vanillabp.outbox.blocked, repair the cause and open the entry again, and they said nothing about the bytes that entry carries. The MongoDB point even said that the housekeeping deletes the payload of an entry which stayed blocked. Both pages now say it where it is needed: the retention counts at the entry, a dispatched entry goes with its payload, an entry which waits or is blocked keeps its own, and only a payload no entry names any more is deleted by age. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: the payload table carries the outbox name as its prefix Story 413 renamed it to VANILLABP_PHASE_TWO_OUTBOX_PAYLOAD, and the pages written today took the older name from a clone which had not been updated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: MongoDB keeps a payload collection as well Both platform pages named one MongoDB collection for the outbox while the application writes two: the payload of a call which carries one lives in `vanillabp-phase-two-payloads`, next to `vanillabp-phase-two-outbox`. The MongoDB bullet now names it, says that VanillaBP owns both and that the housekeeping deletes the payloads nobody reads again. The configuration block shows the property which renames the payload store, for MongoDB and for JDBC, which never showed it either. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: Spring Boot writes its outbox itself On a relational database both platforms now run the same store, so the Spring Boot page names the tables VanillaBP owns instead of gruelbox' one, and the table which says what each store does differently has the opted-in gruelbox in its last row. New on both platforms: the outbox dispatches several entries at once and the workflow aggregate decides which thread takes one. The Spring Boot page explains it, the Quarkus page and the observability page point at it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23
docs: phase two is a moment, not a BPMS call Phase one is your transaction, phase two is everything which runs after its commit. The names say when work runs and not who runs it, so a call to a BPMS is one kind of phase-two work and an operation an extension registered for itself is another. The glossary of the home page, the integration SPI table, the extensions page and the outbox section of both platform pages now say the same thing, so a reader meets one definition instead of two. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23