CaseHub — uengine Notes
Cleaning House Before the Merge
Applying the squash policy to two live PRs collapses docs follow-on commits and surfaces a hitchhiker commit that snuck in under a different author's PR.
What Kind of Message Is This?
Adding MessageType to CaseChannelProvider.postToChannel forces a dependency graph decision: the engine takes a narrow compile dependency on casehub-qhorus-api rather than inventing a parallel vocab...
Workers can finally talk back
The CaseChannelProvider.postToChannel path existed but was never connected — WorkerContext.channels was always empty, and the buildContext() result was silently discarded before workers were schedu...
The Workaround That Wasn't
We submitted a PR to fix a null output bug in sdk-java. The maintainer closed it: it wasn't a bug.
Migration Gaps Closed
Idempotency window, DLQ replay, and SubCaseBinding close the last migration gaps, but a transitive quarkus-ledger dependency bundles JPA entities into every module that touches engine and breaks fo...
Worker registration as a speech act
WorkerRegistry becomes the single source of truth for all three worker entry paths — static, provisioned, self-registering — and Java 21 sealed classes provide the execution fork without an explici...
Connecting quarkus-work to the blackboard
CaseLifecycleEvent gets its missing worker execution call sites, and the casehub-work-adapter uses CDI choreography to route quarkus-work terminal states into PlanItem transitions via the callerRef...
Wiring the SPIs and adding lifecycle control
The Worker Provisioner SPIs get their call sites wired in, and resume adds a single CONTEXT_CHANGED publish so bindings re-evaluate immediately when a suspended case returns to RUNNING.
WorkBroker: wiring the shared SPI into casehub-engine
Wiring WorkBroker into casehub-engine reveals two undocumented quarkus-work-core behaviours — WorkerCandidate.of() silently drops all selections, and WorkItemStatus.EXPIRED.isTerminal() returns false.
casehub-resilience: conflict resolution, a timeout enforcer, and a Vert.x surprise
Building ConflictResolver and CaseTimeoutEnforcer surfaces a Vert.x event bus gotcha: publishing from a non-event-loop thread requires explicit context acquisition, or messages silently disappear.
Ecosystem Mapping, PRs F-J, ADR-0002
Gap closure via PRs F through J expands into a fifteen-issue ecosystem map, and the binding-gating decision — presence of stage.addBinding() as the opt-in — is validated as the only bounded and fai...
Closing Every Gap: Parity, Kogito, and ADR-0002
Four genuine gaps against the prior implementation — including strict PlanItem lifecycle and a CDI pre-registration SPI — are closed via PRs F-G and documented in ADR-0002.
QE Pass: 68 Tests to 99, Five PRs
A systematic comparison against the original implementation surfaces thread-safety gaps in PlanItem and Stage, missing end-to-end scenarios, and a null pointer hidden by the String constructor over...
Blackboard: Research, Analysis, and Implementation
Academic research into LLM-based blackboard architectures shapes one critical design decision — changing LoopControl.select() to return Uni — before the blackboard module ships its first implementa...
Cutting the JPA Wire
PR3 strips JPA from the engine module entirely — three domain objects become plain Java, twelve handlers route through three SPI interfaces, and no framework annotation remains in casehub-core.
The Dedup Wasn't Broken. The Test Was.
PR 2 shipped, Flyway is gone, and two CI failures that turned out to be different problems than they appeared.
Persistence PR 1: Container Chaos and a Quarkus Context Trick
PR 1 of the persistence decoupling plan exposes a Podman misconfiguration and a Quarkus Vert.x context requirement that blocks standard JUnit methods from calling reactive Panache.
Phase 2: Resilience, Diff Provenance, and a Persistence Rethink
Three new modules designed and shipped — resilience, EventLog enrichment, and a persistence decoupling spec — plus a conversation that changed the ORM approach entirely.
Phase 2: Standards, a Hidden Bug, and casehub-blackboard
Naming decisions resolved, CaseStatus aligned with CNCF standards, a silent bug found by the tests we wrote, and casehub-blackboard went from brainstorm to 390 tests in one session.
Phase 1: Into casehub-engine
The merge direction reversed before a single line of code was written. casehub-engine becomes the home; Phase 1 lays the extension points incrementally, one PR at a time.
Two CaseHubs, One Design
Discovering a parallel casehub-engine implementation and charting a 9-phase plan to unify both systems into one coherent design.
Session 3: Getting the Architecture Right
Collapsing the lineage graph, redesigning the persistence layer, and researching goal models across BDI, GOAP, CMMN, and HTN.
The Architecture Behind CaseHub: Blackboard Meets CMMN
Two patterns from very different traditions — Blackboard Architecture and CMMN — and why they belong together for agentic AI.
Wanted a Sketch, Got a Framework
One session, 73 files, 14,003 lines of code — what started as a request for a sketch became a working framework.