Development notes from across the CaseHub ecosystem.
Who Posted That? Mesh Participation Enforcement
The Taxonomy That Was Already There
The Import That Wasn’t
The Audit Gap — Building Test Infrastructure for Step 4
Three Dead Ends and a Bridge
Three Assumptions the Spec Got Wrong
The Minimum Honest LLM Deployment
When Two Provisioners Walk Into a Router
YAML channels — config-first for the zero-authored-Java world
The Cascade That Couldn’t See Its Own Children
Measuring the Wrong Thing
The Frida Kahlo extraction pipeline hit its targets — 276 entities, 138 goals, 57 formative experiences, all up from a baseline that had zero goals in the first import. The numbers are good. What’s more interesting is...
The Composable That Wasn’t a Component
Applications as First-Class Fleet Citizens
EmulatedGame had a supply accounting error that’s been quietly dragging down Terran and Protoss economy fidelity since the production queue was added. When a unit was queued behind another — not training, just waiting...
EmulatedGame has had mineral income since its early days — workers assigned to bases, tiered saturation rates, the whole thing. But vespene income was a gap. Gas buildings could be constructed through BuildIntents, an...
The Strangler Fig Has Teeth
The Terran economy playbook was producing 40 SCVs at the 5-minute mark. Real SC2 Terran players hit 48-50. I expected the gap to be about supply depot timing — real players pre-build depots before hitting cap, our pla...
One Algorithm, Not Two
The quorum hole and the distributed testing push
Drift badges — IoT state visualization lands in Pages
Teaching Two Editors the Same Language
A Registry That Knows What’s Alive
Sub-Thoughts and the Question They Raised
The formation memory pipeline had been broken since it was built. Twenty memories went in, zero came out, and every diagnostic pointed to the wrong layer.
Three Races, One Path
Sub-thought decomposition — turning raw experience text into typed, entity-tagged cognitive reactions — has been the intermediate representation I wanted between experience ingestion and cognitive processing for a whi...
The cluster bug fixes from last week (#485–#487) landed the routing and heartbeat corrections, but left gaps in test coverage and resilience that this session addressed.
OAuth tokens already live in OAuthTokenStore. Required scopes already live in ScopeRegistry. Whether a user is “connected to Google for Drive access” is just a question you can answer by combining those two — token ex...
A Unified Model of Personality, Relationships, and Developmental Origins
Why LLM Villains Turn Nice — and What Cognitive Psychology Says About Fixing It
The character has a gallant disposition, high-risk tolerance, a protective instinct. The cognitive system also gives it explicit tendencies: “plan obsessively,” “narrate in third person,” “volunteer for danger.” Under...
The Conductor Finds Its Audience
Measuring What the Emulator Gets Wrong
Goal tiers and progress bars — making the goal graph visible
Closing the Loop on Authentication Events
Bridging the Scenario Engine to the Topology View
The Ring That Routes
The Merge That Lies
Every Java developer knows what synchronized does. You put it on a method, and only one thread enters at a time. Reliable. Understood. And completely invisible to a second JVM running the same code on another machine.
The neocortex codebase had a pattern I hadn’t expected. A root-to-tip audit revealed that the newer cognitive subsystems — CARMA appraisal, gut feeling, behavioral synthesis, domain activation, mood persistence, atten...
Search Slots Into Place
The playbook infrastructure landed in the previous session — front matter parsing, schema registry, capability model. A playbook declares schema: clinical-server in its front matter and the registry resolves it. But n...
The knowledge pipeline was built to search for places. It worked — cache, dedup, resolution, normalization, promotion to the MindMap graph. But every layer assumed location. The orchestrator took List<LocationPlatf...
Wiring the Ops Perspective
When the Wiring Is the Feature
Three naming tiers for the playbook system
I’d assumed the upgrade detection work from the previous sessions would generalise across SC2 patch versions. It didn’t. Running the validation against HomeStory Cup XXVII replays (patch 5.0.14, baseBuild 94137) produ...
The Subconscious Call — Cognitive Appraisal Theory for LLM Character Agents
From Hardcoded Java to YAML — Externalising Nine Ref Implementations
Nine SPIs and the Simulation Boundary
Landing the Epic
CARMA: Giving LLM Agents an Inner Mind
I started this session expecting to push upgrade detection from 87.7% to 95%. I ended at 100%. The path there was not what I expected — and the lesson is about how aggregate statistics can hide the truth.
What LLM Characters Actually Need — Emergent Emotion Without Scripts
The Persistence Unit You Didn’t Ask For
The NoOp That Ate Everything
The Generator Was Already Ready
The connectors repo has nine ref implementations and a simulation framework that solve overlapping problems. Ref implementations are stateful in-memory services — you can create a contact, list contacts, and the creat...
A preset is a named desired state. That was the framing that simplified everything about this feature — the moment we stopped treating presets as a special concept and recognised them as IoTGoals files with a name, th...
Mechanical Psychology: Building a CAPS Engine for Emergent AI Behaviour
Giving Devices a Place in the World
I started this branch expecting to wire up Tile38 — a Redis-protocol geospatial database — as the cache engine for the knowledge pipeline. The design spec said so. Twelve adversarial decision reviews said so. Then, fi...
Which Building Did They Click?
CommercePlatform — Shopping Carts and the Naming Problem
Runtime Hardening — The Test Coverage That Was Missing and the Spring Parity That Wasn’t
I spent a day systematically stripping personality from LLM characters and then trying to put it back with nothing but a single instruction in the thinking field. The results changed how I think about LLM agent design.
The Same Number Means Different Things
The concurrency engine was already there
The seventh platform SPI — ProjectPlatform — drops into the casehub connectors library. Issues, labels, milestones, comments, and project boards, backed by GitHub’s REST and GraphQL APIs.
Two views of the same devices
Autonomous agents that can spin up tmux sessions and run Claude CLI are useful right up until the moment one of them decides to rewrite a codebase at $0.37 per turn on Opus. We had pool capacity management — min/max s...
The Last Panache Reference
I came in to write @QuarkusTest integration tests for the ATT&CK ingestion pipeline. qhorus#438 — the CDI deployment error that had blocked this work for weeks — was closed. Clean path forward, or so it seemed.
Hardening the Dispatch Layer
The module that was in the wrong tier
The Ablation That Worked — Proving the Taxonomy Carries the Weight
The Spec That Skipped the Audit
CBR retrieval with CASE_LIFETIME timing is meant to run once and cache the result — query the case store on first access, then return the same experiences for the life of the case. The problem: “first access” can fire...
The Constraint That Isn’t an Edge
ContactsPlatform shipped with incremental sync back in #125 — SyncResult<T>, SyncRequest, and SyncTokenExpiredException as cross-SPI primitives sitting in connectors-api. The pattern worked: null token for full ...
Three pieces of work today, each at a different altitude.
Pool provisioning has been accumulating infrastructure for weeks — scaling policies, eviction, fleet integration tests, real tmux sessions. But it was all engine-room work. No API. No dashboard. No way for an operator...
The desired-state runtime had a blind spot: every provision call returned Success or Failed. A provisioner that checked the world and found the node already at the desired spec had to lie — return Success even though ...
From Spec to YAML
Two Bugs Make a Right
Where Does the State Live?
This session built a complete test framework for YAML plugin authors. The problem: plugin authors who write zero Java have no way to verify their plugins work. They declare a resource type in YAML — spec schema, provi...
The Layers Were Already There
The three tests in #459 all passed. That was the first surprise — the issue said they were failing, but they’d already been fixed by the runtime-core extraction in #458. The real CI blocker was hiding behind them: a c...
The Brain That Lived in the Wrong Body
The Quarkus expression module had two classes — MockConfigManager and MockSecretManager — that read K8s ConfigMaps and Secrets through SmallRye Config. They’d been there since the early days of the platform, doing the...
The agent pool system had static capacity — minActive and maxActive set at startup, never adjusted. That’s fine when load is predictable. It’s not fine when you have pools of Claude sessions that spike during case exe...
Portability Across Runtimes
The Invisible 66%
The container module gets its SPI quad — and the YAML system catches up
Closing the Decay-Signal Loop
Catching Foreign Exceptions Without a Shared Type Hierarchy
Suspend/Resume — a four-verb lifecycle for stateful resources
Proving Emergence — When the Cognitive System Earns Its Keep
Wiring the Coordination Layer
The trading desk has three orchestration layers now. Case definitions detect and dispatch — reactive choreography that fires bindings when context changes. Playbooks coordinate the response — imperative step sequences...
Reconstructing What SC2 Headless Knows
When Widening a Map Type Quietly Rewrites Your Data
I’ve been thinking about what makes an agent feel Pride versus Shame — and it turns out the answer depends on whose standards you’re measuring against.
Testing lit templates without the DOM, and bridging filter events across tabs
Three Things Platform Alignment Actually Buys You
The PoC That Arrived Late
The controllers were already there
Teaching the Step System to Talk to the Outside World
Human Replays Speak a Different Language
EmailPlatform gets real — ref and Gmail implementations
Closing the Safety Net on yaml-core
The Last d3 Component
The step catalog and block control flow branch landed today — 17 issues across four sessions, touching yaml-core, yaml-jackson, yaml-step-runtime, and platform. The branch adds two things that were missing from the or...
The ChatPlatform SPI has nine capabilities — messaging, threading, discovery, reactions, presence, members, channel management, member management, message history. Today it got its tenth: Commands.
Issue #103 started as a simple evaluation: does the IoT bridge audit page need a richer viewer? The 30-line pages-ui DSL table we’d shipped worked fine for flat scanning — event type, device ID, timestamp, CSV export....
The Blocking Interface That Unlocked Everything
Archaeology as Architecture
Teaching agents when to care
The canonical layer problem in the casehub ecosystem is always the same: you have a raw Java API that works, and you need to make it declarative. The pattern — fluent DSL, annotations, YAML — is established across eng...
The dead letter queue has a replay mechanism. Worker fails, retries exhaust, entry lands in the DLQ, admin reviews it, triggers replay. DeadLetterReplayService loads the case, finds the original scheduled event in the...
The Conductor That Types For Itself
Server-Side Data Providers — From SPI to Prometheus Showcase
Broadcast Without Channels (Sort Of)
bank-ref: When the Pattern Absorbs the Complexity
Your Agent Doesn’t Know How It Feels
The ONNX strategy classifier could count units and buildings, track upgrades and economy stats — but it had no idea where anything was on the map. A Terran player with marines near your natural expansion and a Terran ...
BankPlatform Gets Real — TrueLayer as the First Provider
Until now, devtown’s reviewer agents were stubs. The whole coordination layer worked — CasePlanModel dispatch, 4-tier failure cascade, trust scoring, qhorus speech-act messaging — but the thing that actually reads the...
When your agent forgets what it wants
The Map Key Nobody Imported
One Type to Rule Them All
Observability That Doesn’t Pick Sides
Stopping the Drift: Adopting yaml-core Constructs in Desired State
The Search That Skips the Catalog
The Persistence Boundary
The One-Line Fix That Wasn’t
Until today, casehub-soc had two kinds of memory. CBR stores structured incident records — feature vectors that let the retrieval engine find past cases by similarity. The ATT&CK corpus stores public threat intell...
The Bug That Wasn’t There
I came into this session expecting to pick up from where the previous session left off — Task 3 of the blocks-social-jpa plan, refactoring StrategyLearningOrchestrator to use the new StrategyStore SPI instead of reach...
The engine’s context recovery had a design flaw hiding in plain sight. On cache miss, rebuildStateContext() would replay the entire event log to reconstruct CaseContext — scanning for seven event types, applying diffs...
Reporting for auditors — from data services to offline verification
The question behind #116 was simpler than it looked: how does a family go from “installed the app” to “using it”? Until now the answer was Flyway seeds and REST calls — fine for demos, useless for anyone else.
Most agent frameworks treat goals as strings. A prompt says “help the user book a flight,” the LLM generates actions, and when the actions stop, the goal is done. There’s no memory of the goal, no tracking of what blo...
Fourteen issues, five repos, and one question that started it all: can a platform built entirely on Quarkus CDI also deploy on Spring Boot without maintaining two codebases?
Simulation as a First-Class Citizen
Hardening the Agent Pool — From Design to Deployable
I wanted to add goal cognition to neocortex — recognition from experience, dependency tracking, affective valuation, prioritisation. Epic #345 lays out seven scope areas backed by BDI research and the existing cogniti...
Last session I discovered the platform simulation framework and used it to replace hand-written simulation modules for two flat SPIs. This session I tried to do the same thing for a capability-based SPI, and the frame...
The Claude backend talks to Claude Code CLI via the claude-code-sdk. When someone configures authMethod: gcp-adc in the model catalog, nothing happened — the backend didn’t know how to use Vertex AI transport. That’s ...
The Obligation Envelope
A self-improving system that can’t measure its own health is just a random walk with extra steps.
QhorusMcpTools was 2092 lines of accumulated test infrastructure. Every test in the project injected it. Every channel creation was a 19-argument method call where 17 of them were null. After #451 stripped the MCP ann...
Agents Aren’t Connections — Why CLI Session Pools Need a Different Model
Perspectives and the Ops Manager
Closing the YAML parity gaps in the simulation framework
I started this week thinking I was going to write two platform SPIs and a pair of simulation modules. I ended it with two SPIs, zero simulation modules, and a filed issue asking someone else to make YAML do what Java ...
The temporal simulation driver from #371 gave us a lifecycle controller — start a named profile, pause it, change speed, stop it. But it was fire-and-forget. You injected the factory, called start(), and hoped someone...
The Wiring Problem — When Your Cognitive Architecture Works but Your Game Doesn’t Know It
The Rename That Wouldn’t Rename
The Hive That Improves Itself
The simulation framework already had the data model for timed event sequences — TimedEntry<E> carries an event and a relative delay, TimedSequence<E> orders them with a time multiplier. What it didn’t have...
Qhorus has been accumulating @Tool methods in a single 2,756-line class since the project started. QhorusMcpTools owned everything — channel configuration, message dispatch, artefact storage, commitment lifecycle, wat...
165 Lines of Duplication, Two Lines Each
Profiling the Right Bottleneck — Consolidation Phase Scaling
Simulation DX: The Last Mile
Why Your AI Agent Fixates — And What Maslow Can Do About It
Every addNode() call in the MindMap subsystem traverses a chain of five CDI decorators before reaching the database. Each decorator reads back from the store to do its work — DerivedEdgeDecorator fetches the edge and ...
Eighteen Issues Later
The Bridge and the Gate
Neocortex has been growing fast. Four capability areas, 40+ modules, CDI decorator chains ten deep, consolidation phases running on background threads, and cognitive subsystems wiring into each other through events no...
Zod v4 has been stable for fourteen months. Every package in the ecosystem has moved. We were still on 3.x, and the longer we waited the more migration debt we accumulated — particularly since the pages-lsp completion...
Nine Stores, One Pattern
Breaking circular repo entry — 9 to 2 cycles across 8 repos
Every @McpDomain SPI in the platform follows the same three-file pattern: an interface in platform-api, a default implementation in the runtime module, and generated REST + GraphQL endpoints from the APT. For domains ...
Volatile Swaps and Watcher Threads
The Correction That Corrected the Design
Continued from The bugs that weren’t.
The workbench had six entry points that mutated document state, three independent write-back paths, and no coordination between them. Every editor keystroke created a new PageDocument, killing undo history. Every mode...
The cognitive subsystem’s consolidation pipeline had a naivety problem. A single observation about someone — “Bob looks worried” — could graduate to a permanent belief. The CBR retrieval pipeline returned five cases t...
CaseHub’s dispatch model is reactive — a JQ expression evaluates to true, a binding fires, a worker runs. It’s clean, it’s predictable, and it’s exactly wrong for self-organizing agents.
@McpDomain on Classes: One File, Four Outputs
From Pieces to Pipeline
I wanted to build a tutorial example showing CBR ensemble consensus end-to-end — agents reading .cbrEnsemble.stepAnalysis to see which past response steps have UNANIMOUS agreement versus CONTESTED disagreement. Three ...
Four bugs were filed against the graphql-generator APT. Hyphens producing illegal class names. Slashes breaking class name generation. The generateGraphQL=false flag being ignored. The domain filter letting everything...
When Norms Learn to Compete
The Simulation Gap
The Brain That Couldn’t Think
From 30 Games to All of SC2EGSet
Signing Agent Cards — Cryptographic Identity for Qhorus Agents
Teaching by typing
The previous session fixed the upstream CDI drift and built the first real connector — CrowdStrike Falcon for host isolation. This session took the same contract and stamped it across two more external APIs: Palo Alto...
The Package Sync That Wasn’t
Encapsulate the Format, Not the Field
Zero Hand-Written REST
Three Generators in One Sitting
Why Your LSP Completions Land at Column Zero
Fifteen steps that found two edges
Dependency Drift Archaeology
When the Caster Says GG But Nobody Died
When the Pipeline Meets Reality
When Telling AIs How to Think Makes Them Worse
Watching the Cascade Unfold
I started the day planning a tutorial — fifteen steps teaching users how CaseHub Playbook YAML works. I ended it designing a universal composition language.
The Last Repo and the BOM That Broke Everything
The Constraint That Wasn’t
The original plan called for five code generators — REST, persistence, security, GraphQL, and MCP — each producing Spring integration layers from Quarkus source code. Five sounded reasonable from the issue description...
Building a Commentary Training Dataset from SC2 Replays and Caster VODs
One SPI, Three Surfaces
One Interface, Three Surfaces
Why Your LSP Server Runs But IntelliJ Ignores It
Cross-Domain Composition Lands
The MindMap extractor has been producing entities with properties for months — person nodes with roles, meeting nodes with dates, belief nodes with stances. But every extraction was open-ended. The LLM had no memory o...
Calling Out
The Mansion Learns to Sleep
The Ecological Inference Trap
Detecting the Pivot
The Frame Rate Insight — Synchronized Replay Commentary
CaseHub is YAML-first. Pages, case definitions, agentic patterns, org structures, cognitive profiles, work templates — all authored as YAML documents. The CodeMirror editor with schema-driven autocomplete handles synt...
The pipeline that ate the synthesiser
Teaching the Audience to Talk Back
Perspective Is Constitutive
Teaching the Router What a Model Actually Is
When the Expansion Dies
From Server to Plugin in One Session
Every Resolution, Same Pipeline
Context on the Wire
When the Agents Stop Being Stubs
The GraphQL migration’s second domain landed today: messaging. Thirteen operations — five queries and eight mutations — ported from QhorusMcpTools into MessagingQueryResolver and MessagingMutationResolver.
The SPI Nobody Injects — Part 2
The Last Four Gaps
The Generator That Already Existed
The Extraction That Wasn’t a Rewrite
The plugin architecture landed two days ago and immediately told me what to do next. The step pipeline’s interpolation engine — prefix-based ${spec.*}, ${auth.*}, recursive map walking, expression evaluation — is the ...
Half the Backlog Was Already Done
Does the Cascade See the Army?
When the Reviewer Kills Your Architecture
The Army That Never Moved
Building an LSP Server from a Schema Walker
The agentic package has eight orchestration topologies — supervisor, debate, loop, parallel, voting, conditional, sequence, HTN — each assembled through Java builders that produce an ExecutionModel. The builders are g...
The desired-state runtime knows how to provision, monitor, and self-heal any resource type — as long as someone writes the Java. A NodeProvisioner, an ActualStateAdapter, a NodeSpec record, fault policies, and at leas...
The question that kicked this off was simple: can casehub run on Spring Boot as well as Quarkus? The answer turned out to be more interesting than I expected — not because it’s technically hard, but because the right ...
blocks-ui has around fifty web components, and until today none of them had a formal declaration of what properties they accept. The @property() decorators on each class were typed, but nothing enforced that contract ...
The AE regrading spec (#135) introduced grade changes — Grade 1 nausea becomes Grade 3 dehydration. The spec handled the easy case: when no engine case exists, start one. But it explicitly punted on the hard case: wha...
The engine already fires a per-step signal when workers complete — RoutingOutcomeRecorder runs on both success and failure paths in WorkflowExecutionCompletedHandler. I’d assumed fsitrading’s C6a request (per-step CBR...
Moving Schema Shorthands Out of the Post-Processor
The missing half of compensation visibility
The SOC dashboard shows incidents. The analyst workbench shows work items. SSE pushes updates in real time. But if a SOC manager isn’t staring at the screen when a P1 drops, they don’t know about it until they check. ...
The SPI Nobody Injects
The engine’s binding model had an asymmetry hiding in plain sight. producedKeys on a Binding declares what context keys a worker writes — the effects side. But nothing declares what a binding reads. The preconditions ...
The migration that found three bugs it wasn’t looking for
The cross-platform capacity redistribution spec puts ActorCapacityView on SelectionContext — the caller passes it per selection call, the selector forwards it to the probe. Clean on paper. Wrong in practice.
Three Ways to Undo — Teaching Compensation by Example
I came into this session planning to build three modules on top of the existing summarisation framework — a YAML pipeline surface, a CloudEvent bridge, and an API extraction. Straightforward layering work: take what e...
The Prompt That Knows Its Audience
Built <pages-code-editor> — a CodeMirror 6 web component that wraps a full editing experience inside a Lit element with shadow DOM. The starting point was simple: extract the inline YAML highlighter from blocks-...
The 167-Line Delete
Landing the Workbench — Eight Batches and Four Upstream Components
The desired-state runtime has a graph engine problem. GraphRuleEngine and GraphInvariantEngine are generic in purpose — fixed-point evaluation, pattern matching, cycle detection — but they’re littered with imports fro...
Closing the Annotation Gap
Two Registries and a Broken Contract
108 unit tests. All green. The demo was broken in three different ways.
Recursive Forms
Pressure as a Shared Vocabulary
The saga compensation epic started with a question: what happens when completed work needs to be undone? Nine issues later, the answer spans five repos — engine, work, ledger, qhorus, connectors — and today’s session ...
The Viewer That Was Already There
Three Root Causes Behind One Red Build
The Question That Killed the Example
The Native Lib Problem Is a Distribution Problem
The Gate You Already Have
Inheritance Without the Inheritance
Feedback Loops That Converge
When Done Isn’t Done — Designing Saga Compensation for CaseHub
The Bug That Hid a Bug
The Audio Pipeline Nobody Documents
Shared Vocabulary for Overload
Selection: from imperative DOM wiring to parameterised datasets
Multi-Select in a Pipeline Editor: 1-in/1-out and the Constraints That Make It Work
From Three Stores to One Mind
The issue said “per-tenant SLA defaults YAML.” We built something different — and it took about 130 lines of production code, because the hard work was already done.
Teaching Machines to Remember Market Crashes
We Accidentally Built a YAML Programming Language
Workbench v2 — Composition Over Construction
yaml-core has been accumulating Object returns and positional parameter lists since it was first written. Everything worked, but the API was lying to the compiler about what it knew. ParameterType.parse() returned Obj...
The Goal That Earns Its Rank
Org Annotations — Closing the Loop
From Wanting to Doing
A case definition describes what can happen — bindings, workers, capabilities, milestones. An HTN decomposition describes the strategy for making it happen — which tasks, in what order, under what conditions. A Server...
Closing the loop
Drag-and-drop and the position problem
Three Copies of the Same Bug
Two features landed on this branch, both chasing the same goal: a YAML-only tutorial path for casehub-work that requires zero Java.
When the Review Is Right
The Deserializers That Deserialised Themselves
Signing the Evidence
From demos to tutorials
I started this session wanting to know: can the desired-state YAML frontend handle real-world deployment architectures? Not just “declare three K8s deployments” — the full spectrum. A single-service blog on a Raspberr...
The Ref That Connects the Diagrams
The Pipeline That Isn’t Hard-Coded
From demo tool to data-driven automation
Three Confidences Walk Into a Bar
The Toolbox That Isn’t a Framework
The pipeline works. Audio8 DualAR synthesis end-to-end through the avatar WebSocket — tokenize text, build prompt with default voice, run slow AR and fast AR inference, decode codec frames to 44.1kHz audio, enrich wit...
The scenario engine wants to be an automation platform
Making it real
I went into this session planning to integrate Fish Speech — the open-source TTS model that benchmarks closest to human parity. The issue had it tagged as S/Low: “follows established ONNX TTS integration pattern.” Str...
The Type You Don’t Add
The Operator Surface That Scales Down
Closing the Snapshot Gaps
Giving the Workbench a Public API
The Modal That Blocked Everything
The Contract Before the Caller
Shadow DOM Ate My Test API
Schemas That Know Their Shape
Packaging the Evidence Trail
Drag from Anywhere
The issue looked straightforward. Qhorus needs to select agents by trust score from eidos discovery results. Eidos already has AgentRegistry.find() returning List<AgentMatch>. Add an SPI that takes those matches...
The Tensor Nobody Reads
One Layout System
Three issues closed in one branch, all building on the @GraphRule infrastructure from the previous session. The work was straightforward — extend the annotation model with standalone rule containers, @Tier(nodeType) v...
Six Units, Three Inputs, One String
Where Types Live Matters
I started with a clean-sheet design for reputation-aware routing in qhorus. An agent dispatches a COMMAND with target: "role:analyst" and the system picks the best agent for the job based on trust scores. Straightforw...
Quarkmind’s evaluation of blocks-ui came back with a list of reasons not to adopt. Most of them were wrong — but one was accidentally useful.
The Race the Review Caught
The Diagram That Saves Itself
The Agent That Speaks
Spaces Shouldn’t Be Invisible
Teaching Qhorus to Route by Reputation
Property palette: schema-driven editing from first principles
Building the Rule Engine
The Mapper That Wasn’t Needed
The Group That Decides to Want
Surgical Replant — Why Full-Tree Remount Was Always Wrong
CloudEvents Across the Wire
Continues from Personality That Grows.
The Store That Serialises a Sealed Hierarchy
One Model to Rule Them All
Graph Rewriting for the Annotation Model
Decomposing the God Closure — What Extracts Cleanly and What Doesn’t
Closing the Loop on CBR Learning
The Agent That Remembers Its Story
The Rename That Proved the Point
The Type That Was Always Missing
Reflection-generated JSON Schema and hand-written JSON Schema encode different mental models of the same type system. The generated schema sees the Java type graph — every field, every transitive dependency, every enu...
DTW Doesn’t Do What You Think
The original spec for #123 concluded that PagesEventTimeline’s host-pushed data model was incompatible with BlocksTimeline’s self-fetch model. That framing justified shared renderers via composition — both components ...
Colons All the Way Down
The Panels That Already Existed
From Wanting to Doing
YAML Viewer and Visual Feedback
Designing an Annotation Model for Compositional AI Orchestration
A spoken thought decays faster than any other kind of input. You say something useful while reading a document, while debugging, while walking — and unless something captures it immediately, it’s gone. The interesting...
The Issue That Was Already Done
The audit-trail-viewer at 695 lines had been doing three jobs: rendering a filter bar, managing a data table with expansion, and handling ledger-specific concerns like Merkle verification and attestation badges. IoT n...
The Build Extension That Trusts the Builder
Teaching the cascade to see races
Speech SPIs — voice in, voice out
Continuing the scenario engine series.
Governance in Action: When Agents Need More Than Politeness
The Effects That Watch Themselves
Dead Parameters and Hidden Redundancy
The SOC web application has four sidebar tabs. Three were built. The fourth — Compliance & Audit — was a placeholder. Now it’s not.
When Reasoning Becomes a First-Class Record
The plan was straightforward: BlocksTimeline should extend PagesEventTimeline from pages-viz. Both components render the same three timeline layouts (vertical, horizontal, compact). Both consume the same node type. Th...
Last session designed the ONNX cascade wiring end-to-end. This session started building it — beginning with the foundation: extending GameState to carry economy stats and upgrade tracking.
Boolean conditions got per-expression language override in engine#925 — a binding’s when clause could be JQ, MVEL, or whatever the ExpressionEngineRegistry supports. But data transform projections (inputProjection, ou...
When the planner can’t see ahead The GOAP planning strategies had comprehensive unit tests — mock the CaseDefinition, mock the CaseContext, assert the planner returns the right binding. What they didn’t have was a sin...
The Trust tab was supposed to be the hard one. Phase 1 (Incidents) was data display. Phase 2 (Workbench) was form interaction. Phase 3 — trust scores, routing rationale, CBR similarity — felt like it would need new pl...
Wacky Manor’s ObservationBuilder had been doing two things: assembling world perception (what’s in the room, who’s here, what you remember from the kitchen) and assembling cognitive state (your goals, your plans, your...
Three ONNX models arrived from neocortex this week — one per opponent race, trained on 71 SC2EGSet tournaments. The numbers looked good: 70% vs Terran, 78% vs Zerg, 81% vs Protoss. The feature extractor that would fee...
Seeing What You Want
Boolean conditions got per-expression language override in engine#925 — a binding’s when clause could be JQ, MVEL, or whatever the ExpressionEngineRegistry supports. But data transform projections (inputProjection, ou...
The engine’s worker scheduling was welded to Quartz. Not by design — by accumulation. Six job classes had grown to hold domain logic that had nothing to do with scheduling: case loading, definition resolution, retry p...
CaseHub uses LangChain4j. The ChatModel abstraction, the tool-calling pipeline, @RegisterAiService — LC4j is our LLM client layer and I’m not looking to replace it. So when I started designing annotation-driven orches...
@DeclareNode — distributed graph composition via class-based annotations
Thirteen Agents and a Split
The Authoring Surface
The Review That Rewrote the Design
The Contingency
The Judgment Layer
The Agent That Wants
What Does the Agent Want?
The Mood That Colours Memory
The Social Brain
Continuing the scenario engine series.
The feedback loop (#40) gave RAS a memory — outcomes flow back and adjust detection thresholds and priors. But the metrics it publishes are situation-level. A situation with an 80% noise rate tells you the situation i...
The Strategy That Learns from Engagement
Continued from Designing the Distributed Executor Protocol.
Continues from The Signal Your Model Can’t See.
Four Annotation Layers, One Interface An agent that assesses aircraft defects needs to be cautious and methodical. Its inspector sign-off requires two independent approvals. Every step must produce an audit trail that...
The ledger’s annotation module shipped last session — @Audited, @ComplianceSupplement, @Attested, the full interceptor pipeline. Deployment tests passed. The example compiled. And then a real @QuarkusTest boot threw L...
devtown had accumulated seven incremental Flyway migrations for a database that doesn’t exist yet. No production deployment, no live data to migrate — just a growing chain of ALTER TABLE and CREATE INDEX scripts that ...
When Coarse Fails, Decompose
Closing the Loop
The Mind That Reads Minds
The Profile That Builds Itself
Continues from The Format Nobody Documented.
The Agent That Speaks First
Removing the GraphQL Tax
Continues from The Data You Don’t Have.
The Drift That Stays in Bounds
Continues from Teaching the Bot to Remember.
Continued from The outbound bridge.
Continued from Specifying a Scenario Format Before Building the Engine.
From Tool Calls to Browsable State
The hierarchical MCP model uses two tools — casehub_model for navigation, casehub_action for dispatch. That design holds. But until now, casehub_action had a static schema: three string parameters, no guidance about w...
The Memory That Forgets on Purpose
The strategy classifier had three ONNX models trained on synthetic data. The synthetic training exposed the real problem: class imbalance so severe that the model couldn’t learn tail archetypes at all. TECH_RUSH had 4...
Continues from From Event to Response — quarkmind-chat Phase 1.
The RAS has always had a gap: you couldn’t answer “would this definition have caught last week’s incident?” without deploying and waiting. Situation definition authoring was trial-and-error in production. Threshold an...
All manor events used to share a single EventLevel("manor", 0). Every dialogue, every movement, every aside — same priority. That’s fine when TieredObservationRenderer only tiers by count, but it means level-based fil...
Qhorus has had an inbound A2A path for a while — external agents send JSON-RPC requests, A2AResource dispatches them into channels, and the commitment lifecycle tracks the work. What was missing was the reverse: a cha...
The examples gallery had a gap. Every dashboard ran client-side — static data, mock fetch responses, no real WebSocket traffic. With durable EventStore backends already landed, the push protocol had no home where some...
The entire SOC investigation pipeline — alert ingestion, IOC enrichment, ATT&CK mapping, threat assessment — exists to produce evidence for a single moment: an analyst pressing one of four buttons.
Continues from Specifying a Scenario Format Before Building the Engine.
The federation and client modules have been sitting on issue-92-distributed-workitems for a while now, built but undocumented in ARC42STORIES.MD. This session closes that gap — adding the C4 diagram entry, Module Inde...
When a case reaches investigation-closed-no-sar, the triage evaluator originally said “file a SAR” but human authority overruled. Until now, the trust routing system had no way to learn from that. The triage agent’s s...
The Middle Ground
A2A interoperability needs qhorus messages to carry structured data — not just text content but JSON payloads representing DataParts, tool outputs, artifact metadata. The design decision was straightforward: add a nul...
Wiring the Middle Brain
Qhorus has always been richer than A2A. Typed channels with declared semantics, a ten-type speech act taxonomy, commitment tracking with attestation, normative governance — it’s architecturally deeper than anything th...
The Composition Trap
A CDI audit flagged five classes in neocortex for unnecessary CDI annotations. The criterion: zero injections. The class doesn’t @Inject anything, so CDI must be unnecessary. Five out of five were wrong.
The connectors repo had no presence on the platform MCP surface. Engine and work domains exposed their operations through casehub_model/casehub_action — cases, work items, lifecycle — but the connector layer was invis...
The IoT webapp had been building every page by hand — four-column KPI metric cards assembled from columns() + metric() DSL, work item actions as inline HTML buttons with onclick handlers, device detail as stacked pane...
When "Created At" Means "Deployed At\ CaseInstanceResponse had a createdAt field from day one. It was labelled “Case creation timestamp” in the OpenAPI schema. The value came from CaseMetaModel.getCreatedAt() — which ...
The Cascade That Reviewed Itself
The Trading Desk is a dock-workbench — nine panels composed entirely via the pages TypeScript DSL, no custom web components beyond the existing Market Pulse panel. Positions, P&L heatmap, strategies with a split o...
When UNKNOWN Means Yes
The pages runtime has a template system — #{params.caseId}, #{selection.cases.status}, #{filter.ward} — that resolves context values into strings wherever they appear. Title components resolve them. HTML content resol...
GraphCanvas was designed as a self-contained component: give it a model, it runs ELK layout, renders the result. But blocks-ui’s diagram components already run their own ELK pipeline — they compute layout with decorat...
The pages-viz barrel export has a problem. PagesDensityHeatmap statically imports @drdreo/heatmap at the top of the file. The barrel re-exports it. So any downstream consumer importing anything from @casehubio/pages-v...
The rejection routing implementation is complete — supervisor extension, integration tests, the full end-to-end path from gate rejection through senior analyst review and head-of-compliance escalation. But the interes...
The last open items on epic #92 (Distributed WorkItems) were the hard ones — cross-service federation and coordinated rollback. Single-cluster distribution was done months ago: PostgreSQL LISTEN/NOTIFY for SSE, @Versi...
The AML harness has had oversight gates since Layer 9 — when a worker declares a consequential action like filing a SAR, the engine creates a WorkItem that a human must approve before the action proceeds. What it didn...
The SOC incidents list endpoint had a createdAt field that returned Instant.now(). Every time you called the API, every incident had a different creation timestamp. It was a placeholder from the initial wiring — SocIn...
The Store That Forgot to Persist The orchestration workbench needed an SSE endpoint streaming execution state. The engine already had all the data — ExecutionStateSnapshot composing plan model, DAG plan, and DAG resul...
The map that mixed languages
The casehub-work repo had three open epics. Two of them — #79 (External System Integrations) and #92 (Distributed WorkItems) — were marked as blocked on CaseHub and Qhorus not having stable APIs. The blocker sounded r...
The chat module has a running agency loop. Not connected to a real Discord server yet — no bot token, no live LLM — but the structural path from “a message arrives on a Discord channel” to “a governed response is disp...
The pages TypeScript DSL had a curious inconsistency: components existed, rendered correctly, appeared in the activation pipeline — but you couldn’t construct them from the builder API. Seven component types (heatmap,...
CaseHub’s agent identity system is rich — AgentDescriptor alone has 21 fields, and a fully-specified agent with disposition, goals, constraints, and capabilities spans 40+ lines of builder code. That’s the right level...
Three Ways a Quarkus Extension Can Silently Do Nothing The casehub-engine-annotations module reached Batch 4 today — repeatable @Bind fix, goal-to-effect-key mapping, build-time validation. Twelve tasks done across fo...
The C3 deliberation spec deferred WebSocket push to a follow-up issue. The implementation looked straightforward — wire lifecycle events (start, complete, fail) to PushBroadcaster topics, add per-round convergence upd...
The Review That Paid for Itself
Continues from Debate as Architecture.
When Annotations Meet Planners CaseHub has three ways to define a case: YAML, fluent builders, and now — annotations. The builder API works. The YAML mapper works. But both require you to know the type system intimate...
The issue said “no new logic — just a new view composing existing snapshots.” Six endpoints already existed on PlanResource serving decomposition trees, DAG plans, execution results, and live plan models. The orchestr...
The ops console has had a detection-to-dimension routing layer for a while — ServiceDetectionBridge maps situation types to dimension context writes, and ServiceCaseDescriptor declares engine bindings that spawn child...
The engine already observes two compliance dimensions — latency and attestation rate — and feeds them to eidos for trust scoring. Both are straightforward: measure the clock, check the outcome. Adding the two remainin...
Continued from GDPR in a Tamper-Evident World.
The issue asked for a RoundListener — a callback on ConversationOrchestrator that fires per round so consumers like fsitrading can push convergence updates via WebSocket. Simple enough, except the orchestrator’s termi...
casehub-aml has been accumulating Flyway migrations since Layer 4 — twelve files just for aml-engine-ledger, four more for aml-ledger, a handful each for trust routing and the query view. Twenty incremental DDL script...
The scaffold console’s Queues tab was pointing at two endpoints that didn’t exist: a GET /queues/health for the KPI metric row, and an enriched GET /queues that includes per-queue counts. The per-queue plumbing was al...
The blocks research doc identified six composition patterns for autonomous agents. All but two compose existing platform capabilities. The two gaps: dynamic emotional state (mood) and conversational engagement scoring...
Until now, casehub-soc has been an engine with no dashboard. Alerts arrive, workers investigate, containment recommendations get generated — but the only way to see any of it is through REST calls and log output. We g...
The IoT repo had five open bugs clustering around the OpenHAB provider — device class mapping gaps, command dispatch failing silently on Color items, a persistence unit that was never configured, and the headline issu...
QuarkMind started as a StarCraft II agent. The agency framework we extracted into quarkmind-core — needs, intents, perception, the whole perceive-need-goal-plan-act loop — was always meant to work for other worlds. Qu...
The causedByEntryId chain has been the backbone of the AML investigation audit trail since Layer 4. Every ledger entry links to its causal predecessor — case opened caused compliance review, compliance review caused S...
Continues from Boring Is Good.
The blocks conversation protocol was designed for structured multi-agent dialogue — points raised, agreed, disputed, resolved. Epistemic common ground tracks what’s established fact versus contested claim. Convergence...
Continued from The First Tab That Showed Nothing.
The IoT webapp declares casehub-blocks-ui-npm as a Maven dependency, unpacks it to .casehub-packages/, configures portal resolutions in package.json — and then never imports a single component from it. All seven pages...
The GDPR regulatory audit epic hit three issues this session — Art.22 decision record supplements (#82), entity data erasure in ledger content (#83), and cross-tenant erasure (#84). The interesting one was #83.
Autonomous Minds in Virtual Worlds
Continues from Goals Think, Plans Act.
The ledger-graphql module went in today. Third domain — after engine and work — following the same @GraphQLApi + @McpDomain thin-resolver pattern. Seven queries, two mutations, a ModelEnricher, twelve unit tests. The ...
Three domains down, two to go. Engine, work, and the typed client all have their GraphQL + MCP modules built and tested. The pattern that emerged from the engine work — @GraphQLApi plus @McpDomain on thin resolver ada...
The AML investigation had a nine-layer foundation, deterministic triage logic, CBR-adjusted thresholds, and a complete SAR filing pipeline. Everything worked. But every investigation ran the same way: entity resolutio...
QuarkMind started as a StarCraft II agent. The restructure spec (#272) laid out a vision: split the mono-module into quarkmind-core (shared agency framework) and quarkmind-sc2 (game-specific code), so that Town, Minec...
Continues from Goal Lifecycle.
When we shipped the 9-type message taxonomy in April, ADR-0005 made a completeness argument: every message type maps to exactly one obligation lifecycle transition, no transition is unrepresented, no type covers two t...
Building the hierarchical MCP model was the easy part. The harder question: does it actually work? Can an LLM navigate a two-tier operation catalog and construct correct casehub_action calls, including nested record i...
Pattern gaps: speech acts and seven patterns
Continues from Memory Stack Wiring — the first layer of the autonomous agent template.
Continues from 2026-08-14: When Stubs Become the Architecture.
QuarkMind started as a StarCraft II game AI — strategy, economics, scouting, trust-weighted plugin dispatch, all running at game-loop granularity over the CaseHub engine. It was always a living lab for the agentic har...
The trust model scored subjects but not attestors. An agent that consistently endorsed poor work had the same weight as one that tracked quality accurately. The fix is credibility weighting — a third factor in the tru...
CaseHub has a tool proliferation problem. Qhorus alone exposes 37 MCP tools. Add connectors, IoT, openclaw, and drafthouse, and a unified CaseHub server puts 60+ tool definitions in front of an agent. Context wasted o...
The supplement that breaks the chain
The execution drivers have always been blind. OrchestratedDriver and ChoreographedDriver run the five-phase loop — route, activate, dispatch, aggregate, terminate — but they only see what comes back from agent dispatc...
Continues from 2026-08-10: When Eviction is Wrong.
The scaffold console has ten tabs. Nine of them worked. The first one — Cases — showed an empty data table while the Orchestration tab, pulling from the exact same dataset, rendered six cases without complaint.
The commitment endpoint has been a placeholder since the demo UI was scaffolded — returning a flat CommitmentLifecycleResponse built entirely from ProtocolDeviation fields. DevId, status string, commanded-at timestamp...
The milestone trust scoring infrastructure from #191 evaluates strategies at game checkpoints — frame thresholds and phase transitions. A strategy dominating at the 3-minute mark gets partial credit even if the game i...
The WorkItemStore SPI extraction landed today. The core move: pull the store interface and its return type out of the runtime module into api/, so consumers like persistence-memory can depend on the query SPI without ...
casehub’s goal decomposition pipeline looked complete on paper. An LLM takes a high-level goal, produces an ordered sequence of capability references, and the engine materializes them as compound PlanItems with CHOREO...
The foundation from yesterday — AgentBackend, RoutingAgentProvider, SubprocessRuntime — was deliberately generic. Today was about filling in the grid: four provider modules, each proving a different integration patter...
The previous session built the Market Pulse pipeline — five summarisation levels, synthetic tick generation, LLM-powered regime assessment, REST endpoints, arena integration. All of it working. But the push path — the...
The MultiFactorDominanceAssessor has measured dominance across four dimensions since it replaced the supply-only assessor: economy, army value, tech tier, base count. Each factor contributes to a weighted score that d...
I came in to add event-bus integration to ChoreographedDriver — the issue had been open since the engine integration spec, parked as a deferred concern. The driver had a WaitingForEvent state transition between iterat...
Dimensional reviews — where coherence, structure, and robustness each get their own reviewer — have been running for weeks. The problem was always the same: three processes running in parallel, progress visible only i...
Every CaseHub application has the same problem: you can’t demo it without faking half the world. Clinical needs patients, adverse events, a trial protocol, and an IRB review cycle. Life needs bank transactions, WhatsA...
CaseHub’s agent infrastructure has been Claude-only since day one. ClaudeAgentProvider wraps the Claude CLI subprocess, ChatModelAgentProvider bridges LangChain4j for everything else, and a CDI priority ladder picks t...
The goal was simple: at game close, compare what the scouting system predicted early against what actually happened, and store the result as a CBR feature. Future games could then query: “in past games where our early...
The compliance module knows everything about controls — evidence freshness, posture scores, framework mappings. The ops-console app knows everything about infrastructure — K8s deployments, config maps, cluster topolog...
Wiring IoT Situations into the Platform Subscription Engine
Upstream consumption and push protocol adoption
The Strategy Arena evaluates market signals through multiple strategy agents concurrently, aggregates their trade decisions via voting, and executes the consensus. The interesting design question was where to put the ...
The previous entry covered why the arena is a blocks composition rather than a case engine lifecycle. This one covers what happened when we wired the full pipeline — routing through to execution — and where the design...
The architecture document says six JpaLedgerEntry subclasses — one per investigation step. AlertTriageLedgerEntry with typed severity fields and NOT NULL constraints. ContainmentDecisionLedgerEntry with a schema-enfor...
Teaching the SOC to remember
The AML harness had nine completed foundation layers and looked healthy from the commit log. A systematic audit told a different story: five epics that were done but still open, three more that had been partially impl...
Workers in the case diagram were opaque — a box with a name and a capabilities list, regardless of whether the thing behind it was an LLM agent, an MCP tool server, an A2A remote, or a simple step sequence. The engine...
Two things looked routine today. A workspace audit — checking that branches were properly closed across the casehub family. And a CDI cleanup — removing unnecessary @ApplicationScoped annotations from 21 classes flagg...
An automated audit flagged four @ApplicationScoped classes in qhorus for having “unnecessary CDI” — zero or one @Inject fields each. The heuristic is reasonable: if a class has no dependencies, why does it need CDI? R...
The scenario engine epic (#408) spans seven repos and could easily become a coordination disaster. I decided to start with the two specification issues before touching any code — the YAML format spec and the demo SPI ...
The CBR layer knows who the opponent is in emulated mode — the enemy strategy name goes straight into the case. In mock mode, a config property stamps “mock-opponent” on every game. But in real SC2 mode? “unknown”. Th...
Issue #41 is the big one: wire the full neocortex and engine cognitive stack into wacky-manor as the canonical autonomous agent template. Characters should remember, reflect, track relationships, and eventually form g...
Three codebases had rate limiting. All three were doing the same thing differently.
Your MCP Server Has Too Many Tools
The CaseHub platform has changed substantially since fsitrading was first scaffolded in June. blocks now has a full agentic orchestration framework with eight composable patterns. blocks-ui ships 31 domain components....
The orchestrator was wired up — DebateAgentInvoker, DebatePromptAssembler, DebateResponseBuilder, the autonomous flag, everything constructed and stored on the session. But nothing started it. converse() sat there, fu...
I set out to implement SocSlaBreachPolicy — the SOC escalation chain that routes unclaimed or overdue WorkItems from tier-1 analysts up through tier-2, tier-3, and eventually to the SOC manager. The policy itself is s...
The FloatingFrameEngine landed as a clean separation: engine holds state, backend renders Dockview, activation wires events between them. Three layers, clear boundaries. One problem: every consumer duplicates the same...
Cost budgets looked simple at first glance. The issue asked for a costBudget field on PlanningConstraints — an integer, like resourceLimit. One number, one meaning.
When Your Routing Doesn’t Route The plan for engine#882 was straightforward: when an HTN step fails, feed the failure context back to the decomposition strategy and let it produce a revised plan. Three moving parts — ...
The final piece of the agent learning sub-epic landed today — goal formation. Agents can now discover new goals from accumulated experience, completing the lifecycle: goals are declared, revised based on outcomes, aba...
Hortora/grove needs two specific visualisations for its curation analytics dashboard: a similarity heatmap (pairwise entry distances) and a domain composition treemap (rectangles sized by entry count, coloured by heal...
Teaching the Bot to Remember How Games Unfold
When Your Timeout Doesn’t Actually Time Out The agentic planning epic has four phases. Phase 1 landed the execution bridge — blocks patterns running inside the engine’s worker boundary. Phase 2 is about giving those p...
I started this session planning to build eviction — the full machinery. Per-dimension TTL timers, a background sweep, lazy checks on access, two-way state transitions between loaded and evicted. The issue asked for it...
The qhorus trust model had a gap. Attestations — the SOUND/FLAGGED verdicts that feed Bayesian Beta trust scores — were written on the COMMAND entry. The COMMAND entry’s actorId is the requester, the agent who asked f...
The floating workspace landed in casehub-pages today — the last three implementation tasks (runtime integration, examples gallery, event contract), plus two runtime bugs that only surfaced once we drove the actual app...
The AML workbench spec, written six weeks ago, assumed casehub-pages would handle everything — loadSite(), page(), sidebar(), dataset(). Four views, parameterised drill-down, the full component-tree model. It describe...
The Budget That Wasn’t a Number
Five clinical patterns in casehub-clinical have been blocked by the same gap: you can’t select a row in one table and have dependent panels fetch their data based on what was selected. AE table to grade history. Devia...
The session started with a CI fix and ended with a working multi-turn LLM conversation agent. The path between them was more interesting than either destination.
The chat-app workbench has 770 lines of Lit element. About 370 of those are layout: CSS flexbox panels, dock strip buttons, tablet tab switching, phone drawers with swipe gestures, responsive breakpoints. The other 40...
Crash Recovery for Pattern Execution The agentic pattern infrastructure can now survive a JVM crash mid-execution. Before this, if the process died while a DEBATE or SEQUENCE pattern was running, the engine retried fr...
The Life UI scaffolding from the previous session put tabs on every view — Routing, CBR, Channels — each pointing at endpoints that didn’t exist yet. This session built those endpoints and gave the inbox the ability t...
The dominance weight system started with hand-picked rules — specific archetypes matched by enum value, with delta estimates pulled from domain knowledge rather than data. BANSHEE_HARASS got its own rule. BIO_TIMING a...
The landscape analysis I did in July surveyed every multi-agent project worth examining — Smallville, Emergence World, Concordia, the lot. One gap stood out from the rest: no project has agents that form new goals fro...
The desired-state runtime has had ThresholdFaultPolicy since early on — count faults per node, fire an action at a threshold. One tier. The pipeline example needed three tiers (retry → AI review → human review), so Pr...
The Life UI scaffolding from the previous session gave us an app shell, a dashboard, and an inbox — all rendering blocks-ui components but mostly against placeholder data. This session was about making it real: backen...
Blocks had two ways to run multi-agent work, and they didn’t talk to each other.
The branch was called issue-25-commitment-transition-badges but it covered six issues beyond that — a batch of S and XS enhancements for the chat workbench. The kind of work that looks like cleanup in the commit log b...
The engine’s goal decomposition creates a plan at case start — but plans go stale the moment a worker returns with unexpected results. Plan adaptation closes that gap: after each worker completion, the engine evaluate...
Continues from Dock Workbench: Composable Primitives Over Monolithic Controllers.
Worker Data Coordination — From Camel Analysis to Foundation Types The Blackboard has been the only data coordination path for workers since day one. Every worker reads from CaseContext via JQ projection, writes outpu...
A batch job detects a safety signal. It should create a WorkItem for DSMB review. The obvious implementation: detect the signal, persist the record, create the WorkItem, send a Slack notification — all in one transact...
Every AgentProvider implementation in CaseHub had its own concurrency semaphore. Claude’s subprocess manager had one. LangChain4j’s adapter had one. The wacky-manor demo app bolted on another on top. Three independent...
The Plan That Plans Itself
The issue was straightforward: devtown needs sparklines showing how an agent’s trust score evolves over time. The current ActorTrustScore entity is a live value — upserted in place on every recomputation. No history s...
When SOC’s SLA breach policy exhausts all escalation tiers, ExpiryLifecycleService sets the WorkItem to ESCALATED — a terminal status. The engine’s PlanItemCompletionApplier should then transition the backing PlanItem...
The AI resolution agent routes cases based on CBR similarity — high confidence goes to the LLM, medium to an operator with suggestions, low to unassisted. The problem: those stats are computed once, at case start, and...
Continues from Wiring the feedback path.
When Wacky Manor’s autonomous tick loop fires ten character agents simultaneously, the platform’s Claude subprocess semaphore has six permits. Four callers beyond the character agents — narrator, observation summarise...
The trust model for contributors has been accumulating data since the attestation pipeline landed — intake lane classifications, dimension scores, PR outcome history — but none of it was visible outside the API. This ...
The push protocol’s EventStore was designed to be replaced — the CDI @DefaultBean on InMemoryEventStore was an explicit invitation. Issue #113 takes that invitation: PostgreSQL and Redis Streams as drop-in durable bac...
QuarkMind’s coaching mode gives real-time advice to a human player. “Build 3 Stalkers.” “Expand to your natural.” Each piece of advice carries a verification predicate – a structured check that fires after a time wind...
Continues from Closing the loop.
Part of a series on #27 — Agent Control Plane. Previous: When Thirty Terminals Need a Home.
When you extract shared patterns from domain repos into a reusable library, the first instinct is to group by workflow. Attestation observer, intake classifier, vouch service — they all orbit trust. They participate i...
The Conversation Loop
The pipeline learns to ask for pages
The AI resolution agent (#63) shipped without instrumentation. That was deliberate — scope boundaries deferred metrics to a separate issue. But a resolution agent with no visibility into its own behaviour is a liabili...
Part of a series on #114 — LLM sar-drafting narrative adaptation. Previous: Where the sanitiser sits.
RAS has been open-loop since day one. It detects, triggers, forgets. A case gets created, someone investigates, dismisses it as noise — and RAS fires the exact same trigger next time. No suppression, no learning, no c...
I’ve been building a workspace view for Trellis — a floating-frame terminal workbench where each frame holds tabbed terminals pointing at different repos. The use case is a developer managing ~30 repositories across a...
Teaching Agents to Notice Their Own Behaviour
The SAR narrative seeding plumbing (#98) was done. Seeds flow from CBR retrieval through the advisor worker into the sar-drafting worker’s input projection. The workers acknowledge seeds exist — they set narrativeSeed...
Pages loads every row from every REST API into the browser, then slices pages client-side. For a dashboard with 50 rows, nobody notices. For one with 50,000, every page load transfers the entire dataset, parses it, st...
Clinical trials run on a basic assumption: the CTCAE grade assigned to an adverse event at initial report is correct. But clinicians reassess. A Grade 1 fatigue that seemed unremarkable at day two looks very different...
table was renamed to dataTable in @casehubio/pages-ui. A routine rename across four view files — except ide_replace_text_in_file does substring matching, not word matching. sortable became sordataTable in every file i...
Claudony — The Module That Wouldn’t Let Go
Every multi-module system has the same failure mode: you define a thing in one place, register it in another, and nobody enforces the 1:1 correspondence. The gap is invisible until someone asks “why can’t the UI edito...
The AI resolution agent (#63) runs autonomously — polling, claiming, calling the LLM, executing device commands. What it doesn’t do is tell anyone what it’s up to. The queue has entries, but the only way to see them i...
The Eidos personality framework has a disposition encoding pipeline that actually works. Give it Peter Perfect’s ENFJ profile — dominant Fe, auxiliary Ni — and the rendered system prompt reads as an ENFJ. Seven or eig...
Three components in blocks-ui rendered status badges. Each had its own _statusColors record — a private Record<string, string> mapping state names to inline CSS. Each used the same --pages-* CSS custom propertie...
Part of a series on #108 — Explore context-aware chunking. Previous: Chunking the Implementor.
When Your Progress Model Can’t Keep Up
Teaching Workers Who They Are
The visual diagram editor foundation epic is done. We closed #258 and #280 today — all four pages-side phases shipped (graph-core, graph-renderer, graph-work-registry). The remaining diagram editor work lives in block...
“Memory” in LLM agents has become one of those terms that means whatever the vendor needs it to mean. Most of the time, it means a chat log with summarisation bolted on. LangChain’s memory modules, Mem0, ChatGPT’s per...
The Qhorus blockers cleared — both the Channel abstraction (#131) and delivery guarantees (#132) shipped while I wasn’t looking. That makes #97 (WorkItem event mesh) actionable for the first time since the issue was f...
Channel summaries have a scheduler. Every 60 seconds, qhorus sweeps all channels, checks message thresholds, and fires a SummaryUpdateHook. The hook calls into blocks’ ContentSummariser<Message>, which produces ...
I’ve been wanting to write the operational examples for eidos for a while — the features that differentiate it from “just a registry” had no consumer-facing demonstrations. Vocabulary registration and subsumption matc...
The visual diagram editor so far can render a case definition — bindings, workers, milestones, goals — as a directed graph with auto-layout. You can select nodes, zoom, pan, see decorations for runtime state. But ther...
The engine’s HANDOFF had work-repo issues in it. #329, #330, #298, #152, #328 — all from casehubio/work, not casehubio/engine. Branch detection was showing a work-repo branch as the active workspace state. Nothing was...
The pattern classifier has a blind spot. Drools rules fire on known archetypes — a gateway rush looks like a gateway rush because the CEP pattern matches: early gateway, zealot production within a time window, no expa...
casehub-clinical — What the Case Remembers
The work-item-inbox had 30+ fields on its model and showed four of them. Priority was defined but set visible: false. The mock data was richer than the actual UI.
CaseHub Work — The Module That Had to Go
The CaseHub documentation stack had a gap. The consumer guides (#377) explain when and why — contextual documentation owned by each repo, updated in the same session that changes the code. IntelliJ MCP answers cross-r...
Part of a series on #136 — Run minimal briefing experiment. Previous: Is Your Personality Framework Actually Doing Anything?.
Progress has been sitting in the work repo for two days, fully shipped — six new Maven modules, schema validation, rollup strategies, REST and SSE APIs. The issue that tracked it (work#237) was closed as “ideas-captur...
Ten Preferences and a Design Decision
The MCP tools shipped in #69 were deliberately unauthenticated — a placeholder "mcp-agent" string where the caller identity should go, findAll() returning every device regardless of who’s asking. That was fine for pro...
I came into this session wanting to understand what langchain4j’s agentic-ai module actually ships and how it compares to what casehub has. The engine#102 epic — “Enterprise AI Agent Orchestration Patterns” — has 16 c...
The graph packages had a gap between what the model could describe and what the renderer could show. GraphModel handles nodes, edges, containment — the structural skeleton. But runtime state (which binding is executin...
A2A and MCP — Handler, Not Provisioner The langchain4j parity audit flagged two gaps: we couldn’t invoke A2A agents or MCP tools as casehub workers. The obvious implementation path was WorkerProvisioner — it’s the SPI...
An in-process worker is easy. The engine hands it projected data, it returns a result, and it never sees anything else. The sandbox is architectural — inputSchema and outputSchema are the boundaries, and there’s nothi...
Extracted all 9 DraftHouse Lit panels into @casehubio/blocks-ui-document-workbench — a single package in blocks-ui that any CaseHub app can embed. The convergence analysis against existing blocks-ui components (blocks...
The reviewer attestation path already works. An agent completes a review, qhorus resolves the commitment, CommitmentAttestationPolicy writes the verdict. But contributor trust is a different animal. Nobody “reviews” a...
Every reactive system I’ve worked on has the same blind spot. A rule fires, a binding activates, a handler dispatches — and the state that caused it is gone. You can see what happened. You can see who acted. But the q...
A routine dependency update broke a test that had nothing to do with the change. The root cause was a single new field on a Java record three repos away, and the reason it was hard to find is that Java’s type hierarch...
The Fix Was Already There
When the Case Is Already Dead
Git branches share a working tree. That’s fine when you’re switching between features in one repo, but it falls apart when an epic touches multiple repositories and you want to keep working on the main codebase while ...
The retrieval quality epic started with five issues and a clear thesis: code-domain embedding models would outperform general-purpose ones on a Java/Quarkus knowledge corpus, because better tokenization means better e...
The earlier session gave us a viewer. This one gave us an editor.
Part of a series on #265 — Phase 1B graph-renderer. Previous: Three Issues, One Pipeline.
When you give an LLM agent a structured personality — weighted cognitive function scores, disposition axes, type profiles — you also write a briefing. A paragraph of natural language telling the agent how to behave.
HuggingFace Optimum exports the transformer backbone. That’s it. The three things that make BGE-M3 useful — dense CLS pooling, sparse token-to-vocabulary scatter, and ColBERT per-token projection — are custom Python l...
Why Your Agent Forgets What It Just Did
Wacky Manor — When the Narrator Finds Its Voice
The goal abandonment work looked straightforward on paper: track DECLINE signals per goal, threshold, abandon. The APIs are there — eidos ships goals and constraints as first-class fields on AgentDescriptor, and Behav...
The structured personality composition paper ended with a clear finding: the Jungian cognitive function framework delivers personality signal to the prompt reliably — 100% MBTI alignment when briefing and framework ag...
The last session left AML green with a wave plan: four independent S-scale issues, all different subsystems, no shared files. The kind of backlog that begs to be parallelised.
The Workbench Problem
The premise was clean: BERT WordPiece fragments Java identifiers into nonsense — ConcurrentHashMap becomes concurrent ##has ##hma ##p — and that fragmentation degrades embedding retrieval. Hortora/engine#27 demonstrat...
The visual diagram editor needs a graph. Not the rendering — React Flow handles that — but the logical representation between YAML parsing and pixel drawing. @casehubio/graph-core is that middle layer: typed nodes, ty...
The preference schema registry (#195) shipped with infrastructure but no content — register(), resolve(), discover(), and an InMemoryPreferenceSchemaRegistry backed by ConcurrentHashMap, all sitting empty. Issue #197 ...
CaseHub case definitions are YAML. They describe bindings, workers, milestones, goals — the structural vocabulary of a case type. Until today, the only way to understand a case definition was to read the YAML. That ch...
CBR was feature-complete. Retrieve, retain, reuse, narrative seeding — the full pipeline, wired end to end. Cases retained on completion. Similar cases injected at startup. The path advisor analysing experiences and p...
Every case management engine has a moment where identity falls through the cracks. Ours was line 254 of CaseHubReactor.buildInstance() — caseInstanceRepository.save(instance, currentPrincipal.tenancyId()). The tenancy...
There’s a pattern in web frameworks that seems reasonable until you think about it for five minutes: every deployment writes its own request filter to check permissions. Parse the path. Extract the resource ID. Look u...
Open source maintainers have an AI problem, and every solution I’ve seen attacks the wrong end of it.
The First Five Minutes
When Your Agent Remembers Too Much
The original epic (#84) was written when Stage was alive — containment hierarchies, parentStageId pointers, CMMN 5.4.4 alignment. A year later, Stage is retired. Compound replaced it. The epic’s vision of structural m...
Flat plans break on complex goals. Ask an LLM to decompose “investigate a fraud case” into agent assignments and you get a sequence of fifteen steps, half of which are at the wrong level of abstraction. Step 4 says “a...
CaseHub is entirely Lit Web Components. React Flow is the best open-source graph editor. Making them coexist required disabling Shadow DOM on the canvas — which meant finding another way to isolate CSS.
The Gate That Blocked Everything
Most workflow engines treat worker execution as a simple request-response: dispatch a task, get a result, apply it, move on. That model works until you need a worker that stays alive for the duration of a compound or ...
CaseHub’s LLM-invoking components — the routing strategy that selects which agent handles a task, and the decomposition strategy that breaks compound tasks into steps — have always used static, hardcoded prompts. The ...
Every task management system I’ve seen treats progress as a property of the task — a percentComplete integer, a status note, maybe a progress bar that someone updates manually. CaseHub’s WorkItem had exactly this: a f...
A2A Outbound: Your Case Workflows Can Now Invoke Remote AI Agents
Seeing Cases: Building a Visual Editor for Adaptive Case Management
When the advisor stops being a stub
Wacky Manor — When Characters Need to Remember
A Visual Editor for Case Definitions
Most planning systems face the same fork: let the LLM generate the plan (flexible, unsound) or write rigid symbolic rules (sound, brittle). A recent paper from the Pytrich team found a third option — have the LLM gene...
AML’s CI had been red since July 19. Ten consecutive failures, each masking the next. I sat down to fix what looked like a single yarn authentication error and ended up peeling five layers.
The SLA calibration system already knew how long a PR review took end-to-end — median, min, max across historical precedents. What it couldn’t tell you was how long each capability took. Code analysis: three minutes. ...
Claudony started with a simple channel model: the CaseHub engine spins up a case, the case opens channels, agents talk on them. Three channels per case — work, observe, oversight. Clean, purposeful, and completely clo...
The JPAF personality adaptation pipeline had full infrastructure — signal recording, effective weight computation, reflection triggers, decay mechanics. Every component had unit tests. All green. The pipeline did noth...
Most case workers are reactive. A context change satisfies a condition, the binding fires, the worker runs. This is the choreography model — bindings listen for data, and dispatch follows naturally.
Part of a series on #120 — CBR Phase 7. Previous: Multi-Scope CBR: The Wiring Session.
Multi-repo changes break every existing merge tool. GitHub doesn’t support atomic cross-repo PRs. Merge queues operate per-repo. When the third of five repos fails to merge, you have three repos with diverged state an...
Part of a series on #18 — Layer 2: triage workers. Previous: Wiring the RAS pipeline.
Part of a series on #17 — Layer 1: Alert ingestion and case creation pipeline. Previous: Platform audit and vertical slice redesign.
The Test Suite That Found a Bug in Itself
CaseHub Desired State — The Registry That Didn’t Need to Exist
casehub-pages — The Browser Did the Hard Part
RAS Learns to Remember
Most LLM personality systems work the same way. You write a flat list of traits — “competitive”, “bold”, “autonomous” — drop them into the system prompt, and hope the model picks up enough signal to behave differently...
casehub-clinical — Multi-Scope CBR: The Wiring Session
The platform ACL landed back in June — flat grant model, JPA and in-memory backends, parent inheritance, tenant isolation, audit logging. Functionally correct. Operationally incomplete.
When I started blocks’ agentic package a few months back, it was extracted from a single issue on engine — engine#101, “LLM supervisor mode.” That issue described three gaps in CaseHub’s orchestration model: no LLM-ba...
The claudony frontend had a split personality. Half of it was modern TypeScript — Lit components, esbuild, design tokens. The other half was dashboard.js: 800 lines of vanilla JS doing innerHTML string concatenation, ...
Most workflow engines assign human tasks the same way they did twenty years ago: a queue, a round-robin, maybe a role-based filter. The task appears in someone’s inbox. Whether that person is the right person — whethe...
casehub-soc has been dormant since Epic 1 landed the domain vocabulary in late June. A month later, the platform underneath it has changed enough to warrant a full audit before resuming.
The Human in the Channel
Five Root Causes Hiding Behind One Red CI
65% of enterprise AI agent failures are attributed to context drift — the agent loses track of where the conversation is, what’s been decided, and what’s still open. The longer a channel runs, the worse it gets. An ag...
The Property That Does Nothing
CaseHub’s agentic planning framework had the architecture — sealed task nodes, decomposition strategies, routing signals — but the ergonomics lagged. Defining a three-step plan required six-argument constructors with ...
ThresholdFaultPolicy had a ConcurrentHashMap<NodeId, Integer>. Three bugs hiding in plain sight: counts vanished on restart, leaked when nodes were removed, and — the one that surprised me — ignored tenancyId en...
Part of a series on #797 — HumanTask CBR routing. Previous: Teaching the Engine Who Should Handle This.
The two-track detection architecture from the previous session gave us the rails. This session filled them in.
Part of a series on #107 — Jungian personality framework. Previous: Wiring the Disposition Layer.
Part of a series on #60 — Unified execution model. Previous: Why your case needs decomposition.
Part of a series on #107 — Jungian personality framework. Previous: Personality from Cognitive Functions, Not Labels.
Part of a series on #60 — unified execution model. Previous: Delete the Duplicate, Promote the SPI.
The Maven SNAPSHOT work from last session (#246) solved cross-repo dependency distribution. But it surfaced a gap: consumer repos with static HTML pages — login forms, register pages, admin screens — still couldn’t us...
Three iterations to Maven
The Format That Makes LLMs Act
Six months ago I rejected MBTI as a vocabulary source for eidos. The rejection was sound: ~50% of people receive a different type when retested a month later. Any vocabulary built on that instability is unreliable. I ...
The table that needed to grow up
Part of a series on #60 — unified execution model. Previous: Two Primitives, One Graph.
The previous entry proved the characters could talk. This one proves they can act — navigate rooms, pick up objects, trigger plot beats, and produce an actual scene where the Ant Hill Mob accidentally saves Penelope f...
What started as a mechanical rename — propagating text-input → input and dropdown → select across example YAML files — turned into something more useful when I actually opened the examples gallery to verify the change...
The previous session landed descriptor templates — reusable prose fragments for agent system prompts. This session went broader: four issues in one branch, touching the API surface, JPA layer, renderer, and Flyway sch...
The unified execution model spec sat for eleven days after its adversarial review. Thirty-five issues raised, twenty-three verified, ten accepted. The spec was solid. The implementation plan existed. What was missing ...
Three SPIs and a Calendar
The CBR pipeline already stores SAR narratives from past cases. It already retrieves them at case startup. The gap was the last metre: getting those narratives to the sar-drafting worker so it can use them as template...
The question was simple: can you give an LLM a personality descriptor and have it produce output that sounds like a specific Hanna-Barbera cartoon character? Not “responds in the style of” — actually sounds like them....
The engine dropped all its Reactive* SPI interfaces. No deprecation period — the blocking variants exist, the reactive ones are gone. Claudony still implemented three of them, plus a compat shim that used reflection t...
A tenant isolation audit across the platform repo surfaced four gaps — three SPI-level and one endpoint-level.
The strategy detection system started with ten archetypes — all early game, all hand-authored Drools rules. Zergling rush, marine rush, cannon rush, gateway pressure. The kind of thing you can recognise from a three-m...
The IoT repo already has the full device stack — typed entities, providers for HA and OpenHAB, a registry that caches everything in memory, command dispatch. What it didn’t have was a way for LLM agents to reach any o...
The unified execution model spec has been sitting consolidated for two weeks. 94KB across 13 parts — the result of merging the reviewed design spec with two research docs and the execution backend architecture. The de...
The Composable API That Wasn’t
CaseHub Blocks UI — Namespace Hygiene and the Barrel That Bites
CaseHub Blocks UI — The Pipeline Was Already There
The summarisation framework has been growing for weeks — layered event compression, keyed accumulators, channel summary hooks, conversation folds with common ground and convergence detection. Each piece is independent...
The ACL subsystem was the last holdout from the reactive tier retirement (#384). While 13 repos and 30,000+ lines of reactive code were removed in the main sweep, acl-jpa slipped through — still on Hibernate Reactive ...
The Briefing Duplication Problem
I went into #319 expecting a significant migration — the engine’s virtual-thread-migration.md cookbook describes deleting reactive SPIs, rewriting JPA repositories from Panache Reactive to EntityManager, converting ha...
Part of a series on #60 — OpenClaw skill integration.
Three handler tests had been failing since the blocks API refactoring landed. The error messages were clear enough — systemPrompt() didn’t contain the expected text — but the real question was whether the tests were w...
When the Review Writes the Spec
Part of a series on #384 — retire reactive tiers. Previous: Thirteen Repos, One Branch Name.
RAS was wearing a reactive costume. Every one of its 226 Uni references fell into exactly two categories: Uni.createFrom().item(synchronousResult) on the provider side, .await().indefinitely() on the consumer side. Ze...
Part of a series on #384 — retire reactive tiers. Previous: The Reactive Layer That Was Already Dead.
The old pages-ui-tokens system generated themes at runtime from four numbers: base hue, accent hue, chroma, contrast. Call generateThemeCSS(config) in the browser, get 72 colour tokens. Simple. But it couldn’t express...
The glue that was always missing
CI was red. The error said NoClassDefFoundError: io/micrometer/core/instrument/MeterRegistry — a class nothing in the spatial module directly referenced. Every test in the module failed, not just the ones touching RAS...
Platform had two reactive SPIs — ReactiveNotificationStore and ReactiveSubscriptionStore — each with three implementations: NoOp @DefaultBean, InMemory @Alternative, and JPA native. Plus a ReactiveAgentIdentityVerific...
DraftHouse already had the brainstorming backend — MCP tools, session model, terminal endpoint. What it didn’t have was anything to look at. You’d run a brainstorm in the terminal and the options existed only as JSON ...
When the obvious architecture is wrong
The investigation triage worker was a stub — every case got SAR_WARRANTED regardless of what the specialist findings said. That was fine for wiring the engine layers together, but it meant the investigation-cleared go...
Ganglion-level evidence templates landed last session — extract fields from every CloudEvent regardless of which rule matched or which outcome won. The obvious next question: what about evidence that depends on the de...
The version coordination tax
Schema-Driven Notification Forms
Schema-Driven Notification Forms
Every CaseHub app that uses trust-weighted routing ends up building the same composed view. The trust score panel shows per-capability scores. A routing history list shows who got assigned and why. A feedback feed sho...
The CBR feedback loop had a gap. CbrOutcomeConsumer existed — it could convert a CbrOutcomeData record into a CbrOutcome and call recordOutcome() — but nothing delivered events to it. The consumer was wired to nothing.
Filling in the Blanks
Multi-agent conversations accumulate assertions but nothing tracks what’s established vs what’s still contested. The conversation projection folds messages into structured state — points, threads, statuses — but the f...
The platform notification system and the connector library evolved independently. Notifications had NotificationDeliverer and a registry — but only in-app inbox was wired up. Connectors had Connector.send() with five ...
DraftHouse can replay completed design-review workspaces — load the workspace, parse all the response files, replay them as debate entries in the channel feed. That works. But a design review takes 10–30 minutes acros...
Filling the Gaps
casehub-clinical — Trajectory: The Shape of Escalation
Part of a series on #230 — Coach mode. Previous: When the Coach Needs a Playbook.
The frontend that didn’t need npm publish
The commit that fell between the cracks
Household Hub — from accountability engine to something people actually use
Two paths for one job
The per-row CSS Grid model in pages-table was always a compromise. Each .row div was its own display: grid, which meant column spanning worked — a cell could stretch across columns within a single row’s grid. But row ...
Why Every Data Table Gets Spanning Wrong
casehub-clinical — When the System Remembers What Worked
Part of a series on #230 — Coach mode. Previous: Teaching the bot to read the room.
The two missing layers
Short session — two bug fixes and some housekeeping.
The retrieval tracking SPI landed a few weeks ago — raw event recording: which documents came back for which query, optional graduated feedback on whether they helped. Useful data, but useless without interpretation. ...
The subject view toolkit shipped yesterday. Today was about what it still needed before casehub-work could actually use it.
The approval workflow from yesterday’s session left a trail of known debt — small items, each S-scale, none individually worth a branch. I batched four of them onto one branch and worked through them sequentially.
Design-review runs in rounds. The reviewer raises issues — sometimes nine or more — and the implementor addresses all of them in one batch response. Each turn takes 5-10 minutes. The human sees nothing until the full ...
Continues from The Test That Found Two Bugs Before It Passed.
Epic #12’s acceptance criterion is a single sentence: “A 2-repo change set merges atomically, and a failure in one repo triggers automatic rollback of the other.” Five issues built the machinery. The sixth — the integ...
Part of a series on #158 — coordinated-rollback worker. Previous: When sub-cases aren’t sub-cases.
Issue #175 asked for a generic queue toolkit. AbstractQueueEntity, AbstractQueueService, QueueSubject — the container model. Items enqueued by name, escalated by moving to a different queue. Straightforward JPA @Mappe...
Schema-form was sitting in blocks-ui-core. It rendered JSON Schema as editable forms — text inputs, dropdowns, checkboxes, dates, nested objects. Useful component. Wrong repo.
Claudony — The Extraction Gap
The last piece of the work-adapter module landed today: WorkItemPendingApprovalHandler, a stateless bridge between the desired-state reconciliation loop and casehub-work’s WorkItem system. A provisioner returns Pendin...
The OpenClawAgentRegistry had a silent data-corruption bug hiding behind a “works for now” 1:1 constraint. The registry maps agents to cases for channel routing — when a Qhorus COMMAND arrives, the backend needs to kn...
I’d been treating the approval workflow as a feature to build. It turned out to be a feature to delete.
RAS situation definitions started declarative-only: you define event types, chain modes, trigger actions, and correlation windows in YAML. Anything beyond static configuration — extracting a correlation key from event...
Two separate problems landed on the same branch: how to let modules receive specific CloudEvent types without the full DataSource machinery, and how to make MvelExpressionEngine work with POJOs instead of just Maps. T...
The CBR system had three case types: TextualCbrCase for text-only matching, FeatureVectorCbrCase for structured feature matching, and PlanCbrCase for plan resolution with trace data. Every consumer used PlanCbrCase. T...
Cross-repo coordinated merge sounds like sub-case orchestration. The engine has sub-cases. The YAML has subCase: bindings with groupId and M-of-N semantics. The merge queue already uses them for bisection — two sub-ca...
The branch covered four issues: #125 (CSV field names), #126 (GDPR erasure dialog), #127 (demo mode fixes), and #123 (work queue inbox). I expected a session of small UI fixes. What I found was that three of the four ...
The emoji picker in channel-reaction-bar overflows the viewport on narrow screens. The component positions it with position: absolute; bottom: 100%; left: 0 — always above, always left-anchored. On a 375px phone scree...
The Obligation Model Was Already There
Part of a series on #5 — async WorkerFunction. Previous: Removing the type bottleneck.
The requiresHuman flag on a DesiredNode was always described as a routing signal — “consult the HumanNodeHandler for this node’s lifecycle.” But it only routed half the lifecycle. Provision checked it. Deprovision did...
The column renderers in similarity-panel and compliance-summary weren’t broken. The HTML was rendering. The elements existed. The tests passed. Everything about the code was correct — property binding, Map lookup, Cel...
Part of a series on #102 — standalone showcase page. Previous: The screen that lies.
Platform has a full notification system — per-user lifecycle (UNREAD → READ → DISMISSED), subscription matching, quiet hours, digest batching, multi-channel delivery. Qhorus has membership with cursor-based unread tra...
Last session closed #188 — PagesGroupedView composing per-group <pages-table> elements instead of reimplementing table rendering via innerHTML. Four follow-on issues fell out of that work: column renderers in li...
Delivery tracking tells you whether a notification reached the channel. It says nothing about whether anyone read it. That gap — between “delivered” and “engaged” — is what #170 closes.
The demo UI started as five hand-rolled Lit components with hardcoded CSS values and its own token system (--blocks-*). It worked, but it was carrying 380 lines of layout, channel rendering, and modal management that ...
casehub-clinical — Closing the CBR Audit Loop
CaseHub Life — Trust Scores Meet CBR Adaptation
Claudony needed two extension points on channel-activity — a way to customise message body rendering, and a compact channel selector for narrow panels. Both turned out to be straightforward implementations with one ge...
Phase 1 of CBR (#116) wired the basics — three CDI event writers, feature schemas, precedent endpoints. It worked. AE escalation completes, CDI event fires, AeResolutionCbrWriter stores a FeatureVectorCbrCase. Clinici...
Part of the CBR series on casehub-life. Previous: The Last Mile Was the Whole Point.
The Feature That Was Already Half-Built
Two pieces of work that look unrelated but share a theme: devtown had scattered patterns where centralised ones now exist.
The Method That Touched Twelve Files
Supersede, Score, Split
The pipeline had a method called refreshDataSet. It didn’t refresh anything.
Small Issues, Structural Gaps
NaiveBayesGanglion had a gap that became obvious once I looked at it through the persistence lens: it holds running log-posteriors in a ConcurrentHashMap that evaporates on restart. For windowed situations this barely...
CBR has four phases — Retain, Retrieve, Reuse, Revise — and until now neocortex implemented three of them. Cases were stored, retrieved with similarity scoring, and their outcomes fed back via EMA confidence. But the ...
Part of a series on #56 — CBR engine integration. Previous: CBR: The Foundation Was Already There.
CaseHub’s decomposition infrastructure already has both halves — StaticDecomposition for guard-based method selection, LlmDecomposition for when the LLM needs to reason about which agents to deploy. What it didn’t hav...
The Grouped Window Nobody Had
The summary that was already there
The CBR infrastructure work (#49) left a capable engine sitting idle. The case base could store resolved situations. The similarity scorer could compare them. The feature schemas could describe what matters. But nothi...
Removing the Type Bottleneck
The examples in casehub-pages had been lying for a while. Forty-three TypeScript files importing from @casehubio/ui and @casehubio/data — packages that don’t exist. They were never compiled, never type-checked, and th...
The design-review skill has a structural problem I’ve been aware of since #95 shipped the workspace replay adapter: two independent regex parsers — one Python, one Java — extract the same structure from the same markd...
Issue #31 proposed putting ganglion internal state on a case blackboard — Drools CEP sessions, Bayesian posteriors, anything a stateful ganglion accumulates over time. The original RAS spec had this as an optional pat...
Batched three chat-demo UI features onto a single branch: progressive disclosure on messages (#63), an emoji reaction palette (#64), and swipe-to-reveal gestures for phone drawers (#55). All Phase 2/3 from the qhorus ...
I’d been expecting this one to be a slog. Modals have a reputation — focus traps, scroll locking, backdrop click detection, screen reader announcements, z-index wars. Every framework has a modal component and none of ...
The channel-activity component started as a two-line stub. The real implementation lived in two other places — claudony had a hand-rolled channel panel with SSE, polling, and cursor management, and connectors had a fu...
The Shim That Wasn’t Dead
The Drift You Don’t See
The pages-table component migrated from blocks-ui months ago with most of the original spec implemented — virtual scroll, pagination, sorting, selection, keyboard navigation. Three items from blocks-ui#22 never made t...
Part of a series on #76 — CBR Revise step. Previous: When the Graph Remembers.
Batched three issues onto one branch — telemetry JSON escaping, CommitmentContext enrichment for V1/V4 evidential checks, and topic-aware channel digest. The kind of session where each item is small enough to be borin...
The audit-trail-viewer’s row click was broken. Clicking a row set _expandedEntryId and called _renderExpandedDetail, but the detail panels rendered after the entire <pages-table> element — not between rows where...
I set out to fix four small issues on the engine — the kind of cleanup batch where you expect to be done in an hour. Two constructor mismatches from upstream SNAPSHOT changes, one checkstyle violation, and a TODO that...
Every CBR case in neocortex has carried a origin field since #140 landed the Revise SPI. recordOutcome updates it via EMA. Retrieval ignores it completely.
The branch that nobody owned
Sealing the cracks in goal composition
The backlog had four issues tagged XS or S. I batched them onto one branch to clear them in a session.
casehub-life had eight layers of infrastructure — SLA enforcement, commitment tracking, tamper-evident audit, case plan orchestration, trust routing, risk classification, CBR retention — all writing data. WorkItems ac...
The Type That Replaced Object
The Naming Convention That Wasn’t Scaling
Part of a series on #44 — agentic planning architecture. Previous: Closing the Description Thread.
Showing the Work in Similarity
The previous session landed topics, reactions, rich artefact refs, and channel membership. This session picked up the trailing work — five deferred issues batched onto a single branch. The interesting part wasn’t the ...
The ops console’s drift detection had a 5-minute blind spot. The ReconciliationLoop polls on a configurable resync interval — good enough for convergence, but if someone runs kubectl delete on a managed deployment, yo...
I’ve been thinking about what happens when desired-state reconciliation hits a wall. A node keeps failing to provision. The fault policy fires, proposes a retry, the retry fails, the policy fires again. Eventually the...
CaseHub Pages — The Gallery That Wouldn’t Render
Teaching the Bot to Read the Room
Five small issues had been sitting in the backlog since the structured fields (#89) and sequence similarity (#92) work landed. Each was a gap noticed during implementation and deferred — not because it was hard, but b...
Part of a series on #49 — TypedDataSet native. Previous: Fetch Is Just Push.
CBR cases in neocortex have been point-in-time snapshots since day one — flat features like race, MMR, and game phase. The structured fields work (#89) added nested objects and lists for richer case anatomy, but those...
CaseHub has three coordination models: blackboard (engine), workflow (engine-flow), and agentic patterns (blocks). They all answer the same question — how do I coordinate work across multiple agents? — but they evolve...
The table had its own type system because the pipeline didn’t give it one.
The DataSource system was add-only. You could register a DataSource, subscribe to it, push events through the alpha network — but you couldn’t remove one. No CDI event for removal, no cleanup in the router, and regist...
The Type That Leaked
Case model foundation and drift remediation
Zulip has had an open issue since 2014 about creating a topic table in the database. Twelve years. Their original design stored topics as strings directly on the message table — simple for reads, painful for renames. ...
Moved pages-data-table and four a11y mixins from blocks-ui back to pages where they belong. The layering violation was clear: generic UI primitives living in a domain-component repo. A table that renders rows and colu...
The trust-score-panel had a placeholder where the trend line should be. The issue was straightforward — replace it with an SVG sparkline fed by the pages-data pipeline. What made it interesting was the architectural q...
CaseHub Neocortex — When Flat Features Aren’t Enough
Where the Gap Was
CaseHub RAS — The Store That Learned to Fail
The garden entry that started this was blunt: devtown’s trust routing is degenerate CBR — Retain and Reuse, but no Retrieve and no Revise. Trust scores flatten per-case variation. A reviewer with 0.72 overall might be...
I started #44 thinking the migration was mechanical — swap one mixin for another, keep the same fetchData pattern, done. The issue even said “one-line mixin swap per component.” I’d read the DataSourceController code,...
Seven of eight implementation tasks for the ContextBridge protocol landed today. The protocol was fully designed and adversarially reviewed yesterday — today was pure execution. The pipeline now carries typed context ...
I went into the CBR epic expecting to build a similarity engine, a retrieval pipeline, and a retention mechanism. Three substantial pieces of infrastructure. The issue descriptions assumed the foundation didn’t have a...
Part of a series on #124 — Consolidate RrfFusion with generic CbrFusion. Previous: Three Implementations of the Same Algorithm.
Three Implementations of the Same Algorithm
The pages team delivered casehub-pages#145 — the DataSource pipeline unification — and asked blocks-ui to confirm three design questions before they close it out. I spent the session reviewing both the spec and the im...
The Score That Lied
The desired-state runtime started with an implicit assumption: one domain per deployment. A single ActualStateAdapter, a single EventSource, a single NodeProvisioner. That was fine for teaching examples and single-pur...
I counted nine distinct abstractions in casehub-pages for getting data to a component. DataSource, DataSink, DataReceiver, VizTarget, DataEndpointMixin, SSEManager, EventStream, EventStreamPool, the DataPipeline itsel...
CaseHub passes data through five different boundary types — worker input, work items, sub-case context, signals, connectors. Every one of them uses Map<String, Object>. Every one of them has the same class of bu...
SC2Data had a quiet bug. Three cost methods — mineralCost, gasCost, supplyCost — used switch expressions with default clauses. When the UnitType enum grew from 6 types to 67, most new entries silently got the default....
The Workbench Problem
The summarisation framework in quarkmind was built with its destination address on the box. Every class sat in io.casehub.blocks.summarisation — the package name told you where it was going before anyone filed the ext...
The approval-gate component had a quiet blind spot. It sent a PUT to complete a gate decision, checked response.ok, and threw the response body away. The gate.decided event carried only what the client already knew — ...
The reranking issue asked for the decorator to live in rag/ alongside HybridCaseRetriever. That felt wrong before I could articulate why — a gut reaction to the dependency graph. rag/ depends on inference-api and infe...
The in-memory digest buffer worked fine until I started thinking about what happens when the process restarts mid-digest. Notifications buffered for an hourly email digest just vanish. For most deployments that’s acce...
Every design-review workspace already has a version history. Each implementor round produces a git commit, and the tracker records **Spec commit:** → abc123 per issue. The timeline was sitting in the data — it just wa...
Part of a series on #18 — propagate bindingName through worker completion path. Previous: K8s Restart Recovery.
A platform convention isn’t real until the second project adopts it. The first adopter shaped it; the second one proves it generalises.
Part of a series on #125 — event-mode push API.
The original design was straightforward — attach a LocalSimilarityFunction to each FeatureField and let the scorer call it. LocalSimilarityFunction is a @FunctionalInterface, already used for per-field overrides via t...
CaseHub — Trust Closes the Loop
Claudony had two custom classes for cross-node channel delivery in fleet deployments: FleetMessageRelayObserver (HTTP tick fan-out on every message dispatch) and ChannelFleetBroadcaster (HTTP channel sync on creation)...
The host-panel activation code had a line I’d walked past dozens of times:
The compliance module had six EvidenceCollector implementations. Five of them did the same thing: check whether a file exists and is recent. The only difference was the controlType() method returning a different strin...
Part of a series on the data-table build. Previous: The Platform Table.
Part of a series on #147 — notification system. Previous: Digest and Batching.
PLATFORM.md was 685 lines. That’s not huge by document standards, but it’s the wrong shape for how LLM sessions actually consume it.
Wired casehub-neocortex’s CBR store into clinical today. The goal was straightforward — store resolution precedents so future AE/deviation/amendment decisions can reference what happened before — but the design choice...
Arc’s @Decorator support has a gap nobody warns you about. If the bean being decorated was created by a @Produces method, the decorator registers at build time, passes every diagnostic check, and then silently does no...
The notification pipeline has been delivering every matched event immediately to every channel since it shipped. That’s fine for in-app — real-time is the point. But for email? A user subscribed to “all comments on my...
Every CaseHub app needs tables. Until today, every CaseHub app that needed a table would have had to build its own — or use the one baked into pages-viz, which is coupled to the pages-runtime data pipeline and has no ...
I filed a bug that was already fixed. That’s the short version.
A routine question — “other repos say governance is missing” — turned into a full audit of the casehub-parent BOM against every child repo in the build chain. Governance was fine. The BOM was not.
The pages codebase has been accumulating conventions — token naming, event contracts, component strategy — but none of them lived anywhere a fresh session could find them. They were implicit in the code. This session ...
When desired state learns to finish
The queue board redesign left blocks-ui with a solid inbox and detail panel, but no shared primitives for the things every CaseHub app actually needs: deadline indicators, metric dashboards, and approval gates. Four i...
The issue said “only when profiling demonstrates the O(n) scan is a bottleneck.” I nearly deferred it on those grounds — current scale is under 100 patterns. But the more I looked at TopicRegistry, the more the trie f...
Three Bugs Where There Was One
Part of a series on #7 — DroolsSessionStore: persistent implementation for restart survival.
The SNAPSHOT That Wasn’t There
Supply count was always a placeholder. It tells you who has more stuff on the field, but nothing about whether that stuff is any good. A player with thirty zerglings and no tech is behind a player with four immortals ...
casehub-pages — SSE Crosses the Repo Line
Added JSON Schema validation to the worker executor — but with an asymmetry that took some design thought: input validation rejects (returning a Failed result before the function ever runs), while output validation on...
The Document That Nobody Read
The iframe component API had been sitting in the “if patterns emerge” queue since we wrote the first batch of casehub-pages protocols last session. I’d assumed there was something to formalise around the React renderi...
When I started the subscription system a few days ago, I left a design flaw in place knowingly. The userId field on a subscription was both the person who created it and the person who received notifications. For pers...
The LLM routing strategy could reason about agent descriptors. The CBR strategy could tally historical success rates. Neither could do both. The obvious fix — a new "rag" strategy combining them — would have started a...
The Silence of the Wrong Superclass
blocks-ui-core accumulated a set of primitives that had nothing to do with blocks-ui’s domain — a11y mixins, an event bus, a schema-driven form renderer, an SSE manager. They ended up there because pages didn’t have t...
I asked a simple question after the last session’s work: are we still aligned with the rest of CaseHub? The answer was no — in two directions. The npm packages had been bumped to 0.3.0, ahead of casehub-parent’s 0.2-S...
Part of a series on #652 — add semantic labels/tags to CaseDefinition Java API. Previous: Two Canonicals, One Convention.
Subscription Management: From CloudEvents to POJOs
Nine Issues, One Branch, and a Chicken-and-Egg Problem
The batch that closed six issues taught me something I should have seen earlier: neocortex’s CBR retrieval was architecturally wrong.
The compliance record consolidation from blocks #17 had been sitting as a trailing obligation for weeks — “shared types exist but aml and devtown haven’t migrated.” Except the shared types didn’t exist. CLAUDE.md said...
Part of a series on #172 — CloudEvent WorkItem Bridge. Previous: Six Issues, One Branch.
Two Canonicals, One Convention
Part of a series on #91 — AML workbench UI. Previous: From Nine Layers to a Screen.
AgentCapability had a name and it had routing signals — qualityHint, latencyHintP50Ms, costHint, epistemicDomains. What it didn’t have was a way to say what the capability actually does. The name code-review tells you...
The notification store is the first new store SPI in platform-api since CaseMemoryStore moved to neocortex. It’s the terminal sink in the notification pipeline — the routing layer evaluates subscriptions against incom...
Part of a series. Previous: Duplication Points Upward.
Explore Mode Gap Closure + CBR Roadmap
pages had a flat 13-token theme system — hardcoded hex values for --pages-accent, --pages-bg, --pages-text and a few friends. Good enough for prototyping, wrong for a foundation tier that other packages inherit from. ...
The CBR dual-store architecture has a blind spot I hadn’t noticed until reconciliation forced the question. QdrantCbrCaseMemoryStore delegates durable storage to CaseMemoryStore — JPA or SQLite — and maintains a Qdran...
Part of a series on #88 and #85. Previous: Killing the polling loop.
Killing the Polling Loop
The last session landed the universal routing strategy convention (#634) — NamedStrategy, StrategyResolver, five SPIs retrofitted. That work left a trail of follow-on issues: evaluation happening in the wrong place, n...
The previous session’s final code review flagged five minor findings. Three of them — a missing generation counter in PagesMetric, an unhandled Promise rejection in PagesChartElement, and a cache hash collision from a...
Delegation and escalation were the compliance dimensions I’d been avoiding.
Channel.builder("name").build() returns null for allowedWriters(). Every consumer that iterates the list without a null check gets an NPE. The fix sounds trivial — default to List.of() — but the design question undern...
What does it look like when a StarCraft bot learns from its own history? Not just trust scores nudging strategy selection — actual case-based reasoning across games, where the bot remembers how a game played out, what...
One Convention, Not Seven
From Drools Alpha Networks to CaseHub DataSources
I wanted to clear the small-issue backlog — four S-scale fixes that had been sitting open since the data module landed. Each one independent, each one well-understood, none individually worth a branch of its own. So I...
The workbench shipped last session — casehub-pages, Quinoa, the whole lot. Clean swap, 366 tests green. I opened the browser expecting to see something. Empty panels.
Part of a series on #52 — feat(chat-demo): user identity / login. Previous: Making the Demo Talk Back.
The sixth worker module — workers-k8s — shipped two days ago. A K8s Job can run for hours. The in-memory completion registry doesn’t survive a process restart. That’s a qualitatively different problem from HTTP worker...
Three layers of the eidos stack computed match information — which capability matched, how well it matched — and then threw it away. CapabilityResolver.resolve() iterated each declared capability, computed an OWLS-MX ...
Part of a series on #21 — Optional Quarkus backend MVP. Previous: Completing the Data Module.
Where the graph runs out
The CBR store has been embedding problem() text at write time since it was built. Every case goes in with a dense vector alongside its payload filters. But retrieval never used it — scrollAsync with payload filters, s...
The backlog had one item in it. That’s not because there’s one thing to do — it’s because nobody had looked at what was open. Ten issues in GitHub, and the handover said “pick up #152.”
The per-dimension compliance threshold from yesterday’s behavioral contracts work had a known blind spot: an agent with 2 violations in each of 10 dimensions — 20 total, all individually below the threshold of 3 — loo...
The Qhorus normative layer has had a clear speech act taxonomy for months — nine types, seven commitment states, a sealed CommitmentStore. casehub-work has had a complete WorkItem lifecycle for nearly as long — twelve...
Part of a series on #85 — Behavioral contracts and runtime validation. Previous: The Tag That Didn’t Match.
What belongs in a shared library — and what doesn’t
The Tag That Didn’t Match
The Remote That Pointed Somewhere Else
I sat down to explore #24 — the state-vector abstraction for QuarkMind. The issue described a new DesiredStateVector data type for continuous/spatial state that didn’t fit the graph model. Reasonable enough on the sur...
casehub-pages has been 100% TypeScript since the migration from GWT. Every feature — data pipeline, layout, navigation, rendering — runs in the browser with no server dependency. That constraint was always intentional...
casehub-pages — The Dedup Semantics Question
The backend shipped last session with auth and layout persistence, but the data module was a placeholder — just a package-info.java. The original #21 issue described a SQL data provider with push-down operations, and ...
Seven issues, all small, all on one branch. The kind of session where the value isn’t in any single change but in the cumulative surface area they open for downstream consumers.
The engine port landed. QuarkMind now runs on casehub-engine — signalAndAwaitSync per tick, TickOrchestratorWorker chaining plugins via WorkerFunction, the poc dependency gone. That was the prerequisite. The point was...
Discord embeds, Slack Block Kit, Teams Adaptive Cards, Google Chat Cards V2 — four platforms, four incompatible JSON schemas for saying “here’s a title, some fields, and an image.” The question for connectors was whet...
Watch-Based Completion — The Sixth Worker
The Great Memory Migration
The question behind #279 was whether WorkItemGroupLifecycleEvent should integrate into the WorkItemEvent hierarchy — share a common base, implement the interface, or remain standalone. It was filed during the #278 API...
casehub-pages has had resizable splits since the workbench primitives landed. You could drag a split handle and resize panels. But the resize was a DOM-only mutation — flex: 0 0 200px applied directly to the element, ...
The desiredstate runtime has two approval mechanisms: requiresHuman (compile-time — the node structurally cannot be automated) and PendingApproval (runtime — the provisioner evaluates risk and decides). These are orth...
Closing the Result Model
The agentic orchestration framework had five SPIs, two drivers, and eight pattern builders — but the data flowing between them was thin. RoutingContext.task was the literal string "task". RoutingDecision.Selected carr...
I started this branch thinking issue #13 was about making provisioners return PendingApproval. The issue body described a “HumanNodeProvisioner” that returns PendingApproval with a plan artifact, gets called back afte...
The hybrid orchestration epic shipped last session. What it left behind were three follow-up issues — not defects exactly, more like threads that were cut short when the scope boundary was drawn.
The Rename That Touched Everything
The issue said “Scale: S — convention + config + migrate existing grid.” Two days later there are twelve commits on the branch, three upstream SNAPSHOT adaptations, an adversarial design review, and the build is block...
What I was trying to achieve: a reusable terminal for the platform
The vocabulary system we built for eidos had a deliberate constraint: specializes() could only reference terms within the same vocabulary. An application couldn’t say “my clinical-documentation-review is a kind of doc...
Part of a series on #44 — IoT webapp — operational console with situational awareness. Previous: XS Test: The Design Review That Found a Real Bug.
Four signing adapters, four cloud KMS providers. AWS was correct from the start. GCP and Azure weren’t — and the surface symptoms (eight items in the issue) all traced to one architectural mistake.
Every DesiredNode carries a NodeType — the API javadoc even calls it “classifies a node by its provisioning domain.” The runtime ignores it completely. SimpleTransitionExecutor takes a single NodeProvisioner. DesiredS...
Part of a series on #75 — Adopt casehub-pages for UI composition via Quinoa. Previous: The Half-Extracted Fold.
Three features on one branch again. Discord needed two fixes — message history wasn’t downloading attachments, and the inbound translator was silently dropping them. The MCP tool needed the rest of the embed surface e...
Discord attachments, embeds, and MCP tools — three issues, one branch. The attachment work is where the interesting decisions live.
One Model, Three Signals
casehub-pages started as a dashboard renderer — YAML in, charts out. DraftHouse, Claudony, and DevTown each needed more: a workspace shell with panels, docking, and inter-panel communication. Each hand-coded its own s...
The Roots, Not the Leaves
I started this session thinking I was adding a similarity search API. I finished it questioning whether the repo should be renamed.
Sometimes the most useful thing you can do with a filed issue is close it.
Recovery Belongs to the Engine, Not the Scheduler
I started this session planning to add a template method to YamlCaseHub — a straightforward refactoring to eliminate duplicated double-checked locks across eight consumer subclasses. The kind of thing you file as “S /...
The guided walkthrough pages for casehub-clinical looked complete — shipped under #105 with all 8 steps and 6 explore pages. Issue #98 asked for specific things: a target-vs-actual enrollment bar chart, an endorsement...
Three Legs and a Flat Namespace
The issue was straightforward: add a ScimDIDResolver that constructs synthetic DID documents from SCIM certificate data, so enterprises don’t need to host DID documents externally. SCIM already has the certificates. J...
The demo UI had a problem hiding in plain sight. Four pages — PI authorisation, SUSAR gate approval, Merkle verification, and the audit trail — all embedded JavaScript inside html() template literals. Browsers don’t e...
The Module That Wasn’t a Module
The ledger has always supported bilateral signing — an agent signs each entry it creates, and the signature is verified on read. Until now, that meant the private key lived on disk, loaded from PEM files at startup by...
CTE has been broken since day one. Not in an obvious way — tests pass, the case starts, the result comes back. But inside the case, nothing happens. The workflow steps call desiredstate:dispatch and there’s no handler...
casehub-pages had an identity crisis baked into every document it owned.
The data pipeline had a gap I hadn’t seen until three issues forced me to look at it together. #70 (error propagation), #71 (subscription lifecycle), and #74 (SSE source) all pointed at the same root: WebSocket was ha...
I started this branch expecting mechanical fixes — stale names, misused UUIDs, unconditional log statements. The kind of work that fills a morning and leaves the commit history slightly tidier. What I found instead wa...
I wanted to know what it would feel like to operate the AML system we’d built. Nine layers of investigation infrastructure — specialist dispatch, trust routing, Merkle-chained audit, oversight gates, case memory — and...
The qualifier that ate the test suite
The last session shipped the WebSocket event model — DataSetEvent, the unified apply() method, connection pooling, the whole reactive data pipeline. Five issues came out of that review. All five touched the same narro...
Seven CaseHub classes in casehub-life shared the same structural boilerplate: a volatile field, a double-checked lock in getDefinition(), an identical cap() helper, identical CDI injections, and 32 worker methods that...
A Governance Surface for CaseHub
P5 moved the conversation protocol to casehub-blocks — the state model, the renderer, the abstract projection. Any CaseHub app could now fold channel messages into ConversationState and render the result. Except they ...
Part of a series on #80 — Extract P4 channel agent dispatch SPI to casehub-blocks. Previous: The First Blocks.
The blocks repo has been sitting empty since its scaffold landed earlier this week. Today we put actual code in it — the first three utility patterns extracted from DraftHouse.
We came back to connectors to check whether Pages finishing its WebSocket support (#52, #53) unlocked anything here. It did — connectors #27, the chat-demo WebSocket endpoint, had been explicitly blocked on those two ...
Discord, and What the SPI Survived
CaseHub IoT — The XS Test That Needed a Design Review
Two issues that looked independent turned out to share a root: data models that quietly misrepresent what they know.
The tempting wrong answer
The Missing Abstraction Between Engine and Ledger
casehub-pages — The Event Model That Three Issues Needed
casehub-pages has been a static dashboard runtime since its GWT-to-TypeScript migration. YAML defines datasets, components render, filters cross-propagate — but everything is fixed at parse time. The URL in a dataset ...
Three issues closed on one branch — #69 (worker imports, already done), #68 (CI rename), and #71 (gate rejection outcome). The first two were housekeeping. The third is where the design work happened.
The Semaphore That Was Already There
The Review That Reversed the Design
The Profile That Didn’t
CaseHub Pages — The Last Rename
Until now, QuarkMind’s intelligence layer lived entirely at Level 1: Drools CEP fires on raw tick data, producing posture classifications and timing alerts. The strategy plugin reads those signals and decides DEFEND, ...
The mesh prompt gap turned out to be embarrassingly simple. MeshSystemPromptTemplate generates a per-case prompt — channels, prior workers, participation mode — and ClaudonyReactiveWorkerContextProvider stores it in W...
I came into this branch with a clear problem: two JVMs processing events for the same situation both evaluate to CREATE_CASE, both fire caseTrigger.fire(), and you get a duplicate case. The #18 work had already put OC...
The merge queue shipped last session with a design gap I knew was there: batch records deleted on completion. ActiveBatchEntity was ephemeral — once a batch merged or bisected, the record disappeared. The adaptive bat...
The composite WorkerExecutionManager (#461) solved CDI ambiguity when co-deploying multiple worker backends. But it left a question hanging: what happens when Quartz — the catch-all fallback — catches a capability it ...
CaseHub Life — The Memory Gap in GDPR Erasure
The Hortora engine benchmark proved what I suspected — nomic-embed-text treats @DefaultBean and ConcurrentHashMap as generic English tokens. Dense vector search returns WireMock entries when you search for CDI annotat...
Eidos — Backlog Zero
Adaptive Ops — Teaching Agent Topology to Respond to Reality
Part of a series on #36 — ARC42STORIES.MD update and #35 — BridgeAuditStore SPI.
Part of a series on #11 — runtime enhancements. Previous: The deferrals that took an afternoon.
Desired State — The SPI That Was Missing
casehub-clinical — The Demo That Reviews Itself
CDI 4.x has two completely disjoint event delivery channels. fire() reaches @Observes observers. fireAsync() reaches @ObservesAsync observers. Neither delivers to the other, and there’s no warning when an observer exi...
What I was trying to achieve: giving the Agent API eyes
Documentation Debt Has a Half-Life
Three issues landed on one branch: plugin endpoint auth (#42), a CDI cleanup (#48), and a documentation update (#47). The CDI cleanup was mechanical — OidcCurrentPrincipal @Alternative @Priority(100) shipped in platfo...
CaseHub Ops — The Abstraction That Hid a Bug
The issue for #31 described a tiered search pipeline: store both full-precision and truncated+binary-quantized vectors per point, use the compact one for fast first-pass retrieval, rescore against the full-precision o...
The last session closed two branches and left a clean backlog. This one picked up the two S-scale issues — #44 (domain dashboard polish) and #35 (map chart geo data) — and ran them on a single branch.
The examples gallery had its categories in alphabetical order. “ansible” and “Basic Usage” appeared before Sales, Clinical, IoT — the dashboards that actually show what the runtime can do. A visitor’s first impression...
The sar-drafting workers had been calling openReview() unconditionally — creating a compliance officer WorkItem before any MLRO gate could fire. The design for #58 was always clear: split the side effect out, gate the...
When now() Is the Bug
The question that started it
Another Claude session had reviewed our Lifecycle Coherence Protocol — the normative doc that registers every lifecycle state machine across CaseHub. It came back with a rewritten version of the state machine table. E...
The Data That Disappeared
Three charts in Workforce Analytics rendered empty — donut, stacked bar, and scatter all showed axes and labels but no data. The canvas elements were there, ECharts was initialised, and the existing Playwright tests p...
The Hortora engine’s garden corpus hit ~6,500 entries. When CorpusIngestionService bootstraps from an empty cursor, it passes every chunk to QdrantEmbeddingIngestor.ingest() in a single call. Three unbounded operation...
The ChatPlatform SPI shipped last session as an abstraction. This session gave it its first real implementation — and the implementation pushed back on the design in several places.
CaseHub IoT — Three Walls Between Config and Runtime
I started issue #60 planning to build casehub-eidos-desiredstate — an optional bridge module that would displace the ops drift checker via CDI @Alternative @Priority(1). The existing AgentDriftChecker compares sorted ...
Part of a series on #3 — JavaSwitchGanglion. Previous: The Deferrals That Took an Afternoon.
The DirectCallBridge from the previous session had a known gap: no eviction for orphaned CompletableFutures. If a webhook never arrives and the subscriber doesn’t cancel, the map entry leaks. The fix is CompletableFut...
The Trampoline That Changed the Design
This branch closed three issues on a single pass — a tenancy exception mapper (#89), a listener transaction fix (#87), and a GDPR patient-scoped erasure endpoint (#79). The mapper and the listener fix were straightfor...
Gastown’s Refinery is production software. v1.0.1, battle-tested, doing exactly what it was built to do. It batches PRs, tests the tip of the batch, bisects on failure, rejects the culprit, merges the rest. The algori...
casehub-pages — Four Domains, One Gallery
The deployment module started as four node types: agents, channels, case types, trust policies. I’d always known this was incomplete — a deployment that can declare who does the work but not what infrastructure it con...
When I originally designed qhorus’s MessageType enum, I modelled it on FIPA ACL — the IEEE standard for agent communication that grew out of speech act theory. FIPA defines 22 communicative acts. Qhorus has 9. I’d nev...
The rag-hyde module had the wrong name from the start. It was always a generic query expansion decorator — it called QueryExpander.expand() and delegated. It didn’t know or care about HyDE. But HyDE was the first stra...
Duck Typing for Chat Platforms
Desired State — Clearing the Backlog
Part of a series on #116 — CredentialResolver bridge to Quarkus CredentialsProvider. Previous: The Quarkus CredentialsProvider Shaped Everything.
casehub-pages had a coherent architecture for cross-filter state — centralized in the runtime, URL-serialized, restored on reload. But sort and pagination were the opposite: private fields scattered across component i...
casehub-pages — Three Leftovers from View State
The trust feedback loop in devtown was supposed to be the big epic. Two repos, new platform primitives in qhorus, upstream-first architecture. Three review rounds later, the scope collapsed to something embarrassing: ...
The Switch Statement Was the Problem
CaseHub RAS — The Runtime That Found Its Own Clock
Desired State — The One-Line Fix That Wasn’t
Three issues sat in the casehub-ras backlog since Epic 2 closed: a YAML provider for situation definitions (#13), ANTI signal handling in the trigger policy (#15), and compact() invocation for persistent situations (#...
The Quarkus CredentialsProvider Shaped Everything
Part of a series on #4 — Epic 3: IoT desired state domain. Previous: ARC42STORIES.MD migration.
DraftHouse — The Single Entry Point That Wasn’t
The native image gate passed weeks ago. C2 proved both JNI layers — ONNX Runtime and HuggingFace Tokenizers — work in Quarkus native image on macOS ARM. Reachability metadata shipped in inference-quarkus. The gate was...
The Overload That Kept Growing
Seven Fixes and a Schema Decision
The casehub-filter event has been working since day one of the TypeScript migration. Selectors emit it, the runtime listens, filtered data flows to listening components. The flow works. The contract underneath it was ...
Part of a series on #62 — Multi-LLM reviewers with personality library. Previous: Four Layers of CI Rot.
I’d been staring at CaseRetriever.retrieve(String query, ...) for weeks without seeing the problem. The String query parameter was doing three separate things: providing text for dense embedding, providing text for sp...
The Dependency That Wasn’t
engine#530 and engine#531 both shipped while I was away. ProvisionContext now carries tenancyId as a first-class field, and the engine no longer hard-gates on getCapabilities() before calling provision().
Zone 2 showed the 1B model sending RESPONSE on every COMMAND — technically completing the commitment while using query-fulfillment vocabulary. Zone 3 caught the type mismatch. But there was a gap one layer deeper.
Four small things that make the platform real
Part of a series on #26 — Platform convention: Quarkus + TypeScript frontend via Quinoa. Previous: arc42-issue-remap.
The plan was simple: fix a broken import (PlannedAction moved packages), close a test-polish ticket, and be done. Neither issue was hard. I had a branch in under ten minutes.
The branch started as routine maintenance. Four docs issues, all small — update some type names, remove a stale deferred note, update the neural-text section, register a new repo in the build dashboards. Nothing that ...
Part of a series on #89 — GitHub REST API combined-status check. Previous: The Security Layers That Don’t Talk.
The spec for clinical#88 — wiring casehub-platform-oidc and @RolesAllowed across nineteen endpoints — went through four review rounds. The implementation went through zero rework. That ratio is the point.
ARC42STORIES.MD is done. It took most of a session — reading docs, reading blog posts, reading git history, then writing 1,120 lines in one pass. It lives in the project repo now. The workspace had a stub, which was w...
CaseHub RAS — The Collection Strategy That Started With the Wrong Ordering
casehub-work fires lifecycle events on every WorkItem transition — created, assigned, completed, rejected, the full twelve-status lifecycle plus operational events like spawned and claim-expired. Twenty-four distinct ...
The theory going in was simple: small models cheat on impossible tasks. Give them a document UUID that doesn’t exist and ask for a summary — they’ll fabricate one. The normative layer should change that. Zone 1 would ...
DraftHouse needs four reviewer agents — structural, content, readability, completeness — each with a distinct personality grounded in Thomas-Kilmann conflict modes and Conscientiousness disposition axes. The issue ask...
casehub-life got its auth wiring three days ago (life#40). Now it was openclaw’s turn. The task looked the same — add casehub-platform-oidc, configure OIDC, annotate REST resources. But openclaw is a different kind of...
Part of a series on #66 — migrate SAR drafting workers to FuncWorkflowBuilder. Previous: Cache gaps and workflow context.
CaseHub Worker — First Blood
There’s a GE rule that says always use .exceptionally() when calling fireAsync() for CloudEvent dispatch. It’s right. Except in Kafka and AMQP stream processors, where following it would silently eat your messages.
casehub-ops had four domain modules, four design specs, five blog entries, and no architecture documentation. The specs describe each domain in isolation. The blog entries capture session narratives. Neither answers t...
Remapped all issue references in ARC42STORIES.MD §9 from the previous tracker to the current casehubio/casehub-pages GitHub issues.
devtown ran without any authentication for its first six layers. MockCurrentPrincipal @DefaultBean returned empty groups, every endpoint was open, and the comment in application.properties said “devtown#71” — no auth ...
The FDA says seven days. For Grade 4 and 5 unexpected adverse events, that’s the window from AE report to IND expedited safety report filing. Grade 3 gets fifteen. RegulatorySubmissionCaseService had been computing th...
Platform#104 was started on 19 June, code-reviewed, fixed, and then orphaned — the branch never made it to main before the session ended. Wrapped it today.
The #270 review surfaced two follow-up issues. #271 was a pre-existing bug: JpaWorkItemStore.countByParentAndAssignee() hardcoded a terminal status exclusion list — COMPLETED, REJECTED, CANCELLED, ESCALATED — four of ...
CaseHub Pages — Smoke Tests and the ESLint Zero
CurrentPrincipal.groups() has always returned an empty set in casehub-life. Every harness is in the same state — casehub-platform-oidc exists and is production-ready, but nobody had actually wired it yet. That changes...
Seven Issues, Three Specs, and the Engine’s Actual Dispatch Chain
The investigation status endpoint had a subtle defect. Both Layer 6 and Layer 9 used CaseInstanceCache.get(caseId) to determine whether a case had completed. This was introduced deliberately — the previous approach sc...
The task was straightforward: add a CloudEvent adapter to casehub-connectors so casehub-ras can observe inbound messages without coupling to connector types. IoT and Qhorus had already shipped theirs. I just needed to...
Cleared the entire S/XS backlog in one branch, then built the navigation distinct rendering feature on the same branch. Twenty-eight commits total.
Part of a series on #2 — TypeScript project references. Previous: ts-strict-enforcement.
TypeScript Strict Enforcement
MongoWorkItemDocument has been shipping since Chapter C20 with a silent data loss bug: 13 of the 44 WorkItem fields weren’t mapped in from() or toDomain(). Put a WorkItem through the MongoDB store, get it back, and ca...
ARC42STORIES.MD had fallen six weeks behind the code.
Part of a series on #4 — DroolsGanglion. Previous: The API That Didn’t Wrap Anything.
The webhook receiver for devtown started with a deceptively simple question: should GitHub PR events go through casehub-connectors?
DraftHouse — Four Layers of CI Rot
The spec for reactive CRAG looked straightforward: mirror the blocking CorrectiveCaseRetriever as a @Decorator on ReactiveCaseRetriever, swap fire() for fireAsync(), wrap the evaluator call in runSubscriptionOn(). Two...
CI went red again on the first push to main.
The RAS design spec was written on June 12. Two days later, the parent repo’s layering decisions landed — and they made a quiet but significant choice: io.cloudevents.CloudEvent is the platform’s typed CDI event envel...
Seven issues, all flagged S or XS, all on one branch. The kind of session that should be mechanical. It wasn’t.
The plan for #31 was straightforward enough: move OversightGateService out of casehub-openclaw and into casehub-engine-api where it belongs, classified as a Known Placement Violation in PLATFORM.md. I assumed it would...
Part of a series on #24 — Move to casehubio org.
This was an infrastructure session. CaseHub Workers had no CI, 14 repos were pushing to personal forks, and the parent build scripts didn’t know half the ecosystem existed.
I came into this session planning to design managed pipeline execution. Within an hour we’d uncovered something more fundamental: Worker doesn’t belong in the engine.
The probe was working backwards. Eidos could tell casehub-engine whether an agent was ready, degraded, overloaded, or epistemically weak in a domain. What it couldn’t say was: this agent has declined Rust security rev...
The @QuarkusTest suite for casehub-life is fully green. 286 tests run, 0 fail, 0 skip — including all eight integration test classes that were blocked while engine#536 and engine#537 were open.
CI had been failing since June 12. Every push — Build and Test red, before reaching a single test. The project itself was fine; the CI failure had just been queued behind feature work for a week.
The Accessor That Was Lying
CaseHub Neural-Text — Fifteen Branches and Nine Missing Posts
CaseHub Neural-Text — The Guard That Isn’t a Guard
The workers repo had a structural placeholder for EndpointRegistry since the HTTP module was first built — a comment in HttpEndpointResolver.initialize() that said “when EndpointRegistry ships, add a tier here.” Platf...
CaseHub IoT — The Mock Server That Doesn’t Mock
The failure cascade shipped in the previous session but had no connection to Qhorus. An agent declining via a DECLINE speech act on a channel wrote a generic channelMessage signal — the same as a DONE or RESPONSE. The...
OutcomePolicy declared onExpired from the start. The YAML schema parsed it, the mapper wired it, the default constructor set it to REROUTE. But nothing in the engine ever used it. A worker that timed out hit TimeoutEx...
The health job’s gap-detection query had been wrong for a while. Not subtly wrong — wrong in a way that Hibernate 6 explicitly refuses to execute. The HAVING clause did arithmetic on MIN() and MAX() aggregates, and on...
The Slack channel backend is shipped. #261 is done. But getting there involved two decisions about timing that weren’t in the spec.
For three months the platform has been able to produce things — ledger entries, memory stores, WorkItems, channel messages, agent sessions. It couldn’t receive anything from outside. That changes today.
Part of a series on #34. Previous: Runtime Improvements.
Epic 10 started from a simple spec: demonstrate the full compliance story across three independent sites, and publish a comparison table showing what ClinicalAgent doesn’t do. I expected the implementation to be mostl...
The issue said pluggable execution backends for pipeline stages. Camel for integration routes, Drools for business rules, Stream for lambda chains. The NodeProvisioner SPI already supports it — just make the per-type ...
The issue title left nothing ambiguous: “ON CONFLICT DO NOTHING masks concurrent data race instead of fixing it.” The analysis was thorough — traced the commit history back to the change, named the specific pattern, p...
WorkItemStatus started life with ten states. Enough to model a human task inbox — claim, start, complete, reject, cancel, the usual suspects. It handled delegation, suspension, expiry, and escalation. It was functiona...
The failure cascade landed in the previous session — WorkerOutcome sealed type, OutcomePolicy, structured _outcomes state, agent exclusion. Four follow-up issues remained open. All four turned out to be straightforwar...
The eval harness runs sixteen enrichment calls in parallel. Each one invokes the Claude CLI, and each one has a seven-minute timeout. When all sixteen hit that limit simultaneously — which they do, because they are pa...
The runtime code review (#13) left a backlog of four findings. Three were surgical fixes; one — lazy page activation — turned out to have more depth than it looked.
Three issues on one branch — #70, #90, #99. The sequencing was forced: #90 (moving ReactiveCaseMemoryStore to platform-api) had to land before #99 could add methods to it. You can’t add a method to an interface that’s...
The book-appointment-agent now calls an actual LLM. That’s the headline.
The branch closes four issues — three small doc fixes and one that needed thinking.
The compliance module started from a question that kept surfacing during the deployment work: what would continuous compliance look like if you treated regulatory controls the same way you treat infrastructure — as a ...
Part of a series on #21 — docs: create ARC42STORIES.MD.
Part of a series on #5 — C5: Bridge Runtime. Previous: Two Providers, One SPI.
Part of a series on #37 — batch S items. Previous: Enforcing What Was Already True.
Four issues landed today on a single branch, and the most interesting thing about three of them is what I didn’t know going in.
The branch was closed. CI was sitting at the expected baseline — six pre-existing MeshResourceInterjectionTest failures from a Qhorus SNAPSHOT bug, one known ResearcherCaseCompletionTest failure. That was the state I ...
The A2A SSE endpoint had what looked like three separate problems: no keepalive (proxies drop idle connections), orphaned consumers (disconnected clients leaving their entries in the registry forever), and no maximum ...
When I filed #267 during the MongoDB completion work, the shape of the bug was already clear: CrossTenantProducer hardcodes three JPA concrete types. The cross-tenant path — cleanup jobs, timer recovery — was silently...
Melviz — Lazy Rendering and the Gallery at 90%
Prompt caching was always the point. quarkus-langchain4j-anthropic doesn’t support cache_control breakpoints — langchain4j#1591 has been open for a while — so repeated calls with the same large system prompt pay full ...
The eval passed. Then it failed.
Three issues today — XS, S, S — and I expected them to be quick. Grade 4 was. The other two had interesting surprises underneath.
The Grade 5 IND expedited reporting path has been live for a week — unexpected fatal adverse events now start a regulatory submission case within 24 hours of being reported. Grade 3 was the next step: unexpected sever...
The spec for this took seven review passes before anyone was happy with it. I’m not complaining — the reviewers were right every time, and working through the @Blocking deadlock, the SESSION__KEY double-underscore, an...
Part of a series on #2 — data pipeline example. Previous: The Pipeline That Broke the Runtime.
The deployment module from last session registered things — agents in eidos, channels in qhorus, case definitions in the engine. Declarative topology with reconciliation. But it stopped at the registration boundary: “...
KeyRotationRepository had the same structural gap as the identity binding repository from the previous session: findByActorId returned results from any tenant. The fix looked identical too — add tenancyId, update the ...
Part of a series on #11 — docs: create ARC42STORIES.MD. Previous: The Fifth Worker and the Extraction It Forced.
Writing four chapter entries for an architecture document turned out to be mostly a verification problem.
The Fifth Worker and the Extraction It Forced
The previous session closed three issues and left two open. Issue #144: JpaActorIdentityBindingRepository.save() never called frontierRepo.replace(). Issue #145: latestBindingFor and bindingHistoryFor had no tenancyId...
Layer 6 — trust routing — has been sitting at “implementation complete” for a couple of sessions with the GitHub issue still open and the ARC42STORIES.MD §9.4 entry half-written. Today I closed it. But before signing ...
The plan coming in was to do three issues in sequence — #266, #271, #261. The first one dissolved before we started: #266 tracked a MessageReceivedEvent consumer migration that turned out to already be complete. All t...
The Type Dispatch That Didn’t Belong
Three fixes landed on this branch. One of them turned out to be about cryptographic correctness, not health monitoring.
What brought us here was a closed issue — engine#231 finally threading triggerChannelId and triggerCorrelationId through to ProvisionContext. The provision path in Claudony has carried a TODO for weeks: when a Qhorus ...
The issue said infrastructure provisioning. Kubernetes namespaces, deployments, services, ingress. Six node types, a dependency chain, a crash-loop fault policy. Standard validation exercise — prove the SPIs are domai...
Six foundation layers shipped. The closed feedback loop — trust scores updating from agent behaviour, driving future routing without human intervention — is live. And the docs still described it as aspirational.
CI was red — not from a push, but from a repository_dispatch. A casehub-qhorus SNAPSHOT had published and triggered a rebuild on casehubio/life. Twenty-seven identical errors: “Ambiguous dependencies for type CurrentP...
The multi-turn agent API has been sitting in the backlog since the single-shot AgentProvider.invoke() shipped in June. Platform#58 was the explicit “finish this later” — the spec said multi-turn was deferred because n...
I started Layer 7 confident I understood the trust routing architecture. I was wrong in ways that four rounds of spec review had to correct before we wrote a line of implementation code.
Filtering Out the Enum
I started the deployment module expecting to mirror the infra module’s design. Three-layer architecture, typed specs, backend abstraction, dependency graph — the infra PoC established the pattern, and the deployment d...
Chapter 6 of the Game Agent Coordination journey is closed. L7 wasn’t a new capability — it was the question I’d been putting off since the first layer: what does the harness actually cost, and does it close what L1 c...
The trailing edges, trailed
Trailing Edges
Fourteen open doc sync issues. One pass. The size of the batch is itself a signal — platform development across a dozen repos had outrun the documentation. The previous session closed five; this one closed fourteen. T...
Three questions, three repos unblocked.
The Wrong Hypothesis and the JSON Document That Ate Every Binding
The last entry added AgentKey(agentId, tenancyId) to ChannelContextWindowService to prevent same-agentId cross-tenant collision. Sound reasoning at the time. Except OpenClawAgentRegistry — the other map that tracks ag...
The Layer 9 feature — the oversight gate that intercepts consequential agent actions and routes them to human review — shipped on June 10. CI wouldn’t pass. Not because the code was wrong. Because three different SNAP...
The poc dependency had been on borrowed time for months. casehub-core:1.0.0-SNAPSHOT — the retired proof-of-concept — was still running every game tick, dispatching plugins via createAndSolve() and returning a CaseFil...
Extracting @casehub/component — The Zero-Dep Split
Showing the Work
Worker Lifecycle — From Ad-Hoc CDI to a Real SPI
Filed issue #5 against the infra PoC as five code review findings. By the time I got to them — one session later — three were already implemented.
Today was supposed to be a calibration day. Run the eval, read the proximity scores, set PROXIMITY_FLOOR, move on. Instead we spent most of it figuring out why the eval wouldn’t run at all.
The foundation constraint is simple: casehub-qhorus and casehub-work are peer Foundation modules. Neither can depend on the other. But consumer apps often need both — a message arrives on a qhorus channel and should b...
I’ve been circling the infrastructure domain in casehub-ops for a while — it’s listed fourth in priority, behind deployment, compliance, and IoT. But it’s also the most universally understood domain. Everyone knows Te...
Two issues closed today that were deferred from the endpoint registry session. EndpointPermissions (#89) was the simpler one — a static utility class mirroring MemoryPermissions exactly, stripped of the async overload...
Layer 7’s workers don’t exist yet. Before I write them, I wanted to know the tests could be written — that there’s a pattern that actually works for spinning up OpenClaw in a container, handing it a mock LLM, and veri...
The point of the session was to build the generic desired-state runtime — the graph model, planner, reconciliation loop, fault policies. Foundation tier. Domain-agnostic. SPIs for everything. What I didn’t expect was ...
Four Reviews and a Fake Class
C2 shipped Java fixture factories — Fixtures.hallwaySwitch(), Fixtures.standardHome(), ten device factory methods covering every DeviceClass. YAML loading was deferred to #8 as additive work. The decision was right ab...
The batch PR from earlier today shipped a composition refactor on CaseLedgerEntryRepository — breaking it free from JpaLedgerEntryRepository so tests could substitute an in-memory double without hitting native SQL tab...
The previous entry ended with “the clean path” — a dedicated SUSAR oversight case hub that doesn’t touch the ae-escalation case. This is the entry where we built it.
The trust feedback loop in devtown has always had a gap: an agent reviews a PR, the PR merges, and then two weeks later a production incident reveals the agent missed something obvious. The agent’s trust score never h...
The Enum That Was Always a Path
When the issue backlog accumulates fifteen XS/S items, the temptation is to knock them out one by one across separate branches. I tried the opposite — one branch, all fifteen, sequential execution.
Ten issues closed in one batch. Most were mechanical — annotation fixes, null guards, one docs update, one method addition. But three of them kept throwing surprises, and one of those surprises turned into a fairly su...
The first thing ctx.py returned was OWNER_REPO=**. Not casehubio/parent — two asterisks.
ExternalDataSetDef and the Shape Problem
The issue going in felt clear: qualityHint, latencyHintP50Ms, epistemicDomains, and costHint were appearing in PROSE and MARKDOWN renders as raw numbers and “strong expertise” labels. None of that information is usefu...
Fifty-Six Files and a Hash Bug
The Storage Layer That Wasn’t There
The OpenHAB provider shipped in C4 with token auth only — Authorization: Bearer <token> hardcoded in the REST client interfaces. Basic auth is the alternative for OpenHAB installs running behind username/passwor...
CaseHub Workers — MCP: Any Protocol Server as a Worker
The question going in: is QuarkMind actually using CaseHub, or just wearing it as a label? We’d built six layers — connection, physics, the plugin pipeline, scouting, economics, and trust-weighted strategy routing — b...
Nine S/XS fixes in a single batch branch. Most were mechanical. Two were not.
The casehub platform has four foundation primitives now. Preferences let modules read scoped configuration. Identity lets code know who’s acting. Memory gives agents a store that survives cases. And as of today: a nam...
DataSetManager and the Thin Orchestration Layer
L6 trust routing shipped two weeks ago. The machinery was correct — Bayesian Beta model, four-phase maturity, designated fallback tiebreaker. The problem was that GameOutcomeRecorder always wrote AttestationVerdict.SO...
Claudony — When the Ledger Enforces Its Own Rules
Every symptom pointed at Quartz. Twelve tests timing out — cases start, workers never fire, ConditionTimeoutException after ten seconds of nothing. The contaminating class was CaseFaultedStateTest, which runs six case...
The issue spec said to post an EVENT. That was the starting point, and it was wrong in two directions simultaneously.
The guard that found its home
Layer 8 was supposed to be the straightforward one.
The Qhorus multi-tenancy work landed (#260) and openclaw had zero tenancy awareness. Not a single tenancyId reference anywhere in the source. That’s not unusual at this stage of integration work, but it meant a full p...
The adapter’s erase() has thrown MemoryCapabilityException since the day it was written. Graphiti’s REST server offers one deletion primitive: DELETE /group/{group_id}, which cascades everything for a group — episodes...
Expression Evaluation and the Parse-Resolve-Execute Lifecycle
I went into this thinking push was the right architecture. A ChannelBackend observer catches every debate message, emits it to an in-process event bus, and the SSE endpoint subscribes. Clean separation. Claudony has e...
The Home Assistant provider went in first. HA’s model is flat — one entity ID, one device, state arrives as old/new pairs over WebSocket. The mapper is a pure function: HA state DTO in, DeviceEntity out. Everything in...
The third worker module shipped: workers-github-actions. Two GitHub APIs — workflow_dispatch and repository_dispatch — exposed as CaseHub capability tags. A case step can now trigger any GitHub Actions workflow as par...
Four issues. Two were already done — one we’d fixed in the previous session and never closed the ticket, one adapted to a SNAPSHOT change without noticing the issue still existed on the board. Closed both without writ...
The ledger that proved nothing happened
The eval harness has been sitting in the repo since eidos#16. This session was supposed to be simple: run it, read the numbers, set the floor constants. It took two days and uncovered three separate bugs before a sing...
Grouping, Aggregation, and the Null Question
The quality batch came first — five issues, one branch, sequential. Most of it was mechanical: rename a misleading field here, fix a JSON escaping bug there, drop a throws declaration that was actively lying to caller...
SlackBotClient.listChannels() used to return the first 200 channels and log a WARNING when next_cursor was non-empty. Now it follows cursor pagination until exhausted. The loop itself is four lines; the design decisio...
When Your Bridge Is the Problem It Solves
The Database That Wasn’t There Yesterday
Layer 9 adds the oversight gate — the mechanism that intercepts a worker’s PlannedAction and decides whether to proceed autonomously or hold for human review. Five action types in AML, three policies: always gate, gat...
The platform had five open correctness issues — none of them features, all of them things that worked but worked wrong. No external users means no reason to tread carefully. I fixed each in the intended way, which mea...
The CaseContext in casehub-engine has been, since the beginning, a flat Map<String, Object>. Workers write their output into it, the engine writes its signals — actionGateRejected, workItemEscalated, whatever — ...
V116 added tenant_id to all six domain entities in casehub-clinical. Writes were correct from the start — resources stamp principal.tenancyId() on creation. Reads were completely unscoped. Any caller who guessed a UUI...
The eval harness has been sitting in the repo since eidos#16 — designed, built, never run. The five judges exist, the real-world profiles exist, the pair contrast infrastructure exists. What’s been missing is: first, ...
Melviz Gets a Type System for Filters
The interesting design question for restart_from_round wasn’t the channel branching — that’s just creating a new Qhorus APPEND channel and posting a provenance marker. It was whether the tool needed a mode parameter t...
The 200-channel cap in conversations.list has been there since we shipped listChannels(). An operator with a large workspace would get a partial channel list with no indication anything was missing — the response sile...
The previous entry shipped SlackBotClient — a clean HTTP client for the Slack Web API. This one wires it into the MCP surface so an LLM agent can actually use it.
Where the Protocol Said One Thing and the Codebase Said Another
The RAG Pipeline That Dropped Its Framework
CommitmentLifecycleScenarioTest was flagged in the handover as a pre-existing isolation failure — passes in the full suite, fails alone. The obvious read: Surefire retries the failing method without running the setup ...
The handover said eight test classes were failing because ledger_subject_sequence was missing from the H2 schema. That was plausible — the table is created by a casehub-ledger Flyway migration that only runs in produc...
The last entry ended with ClinicalTestLedgerRepository in place — a bridge class written because casehub-ledger-memory’s InMemoryLedgerEntryRepository was still on the old one-arg interface while production code had m...
The plan was tidy. Move sequence allocation out of LedgerWriteService.record() — where it was a racy SELECT-then-persist — and into save(), where it would use the same MERGE SQL that casehub-ledger’s LedgerSequenceAll...
The Flag That Wasn’t a Gate
The A2A card has always been thin. Name, agentId, version, capabilities — enough to know what an agent can do, nothing about what kind of thing it is. An orchestrator querying for a Belbin Monitor Evaluator had to pul...
The task for today’s second session was supposed to be straightforward — implement reactive SPI variants for the OpenClaw provisioner and channel provider. S-scale, a few hours, done.
I came into this session expecting the HTTP worker to be straightforward — simpler than the Camel worker, reusing workers-common for the heavy lifting, done in a day. The Camel worker had already established the patte...
Chapter 2 was supposed to be the easy one. Chapter 1 built the type system and SPI contracts; Chapter 2 just needed a mock provider, some fixtures, and a CDI helper to fire events. The design review had other ideas.
The design for multi-tenancy looked straightforward: JPA stores inject CurrentPrincipal, read tenancyId(), add AND tenancyId = ? to every query. Every read returns only what belongs to the caller’s tenant. Writes stam...
There is a gap between what the compliance evidence endpoint promises and what it actually delivers. Issue #44 closed that gap. Two related issues came with it.
Engine had already solved this problem. When we added tenancyId to casehub-engine a week ago, the first instinct was elegant: inject CurrentPrincipal, read tenancyId() in each repository, filter silently. The callers ...
The CaseHub ledger’s Merkle chain had always been described as “tamper-evident.” Layer 4’s job was to wire it into devtown for merge decisions — a domain-specific LedgerEntry subclass capturing whether a PR was approv...
CaseDefinitionYamlMapper had five call sites that all said the same wrong thing:
Before I could write a single line of code for life#27, I needed to find what I was actually fixing. The issue title said “one-class-per-rule for LifeActionRiskClassifier” — a narrow refactor of the risk classifier. P...
The original plan for the real SC2 connection was to use ocraft-s2client-bot — the only Java library that speaks the SC2 Remote API. It did the job for a while: ocraft handles the WebSocket handshake, manages the game...
The gate entry point has been dead code since openclaw#28. When we removed the speech act classification layer, we also removed the code path that decided whether an agent action needed human review. The casehub_done ...
CaseMemoryStore integration requires one thing before the first write can happen: a tenantId. No tenantId, no tenant isolation, no point writing facts that can’t be scoped to the right trial operator. So the two issue...
AgentDescriptor has had disposition axes for a while — five open strings for how an agent operates. The Belbin and DISC vocabularies landed last week. What it didn’t have was any way to tell the renderer that a descri...
I’d been putting off multi-tenancy. Not because it was hard to understand — add a column, filter by it — but because “add a column” in a system with 20+ stores across three persistence backends means touching everythi...
casehub-work had zero tenant scoping. Every WorkItem, every template, every audit entry — visible to every tenant. The platform foundation was ready (CurrentPrincipal.tenancyId() has existed since casehub-engine’s mul...
After delivering the Graphiti memory adapter last session, I had a short list of follow-up items to resolve — none of them new features, all of them correctness questions the adapter had left open.
Three issues that had been deferred from the debate channel session: orphaned Qhorus instances (#33), the [QUALIFY] prefix hack (#38), and the META: sentinel collision (#39). On paper, small and sequential. In practic...
The goal coming in was to add the write path: MCP tools for two LLM agents to post structured debate entries into a Qhorus channel, and a projection to fold those entries back into ReviewState. The previous session ha...
CaseHub Neural Text — The Qualifier That Couldn’t Share Its Name
CaseHub Neural Text — The Layer That Gives Floats Meaning
Four small issues in a single batch branch. Three were exactly what they looked like. One had a finding inside.
The spec came out of a parent session
Claudony — Running the Signal Chain Live
Protocol PP-20260518-case-definition-layers has a simple mandate: every YAML case definition needs a companion fluent Java DSL class that produces the same canonical CaseDefinition. Clinical has three YAML definitions...
Issue #28 was filed as a narrow fix: inject the speech act protocol text into the COMMAND message via OpenClawChannelBackend.post() instead of loading it through the always-active casehub-global skill. A few lines of ...
Three issues this session — vocabulary registry gaps, a Builder migration, and three factual errors in personality-frameworks.md. Small, all overdue.
The Property That Wouldn’t Move
Three bugs came in together from the quarkmind Layer 3 integration: EVENT messages silently dropping their payload, dot-notation channel names throwing a confusing error, and custom-qualified MessageObserver beans nev...
After PR #443 merged — dynamic candidateGroups/Users for humanTask — the question turned to what’s next. I’d been wanting to do Drools integration for a while. Engine has issue #5 (DroolsExpressionEvaluator) and issue...
The batch started with six open issues and the optimistic assumption that most were small. Three turned out to need no code at all — the work they described had already been done by earlier sessions. The remaining thr...
The idea for this one started as an impedance mismatch problem. I wanted to add Graphiti as a Tier 3 memory backend — temporal knowledge graphs, bi-temporal fact validity, the kind of thing that can answer “what did t...
The connectors side of the Slack ChannelBackend lands today — not the backend itself (that lives in qhorus), but the three pieces it depends on.
The starting point was clear on paper: DraftHouse still had a local file-based debate pipeline wired up beside the Qhorus channel system. SummaryProjector, DebateParser, ReviewSessionService — none of them reachable f...
CaseHub Neural Text — The SPI That Argued Back
Until now a humanTask binding in a case definition had fixed routing. You’d write:
Sweeping the small issues backlog — eight entries, ranging from a compile error to a new feature — is the kind of work that’s easy to defer. Nothing urgent, nothing architectural. But deferred small issues accumulate ...
Trust scores in casehub-ledger are a materialized view. The nightly batch job computes Bayesian Beta scores from attestation history, writes them to actor_trust_score, and fires CDI events so consumers can refresh the...
The question I couldn’t answer going into this: how does a Claude Code session tell the case engine it’s done?
Spent most of this session clearing a backlog of doc sync issues — twelve across PLATFORM.md, casehub-engine, casehub-ledger, casehub-eidos, casehub-work, casehub-clinical, claudony, and casehub-connectors. Mechanical...
The Concrete Class Trap
The issue existed for a good reason. Mem0CaseMemoryStore had no storeAll() override — the SPI default fires one REST call per item, and Mem0 OSS had no batch endpoint to improve on that. Platform#69 deferred the work:...
Three small issues, one branch. I’ve been calling them “S-items” in the handover — #20 (CommitmentTools crash recovery), #22 (CDI wiring test), #25 (oversight channel type constraints). Nothing architecturally new. Bu...
QuarkMind — Layer 3: Four Surprises from qhorus
The CI had been red on casehub-aml since May 12. Not flaky red — consistently, deterministically red. Every run, every commit, same failure. The Maven Central BOM download was returning 403 before a single test had a ...
The vocabulary system that eidos#40 cleaned up needed something to run on. Three vocabularies and a new disposition axis — that was the scope of today.
casehub-life — Fewer Approvers, Stricter Gate
casehub-iot’s first chapter delivers the public API module — the types, SPIs, and registry that every consumer and provider depends on. In a semver-from-day-one foundation module, the types you ship first are the type...
The idea behind ActionRiskClassifier is simple: a worker is about to do something consequential — file a SAR, freeze an account, push to production — and before the engine commits that output to the case, a classifier...
The session started with a clear goal: close two small issues. One was removing an annotation from a test class. The other was making ReviewSessionService’s storage path configurable instead of hardcoded to ~/.draftho...
eidos#40 started as a small API gap. It became something larger.
A rename of 53 parameters sounds like maintenance work. All you’re doing is changing channel_name to channel and updating the description to “Channel name or UUID”. Mechanical. Boring. Except the design decision lurki...
Trust scores that update when attestations arrive, not when the clock ticks. The race condition in the obvious approach, the extraction that made it possible, and the CDI test gotcha that nearly derailed the integrati...
The last two issues on my S-scale backlog — conditional outcomes (#177) and JSON Merge Patch for templates (#199) — went through four rounds of spec review before a line of code was written. I went in thinking the rev...
Neural Text — The Native Image Gate
Two things shipped today. The first was small — a null correctness fix in InMemoryCaseFile that we’ve known about since #172 surfaced the problem. The second was the Layer 4 milestone: every agent plugin now reports i...
Five Small Fixes and One Red Herring
ARC42STORIES.MD for casehub-platform had been a stub since June. §1 and §2 were solid; §3 through §13 were placeholders — “complete in dedicated session” appearing in every heading. Issue #56 existed specifically to c...
The test that never ran
Channel names in Qhorus have always been a gentleman’s agreement. The database had a uniqueness constraint, nothing more. You could name a channel "Billing Output", "xp9qr", or a UUID string, and the platform would du...
The initial spec for the bootstrap guard had a gap I missed.
Two Vocabularies Are Better Than One
The problem was simple to state: the engine never found out when a worker finished. Claude CLI would run, complete, exit — and the case would stay frozen in WAITING indefinitely. The engine had called provision(), got...
JpaLedgerEntryRepository.save() never assigned sequenceNumber. Every JPA-persisted entry got 0 — the primitive default. The in-memory implementation had it right from the start: ConcurrentHashMap<UUID, AtomicIntege...
Started by clearing seven PLATFORM.md doc syncs — cross-dep table entries, deep-dive updates, protocol entries to the garden. Mechanical work. Done by mid-session.
Every platform capability looks straightforward from the SPI side. CaseMemoryStore.store(MemoryInput) takes a typed record and persists a fact. query(MemoryQuery) returns a list. Clean, immutable, well-designed. The d...
InMemoryMemoryStore was at @Alternative @Priority(1), the same as SqliteMemoryStore and Mem0CaseMemoryStore. In production this is fine — you never deploy them together. In @QuarkusTest you might: production adapter o...
casehub-life — The Filter That Tested Nothing
The Phase 1 placeholder was always going to need replacing: every OpenClaw agent output dispatched as DONE, regardless of what the agent actually said. If the case step closed correctly, great. If not — the case silen...
The session started without a handover file. The workspace existed — blog entries, ADRs, design journal, specs — but nothing pointing at what came next. I reconstructed from git log and the open issue list: three open...
connectors#1 was filed as a conformance task — XS, Low complexity. Add a section to DESIGN.md documenting which message types agents should use when talking to Qhorus channels. Done in an afternoon.
Four issues closed in one branch: three small quality fixes and the main event — DraftHouseMcpTools.
Writing the Map
A simple history squash revealed a hidden merge commit, the non-obvious patch-id detection behind 'previously applied', and a documentation audit that should have happened before the write.
The quarkus-flow worker arrived in the engine. My working assumption was that it would answer the open questions in §6.5 of the ACL spec — what identity does a flow worker carry, how does provisioning write grants, wh...
The previous entry ended with: “The fix is to return a result type that carries a wasCreated flag. That’s on a separate branch.” This is that branch closing.
Three small issues, one branch. #172 (NEAREST_THREAT null guard), #173 (Assimilator never built), #174 (stale doc refs).
Engine#206 has been on the list for a while: when a Worker runs a Serverless Workflow, the steps inside it have no way to dispatch other casehub workers. The workflow executes in quarkus-flow’s execution environment, ...
The sponsor notification path in casehub-clinical had a gap I hadn’t noticed: the ledger recorded whether a notification was delivered, but not who it was delivered about. writeSponsorNotifiedEntry wrote actorRole: sp...
AgentOutcome has had an observed_at column in its table since the knowledge graph shipped. What it didn’t have was any way to put a meaningful value there. The entity was calling Instant.now() at persistence time — so...
The small stuff first: two cleanups closed quickly. The dead MAP_CENTER fallback in DroolsTacticsTask — two ternary guards that could never fire once the NEAREST_THREAT gate was in place — came out in two lines. The G...
The issue said the channel creation API didn’t expose allowedTypes. That was wrong.
The denied_types enforcement work started with a design question about where validation should live. The Claudony spec called for a static StoredMessageTypePolicy.validateNoOverlap() method — catch bad channel configs...
The tests that were never green
States That Existed on Paper
Completing ARC42STORIES.MD with no DESIGN.md meant reading 16 blog entries first — the only honest source for why the code is shaped the way it is.
The starting assumption was wrong, and catching it early changed the whole design.
The real design work this session happened before any code was written. The spec went through three review rounds and came back substantially different each time — not style tweaks, actual structural errors.
The session started as doc sync — six open issues, all documentation, work from other repos that hadn’t landed in the platform docs yet. DraftHouse Layer 2 shipped and APPLICATIONS.md still said “Scaffold.” casehub-en...
The oversight channel in Claudony’s three-channel layout was supposed to be the governance channel — the place where agents pause and ask humans for approval before doing something consequential. The problem: it was c...
I had planned today as cleanup — close a few small items from the ledger and qhorus backlogs, then implement the project_channel MCP tool that got deferred at the end of the projection work. The cleanup went quickly. ...
Four backlog items. Three were paperwork — a groupId typo in a spec, a CLAUDE.md table that didn’t mention the agent modules yet, a test that used Thread.sleep(300) to paper over a timing race. The fourth was the inte...
The trust gate I shipped last session does the right thing: agents with no ledger history are always permitted. You can’t build a trust floor on nothing. Blocking a bootstrap agent means blocking every agent the first...
The session was backlog cleanup — six small items that had been sitting since Epic 7 closed. Most of them were administrative: close an issue the code had outrun, check an upstream bug’s status, file a parent repo iss...
The silent skip
Six S-scale issues. The kind of work that sounds small until you’re doing it — one test gap here, one undocumented method there, one missing @BuildStep. Each takes thirty seconds to describe and thirty minutes to get ...
Shipping casehub-platform-agent was a longer journey than the module count suggests. Two flat modules: agent-api for the SPI, agent-claude for the Claude integration. The spec looked solid going in.
The spec that got rewritten
Layer 5 is done. TacticsTask now activates only when scouting has found a threat and strategy has set a course of action. In the early game — no enemy contact — tactics never runs.
The tenancy enforcement batch took longer than the individual issue sizes suggested. Four issues on one branch: a migration (#411), a CDI qualifier pattern (#405), DB-level Row Level Security (#406), and a registry ha...
casehub-eidos knows what agents claim to be. Phase 4 gives it a record of what agents have actually done.
The previous entry noted seventeen email-inbound tests passing clean. What I didn’t say was that two of them were passing most of the time, which is different.
The question has been waiting since casehubio/ledger#114 was filed: when L4 and L6 land, should EigenTrust run alongside Bayesian Beta?
The issue description was confident: parent#144, duplicate ## Writing Style in arc42stories-spec.md, introduced by the PR#138 merge, both sections identical. Fix: delete the first.
DraftHouse had a local file-based parser for deriving a review summary from channel history. Claudony wants a digest panel from the work channel. The pattern is always the same: read the messages, fold to state, rende...
Two things landed today that change how the next few months look.
QuarkMind needs trust-weighted routing for four game plugins — strategy, economics, tactics, scouting — at roughly game-loop frequency. What it doesn’t need is Merkle chain verification, DID/VC identity binding, or Ed...
The build was clean — 174 tests. What the session was actually about is making architecture documentation you can trust.
The session started with what looked like a simple question: why is claudony’s CI red?
casehub-aml’s LAYER-LOG has had seven complete entries since May 30th. Each one has Pattern to replicate, Key wiring, Gotchas, Accountability gaps. The content was there. Today Claude and I gave it a format.
The existing eval dataset was entirely synthetic — devtown planners, ML researchers, code reviewers built from scratch to stress-test the renderer. They did the structural job fine. What they couldn’t answer was wheth...
The question was simple: what is this agent currently doing? Trust score, active WorkItems, open Commitments, running cases. Four systems, four separate calls, manual join at the caller. We filed it as parent#56 back ...
The last entry ended with #165 tracked but deferred — canProduce() read-only contract was doc-only. Making PlayerState public was the right call, but it left the plugin seam in an awkward position: nothing prevented a...
Before generating a single line of ARC42STORIES.MD for clinical, I wanted to understand whether the arc42stories spec actually enforced the write-content modes — or just mentioned them.
The first thing I noticed when starting ARC42STORIES.MD was that LAYER-LOG.md was completely wrong. Every Epic from 2 through 7 was marked “Pending” or “In progress” — but all of them had been closed in GitHub weeks a...
casehub-life now has an ARC42STORIES.MD — 1175 lines covering §1 through §13 plus a self-assessment. The document absorbs what was previously spread across LAYER-LOG.md (layer entries), the workspace DESIGN.md (cross-...
The build came up clean first pass — all 17 email-inbound tests through, no IDLE timing failures. After two sessions of coaxing GreenMail into behaving, that counts as a result.
ACL has been the obvious missing piece for a while. The platform has identity, RBAC, and preferences — it knows who an actor is, what groups they belong to, what settings apply to them. It has nothing to say about wha...
The PR had seven commits and clean local tests. CI disagreed — four times.
Issue #164 was a small one by description: PlayerState is package-private and RaceModel takes it as a parameter, so external race implementations (required by #74) can’t implement the interface. Make PlayerState publi...
The session opened with a heads-up from another Claude working in casehub-work: casehub-platform-api was shipping without a Jandex index. It’s the pure-SPI jar — interfaces and records, zero dependencies — and until n...
Wrong Name, Right Exception
I brought Claude in to run the full build and see where clinical stood. Twelve failures, three distinct causes. Two were quick: the engine had a new findByUuid(UUID, String tenancyId) signature, and the pi-oversight c...
The session started with a broken build. Not a compilation failure — CDI augmentation. Quarkus couldn’t start the test application because it found two @DefaultBean implementations for CurrentPrincipal: one from caseh...
I came in expecting to wait the engine round-trip test out. The previous session left a note: CaseEngineRoundTripTest fails because the engine SNAPSHOT has an in-flight PlanExecutionContext constructor change. Engine ...
The last few sessions assembled ledger’s identity pipeline — DID binding, SCIM lookup, key rotation, VC validation. It worked. It just happened to live in entirely the wrong place.
The sweep was done. The branch was closed. Then I ran mvn install.
Phase 5 is done. I expected to branch and start coding. The test suite said otherwise: all four child issues closed, 828 unit and integration tests passing.
Layer 5 adds casehub-engine — the orchestration layer that turns sequences of workers into multi-step case workflows. Where Layers 2–4 gave casehub-life individual capabilities (SLA enforcement, commitment tracking, t...
The S/XS backlog from the multi-tenancy session had nine open issues. I went through them all in a single branch today — eight commits, one PR. Most were straightforward. Two weren’t.
Seven issues with S or XS labels. I wanted to get through them in one session rather than let the list drift further.
Before this branch, ConnectorChannelBackend had one answer for an unrecognised sender: discard with a WARN. That was fine when channels were pre-provisioned. It stops being fine the moment you want SMS from a new numb...
The issue was filed to add a tier taxonomy to the Arc42Stories spec — Application tier, Foundation tier, Extension tier. Reading it, something felt off.
The polling model was always a placeholder. Open a connection, search unseen messages, close, wait 60 seconds, repeat. It worked, but latency of up to a minute is the wrong answer for a platform routing messages to AI...
Batch work day. I wanted to close a pile of S and XS issues before moving to Layer 4, and the result was less about new code than about finding out which issues had already been answered by earlier work.
The branch was supposed to be closed. Handover said so. Seven items swept, committed, pushed upstream.
The closure stamps were all there. Every branch had its chore: branch closed commit, every deletion date in the future, every project branch stamped. By that metric, everything was in order.
Issues #45 and #46 extended the observer fallback pattern to SafetyOfficerNotificationListener and SponsorNotificationListener. Issue #48 extends it to AeEscalationListener and IrbDecisionListener. Those two have a di...
The branch was supposed to be closed. Handover said so. Seven items swept, committed, pushed upstream.
A listener that registers without complaint, data flowing from server to browser, an open connection — and yet the panel never updates. That’s how SseMeshStrategy had been sitting in the codebase.
The ExclusionPolicy javadoc had a forward reference to issue #185 where proper extension guidance should be. I wanted that resolved: what the activation pattern looks like, what the excludedUsers field means, and a co...
My first instinct for tenancy in the engine repositories was elegant: inject CurrentPrincipal, read tenancyId() in each query, filter silently. Callers stay clean. Protocol PP-20260520-e6a5f0 says exactly this — bind ...
Layer 7 had a clear framing: for each FinCEN/FATF requirement the architecture claims to close, surface the evidence an examiner can use to verify the claim independently.
OpenClaw agents are capable. They call APIs, read calendars, send messages, run heartbeats. But when an agent commits to do something, there’s no machine-readable record it ever happened. No deadline. No escalation if...
The session started with cleanup — checking which of the blocking issues from the handover were actually still open. Engine#326, engine#337, engine#336, qhorus#199: all closed. Nothing blocking P1.3.
The visualizer has been working since April. It renders probes, geysers, minerals, buildings, fog — the full SC2 picture. But four things sat on the deferred list since then: HUD mineral formatting, probe overlap, res...
Format Names Matter
The CaseHub memory stack had two endpoints: an in-memory ConcurrentHashMap for tests and ephemeral deployments, and a PostgreSQL-backed adapter for production. There was nothing in between. If you wanted durable memor...
The branch before this one proved that ledger entries can be cryptographically bound to W3C DIDs. This one asked the harder operational question: what happens to the caches when a key rotates?
The sprint list going into this session was eleven issues — #213 through a batch of S and XS items that had been accumulating while the connector backend work ran. I brought Claude in to work through them sequentially...
Qhorus has always been an agent-to-agent communication layer. COMMAND, RESPONSE, DONE — speech acts between agents, with the human in the loop only through Claudony’s browser panel. This branch changes that. Connector...
Platform#48 came in as feedback from devtown — the first consumer to wire up CaseMemoryStore in a real application. The core interface was right; the gaps were in what surrounded it. No standard way to emit memories. ...
Issues #45 and #46 are in main.
When a Quarkus app restarts, every in-memory registry starts empty. For BlackboardRegistry, that meant any WorkItemLifecycleEvent arriving before the next CONTEXT_CHANGED — a human completing a delegated task, say — w...
I knew going into this that connectors#6 was going to be harder than it looked. The issue title — “InboundMessage CDI event → MessageService.dispatch()” — sounds like a bridge: two things you connect with a cable. It ...
The problem is simple to state: a worker posts a message on Node B. The browser watching that channel is connected to Node A. It gets nothing.
Last entry closed with “Layer 7 is next.” Two items had to go first.
The EmulatedGame has been Protoss since the day it was built. Twelve probes, a Nexus, 15 supply — all hardcoded. Adding Terran and Zerg (#138) forced a decision I’d been putting off: where does race-specific logic act...
The batch we cleared this session was five issues — all small, all overdue, all the kind of bugs that pass unit tests and quietly break in production.
The Electron Playwright suite from md-compare got deleted when we migrated to DraftHouse. The intention was always to replace it — “Quarkus Playwright, properly” — but it got filed under Phase 2 and sat there for two ...
The Layer 3 code was done. What wasn’t done was writing it down.
The bilateral signing added in the previous branch proves that someone signed a ledger entry with the private key for a given actorId. It does not prove that the person holding that key is actually claude:reviewer@v1....
CaseHub Eidos — Three Issues, One Pipeline
Epic 6 was supposed to be the wiring-up epic. COMMAND arrives on a Qhorus work channel, gets forwarded to OpenClaw via /hooks/agent, OpenClaw completes, POSTs the result back, the result lands on the channel. Most of ...
GroupMembershipProvider.membersOf(groupName) has been in platform-api since the beginning. It answers the inverse membership question — not “what groups is Alice in?” but “who’s in the reviewers group?” — and it has a...
Issue #11 — AE safety officer notification — is in main.
The problem with "legal_review" is that it looks exactly like "legal-review". One underscore. WorkBroker does exact string matching — if the engine puts "legal-review" in a case definition and the worker registers "le...
ReactiveMessageService.dispatch() has existed for a while with a sign above it saying “full enforcement coming in #193.” That day arrived today.
Worker carries a definition, not an outcome
The squash branch from this morning had been sitting at 1:53 AM — interrupted before it could be pushed. It contained something worth rescuing: a terminology shift that had been rewritten into tutorial-strategy.md and...
Two issues on this branch: one a single line, one an architectural redesign.
The issues were labelled XS and S. Five of them, all supposedly straightforward. I worked through each one, and three of them had a wrong assumption embedded in the design I’d sketched before touching code.
The batch that closed today was supposed to be an afternoon.
Issue #162 was filed yesterday during the #160 review — not a bug, just a duplication I didn’t want to leave in place. AbilityMapping.onSelection() and IEM10CommandExtractor.applySelectionDelta() both maintain an orde...
Three syncs, two principles
The previous entry closed three Panache static calls that were bypassing the store seam in WatchdogEvaluationService. What it didn’t close: line 100, where w.lastFiredAt = now directly mutated the entity field.
The research spec had @agent.on("before_prompt_build") in Python. That code doesn’t run anywhere. OpenClaw’s hook system is TypeScript only.
Three coverage gaps left over from the engine SPI cleanup branch. The issues were clear enough going in: add lifecycle assertions to the grade4 test (it had fewer checks than grade3 despite being the more serious path...
The most useful part of this branch was catching a schema design problem before it reached code.
I started this branch expecting a small fleet plumbing task and found out immediately that the plumbing was already broken — even on a single node.
Layer 3 isn’t about adding more code to the PR review. It’s about making the obligation explicit.
Before starting Layer 4 — casehub-ledger integration — I wanted to close three backlog items that had been accumulating since Layer 3. None were blocking, but they were the kind of drift that compounds: inconsistent d...
Layer 6 shipped last entry. Between the trust loop closing and Layer 7 starting, there was a small backlog to clear — two doc improvements and a quality fix that had been sitting in the queue.
Three issues in one branch: unit tests for IEM10CommandExtractor.applySelectionDelta (#160), a SimulatedGame.isComplete() base-contract test (#161), and Terran ability IDs in AbilityMapping (#140). The first two went ...
The existing ClaudeMarkdownRenderer sent YAML to an LLM and returned whatever came back. Format, structure, tone — all the LLM’s problem. I didn’t question this until I had to design the next version.
Layer 6 is shipped. Experienced agents now route to complex AML cases, and SAR outcomes feed back into the trust scores that drive future routing. The loop is closed.
The store seam pattern in Qhorus is simple: services inject *Store interfaces, JPA implementations run in production, InMemory alternatives activate in tests. Every service follows it — except WatchdogEvaluationServic...
The branch opened with a clear goal: build a REST client adapter for Memori, the SQL-native AI memory engine. Tier 1 of the CaseMemoryStore adapter ladder. By the time we were done, there was no Memori REST adapter. T...
The engine SNAPSHOT update from last week deleted CasehubWorkloadProvider — the CDI bridge that made WorkloadProvider injectable in @QuarkusTest. The deletion made sense architecturally: it was an adapter from the wor...
The question that opened this session: can AgentKeyProvider work with Vault Transit?
Two routing issues had been sitting on the backlog since the AgentRoutingStrategy SPI shipped. One was about what to do when all candidates are borderline on trust — the four-phase model says escalate to human oversig...
The core change was two lines. ClaudonyReactiveCaseChannelProvider.listChannels() was calling listAll() — every channel in the database, then filter client-side for the ones belonging to the case. findByNamePrefix() h...
Not just drift
The question Layer 3 answers is simple: what happens when a contractor says “I’ll be there Thursday” and then isn’t? In Layer 2, a WorkItem expires and LifeSlaBreachPolicy escalates. That’s the right answer for tasks ...
Four review rounds on the email inbound spec before a line of implementation code. Over twenty findings. Three of them would have caused real problems in production. I’m glad we ran them.
The previous entry ended with associate(agentId, channelIds) as the registration mechanism — WorkerProvisioner knows the agentId, knows the channels, calls associate. Tidy in theory. In practice: the provisioner knows...
The goal going in was simple: generate ARC42STORIES.MD for devtown from LAYER-LOG.md, DESIGN.md, and the Arc42Stories spec. Claude had the source material. It would be a documentation session.
The plan was to implement Layer 3 of devtown.
The IEM10 dataset has 30 tournament replays from 2016. Until now we’d used them for tracker events only — building state, counting units, tracking births. The gameEvents array was sitting there the whole time, encodin...
Seven null fields
The watchdog module has always had a gap: conditions fire, alerts go into a Qhorus channel, and nothing reaches a human unless an agent is watching. For pure agent-to-agent systems, that’s fine. For anything with huma...
Every CaseHub case starts cold. A new work item opens, the engine spins up, and it knows nothing about the entity it’s about to reason over — not what happened in prior cases, not what agents learned, not what was obs...
The plan going into this session was mechanical. Add a DTO layer, wire casehub-work WorkItems to HouseholdTask, implement LifeSlaBreachPolicy. The brainstorming session found something else.
Keeping the docs honest
The ChannelContextWindow is what makes the multi-agent mesh actually work at the LLM level. Without it, an OpenClaw agent waking up to a COMMAND knows only what that message says. It doesn’t know that finance-agent po...
I asked about quarkmind issues. The response: “what’s quarkmind?” That was the tell. The repo existed locally, built in the incremental CI, had its own CLAUDE.md. Entirely invisible to the peer repo list, the full-sta...
Four correctness fixes shipped today as a single PR. Three are mechanical — a PlanItem stuck in RUNNING when Quartz retries exhausted, an atomic counter race in the JPA repository, an OTel trace ID always null because...
The tenancyId null guard from last time left agentId exposed. findById takes two required parameters — I only protected one of them.
A Quarkus library module with no end users, no versioning commitment, no backward compat — that’s the license to design cleanly. The OpenClaw hook API client is the first real implementation in casehub-openclaw, and i...
The first layer of casehub-life is done. Before we got there, I spent more of the session than expected on one design question.
eidos#10: findById(String agentId, String tenancyId) had no null guard on tenancyId. The blocking impls silently returned Optional.empty() — "default".equals(null) is false, not an exception. The JPA version passed nu...
The signal gaps in the engine — Qhorus human messages that never reach cases, WorkItem escalations that freeze WAITING cases, M-of-N group outcomes that vanish — all traced to eleven lines in CaseContextChangedEventHa...
After a squash, there’s always a debris field.
Forty commits since the last backup. The goal was to compact them to something readable — Layer 1, Layer 5, Layer 2 as three clean arcs, with the housekeeping noise absorbed.
The issue description for eidos#2 said query.slot().equals(d.slot()) would NPE when d.slot() is null. It was wrong. Java’s String.equals(null) returns false — the argument can be null without trouble. NPE fires only w...
The progress documents were three weeks stale. PROGRESS.md and the Gastown analysis were both dated 2026-05-02, and a significant amount of foundation work had shipped since. We fixed that by dispatching five separate...
Before writing any code, I checked each issue against the current state. Four of the six were already done.
Five small issues. The word “small” proved relative.
The first items off the small-issues queue: one already done, just never closed.
The original description for Epic 3 was “multi-site sub-case structure.” It sat in the backlog for three months, blocked on an engine dependency. When that dependency shipped last week and we started the brainstorm, I...
The sub-tick timing fix for unit training had one known gap: buildings still used integer tick counts, no loop offset, whatever we’d written down.
The spec called for a CapturingBreachPolicy @Alternative @ApplicationScoped static inner class — observe SlaBreachEvent calls from ExpiryLifecycleService, record the SlaBreachContext received, verify the policy isn’t ...
TrialActivationService was throwing ClientErrorException. Not via an exception mapper, not through any abstraction — a raw JAX-RS exception thrown from an @ApplicationScoped service bean that imported jakarta.ws.rs.co...
Phase 3 is done. 121 tests, all green.
I wanted to add casehub-engine to the AML investigation without rebuilding what Layers 3 and 4 already did. The engine should replace the fixed sequential pipeline in QhorusAmlInvestigator — not wrap it.
Today started with a question that sounded simple: what would OpenClaw + CaseHub look like?
I started this session thinking the hook infrastructure was sorted. It wasn’t.
The batch of small issues was supposed to be quick. Some were. But the quick ones turned out to be quick for the wrong reasons — or took detours that weren’t in the issue description.
An untracked file in persistence-memory/src/test/ caught my attention at the start of the session. TestEntryFactory.java. Not in git, not committed, no history at all — git log --all -- <path> returned nothing.
Spent a session on housekeeping — the kind that doesn’t show up in the feature log but matters for the next person who opens the repo and wonders what’s live and what’s done.
When we ran the first production quarkus:build on casehub-clinical, the test suite was entirely green. 115 tests, no failures. The build gave us 43 CDI deployment problems.
The code moved faster than the docs. That’s not unusual, but it starts to matter when the docs are the coordination surface between repos.
Coming back after Layer 4, the docs said Layer 5 — adaptive investigation paths, PEP routing, parallel checks — was blocked on engine P1.3. I’d accepted that at face value when I wrote it.
Layer 2 landed: every human-approval WorkItem now has a 24-hour deadline, escalates to pr-leads on first breach, and signals the case context with {status: "sla-breach"} on the second. The interesting part wasn’t the ...
The ecosystem had drifted. Build scripts, workflows, and the website dashboard were all tracking a different set of repos — some stale, some just missing.
I wanted something on casehubio.github.io that said what CaseHub actually is. The GitHub org page lists repos and their descriptions — useful for people who already know the project, useless for anyone arriving cold. ...
LedgerVerificationService had a secret. Inside its treeRoot() method, injected alongside the proper LedgerEntryRepository, was a bare EntityManager — used to query LedgerMerkleFrontier directly. No SPI. Just JPA, bake...
Three code review nits and a follow-up feature. The nits are barely worth a paragraph.
After shipping the deadline dispatch work, four small items were left on the branch. I expected to clear them quickly. One of them taught me something.
I wanted to understand how casehub-engine would call CapabilityHealth.probe() at dispatch time. The design question is real: WorkOrchestrator needs an AgentDescriptor to call probe, but the engine’s Worker model carri...
The platform coherence audit I ran a few months back logged 32 cross-repo capability gaps. Six of the top eight had since been closed. The remaining 23 sat in parent#4 as descriptions — claimed, not verified against t...
The previous entry ended with a ±1 tick residual in the replay validation — Stalkers completing one tick early because drainBuildingQueues passes 0L to startTraining for the next queued unit, losing the sub-tick loop ...
The smallest task — evaluate whether LedgerTraceIdProvider should move to casehub-platform-api — looked like a clear yes. Multiple peer repos use the interface. It’s named after the ledger but the concern is cross-cut...
Two small fixes that close a larger gap — scope propagation for SLA preference routing and a silent when-field bug in contextChange bindings.
Layer 5 is done. casehub-engine is in clinical, the IRB gate works end-to-end, and Grade 3/4 adverse events now route adaptively rather than through a hardcoded switch. 115 tests, all green.
Forty-three CDI deployment failures at Quarkus augmentation. That’s where the session started.
Five open issues from the #184 code review — most of them small. Test gaps in the MessageDispatch builder. A stale Javadoc on LedgerWriteService that said “write failures are never caught here” when attestation writes...
Layer 4 was supposed to be the simple one. Add casehub-ledger as an explicit dependency, write a couple of domain entries per investigation, wire them to the HTTP response. The main design question was: how do you lin...
The session opened with a question I’d been ignoring: had any of the casehub-platform blog entries actually made it to mdproctor.github.io? I brought Claude in to check. We looked at the _notes/ directory on the Pages...
The Four-Layer Agent
Root scope — Path.root(), an empty path — was never included in the preference resolution ancestor chain for any non-root scope. Call resolve() with Path.of("casehubio", "devtown") and the walk produces ["casehubio", ...
The persistence-jpa module backs PreferenceProvider with Postgres. The platform needed a second option: MongoDB, same SPI, no Flyway.
A separate Claude session — running earlier today — added Path.root() for the zero-segment root scope. The commit was solid: correct logic, clear motivation. When I picked up the session I asked Claude to review it be...
The previous branch left the @QuarkusTest suites in casehub-blackboard blocked — RoutingCursorStore unsatisfied dependency. The fix was straightforward: add quarkus.arc.exclude-types=io.casehub.work.core.strategy.Roun...
Platform#24 opened a question: where do application-layer SPIs live when they’re domain-agnostic but too specific for the foundation tier? The proposed answer was a casehub-platform-apps-api module. The actual answer,...
EscalationPolicy.escalate() was always a lie. It pretended to be a hook, but it was really fire-and-forget: the expiry service called it and moved on with no way to know what happened next. Escalation was void.
The persistence-jpa/ module is the first in the platform that actually writes to a database. Config reads from YAML files. OIDC reads from JWT claims. Nothing persists state — until now.
Every MessageLedgerEntry in qhorus recorded the same field as its subjectId: the channel it was sent on. “entity-resolution”. “pattern-analysis”. Useful for routing. Useless for compliance. A regulator querying ?subje...
I’ve been assuming the agent model was complete. You have an actorId — "claude:reviewer@v1" — you have trust scores, attestations, bilateral signing. Who the agent is: solved. What kind of thing it is: not even asked.
When we moved JQEvaluator into casehub-engine-common as part of the JQ consolidation a few days ago, we knew it was temporary. The comment in CLAUDE.md said so explicitly: follow-on platform extraction tracked in engi...
Before touching any code I stopped and asked whether the casehub Agent class should exist at all. LangChain4j has its own agent model — UntypedAgent, AgenticScope, supervisor patterns. Was the casehub version just rei...
The previous entry ended with gas units as the remaining divergence: EmulatedGame starts with 0 vespene and earns none, so every TrainIntent for a Stalker (50 gas) or Immortal (100 gas) is silently rejected. Each reje...
The parity protocol for casehub-ledger’s blocking and reactive service tiers was enforced by the document that stated it. Add a method to KeyRotationService, add the reactive equivalent to ReactiveKeyRotationService, ...
The branch was closed, the blog written, everything published. That should have been the end of it.
The engine team filed a request: JQEvaluator needs to live in casehub-platform, not casehub-engine-common. Foundation-tier repos like casehub-work can’t reach into the Orchestration tier to borrow a JQ evaluator. The ...
The pre-push hook checks for squash candidates before anything leaves the machine. The patterns in it look reasonable: ^docs\(claude\):, ^fix\(test\):, ^chore:. It had been in place for weeks. Every push sailed throug...
Short session today — a cleanup branch and one unexpected discovery.
Before starting Epic 6 — the IRB gate — I wanted to verify the engine-side wiring was actually there, not just assumed.
The global mesh dashboard SSE stream had been silently delivering nothing.
The previous entry ended with a diagnosis: the completesAt formula uses float arithmetic (268.8 for Probe — derived from 12 seconds × 22.4 loops/second), which causes floor division to give the wrong tick at certain l...
With the HITL lifecycle test passing, Layer 2 has a clear brief: add a formal deadline and escalation path to the human review WorkItem. Currently the human-approval binding creates a WorkItem with no expiry, no candi...
Every external backend in the qhorus gateway was solving its own restart recovery independently. The moment I saw that pattern, I knew the framework was exporting a problem it should own.
The sealed interface SpecialistOutcome<T> has three permits — Completed, Declined, Failed. Every switch expression that pattern-matches on it must handle all three, or it won’t compile. Java enforces this.
The most revealing part of this cleanup was what happened when we converted TestSlackConnector from static fields to instance fields.
There’s a particular kind of bug that’s easy to miss in review: code that compiles, ships, and runs fine — it just doesn’t do what it says it does.
There’s a pattern I keep seeing. Claude builds a workaround. Not wrong exactly — the workaround works — but it accumulates a layer where none is needed. A wrapper class to avoid breaking a caller. A compatibility shim...
The ActorType migration was straightforward until review caught something I’d missed.
The bug was simple: { humanApproval: { status: .decision } } in an outputMapping was producing a String literal in the case context instead of a nested Map. The fix should have been five lines. It turned out to be the...
ActorType (HUMAN/AGENT/SYSTEM) has lived in casehub-ledger-api since the beginning. It’s the right concept in the wrong address — identity classification belongs in casehub-platform-api, not in an audit ledger library.
FlywayMigrationSchemaTest had this at the top of @BeforeAll:
The fix for issue #179 looked straightforward: add classpath:db/ledger/migration to the qhorus Flyway locations and renumber the V1003 subclass join migration to avoid the conflict with ledger’s own V1003. The origina...
The previous session had done the real work — three refactors (#175, #176, #177) that moved ChannelDetail, InstanceInfo, and MessageResult out of QhorusMcpToolsBase into the api module and extracted shared mappers int...
Three small things that had been sitting on the list since the oidc module shipped.
After closing qhorus#179, the blog entry I’d just written was sitting on workspace main and not on mdproctor.github.io. The fix was three lines — copy, commit, push. But the question was: why did that keep happening?
A cleanup session — closing issues that were already done or false, then three refactors that had been sitting on the backlog.
This morning started as a maintenance day. Fourteen open issues on the parent repo, almost all XS or S, almost all doc or protocol work that had accumulated over a few sessions. The kind of backlog where each item tak...
The “What’s Next” table in my handover had nine items. I went to start the first one — engine#300, add the deadline field to the COMMAND message — and found the issue closed. The code was already there, committed thre...
The previous entry ended with building costs as the remaining divergence cause. That turned out to be right about the cause, wrong about the fix — and investigating why led somewhere more interesting.
The platform protocol for Flyway migrations said: if your module has its own named datasource, place migrations in db/migration/<module>/ and configure quarkus.flyway.<datasource>.locations=classpath:db/mi...
The backlog is clear. Everything filed as S or M this session is done — six issues including one I’d underestimated. That felt satisfying until the code reviewer flagged a bug I hadn’t suspected.
The issue description was confident: “Duration.parse() throws DateTimeParseException for any non-PT-prefixed format (e.g. P1D).” We were adding validation to CaseDefinitionYamlMapper.convertHumanTask — the method that...
The previous entry planted tenancyId() and isCrossTenantAdmin() in the SPI before anyone could build on top. This one fills in the real implementation — OidcCurrentPrincipal, now in its own optional module.
A migration path move sounds like infrastructure housekeeping. SQL files, a directory rename, update some properties. Done in twenty minutes.
PLATFORM.md had a boundary rule: don’t call ReactiveQhorusMcpTools from internal service code. ReactiveQhorusMcpTools is the MCP protocol dispatch layer for Claude Code — calling it from MeshResource couples a REST en...
Flyway has been disabled in @QuarkusTest since Layer 3 shipped. The workaround — drop-and-create and migrate-at-start=false — was supposed to be temporary. qhorus#174 moved the qhorus migrations out of db/migration/qh...
I started the session expecting to begin work on train-timing precision. Within two minutes it was clear the work was already done, closed, and merged. My notes from the last session were wrong about the state of thin...
Small fix today, but one that required a small mental reset.
The comment was right there in ReactiveLedgerVerificationService:
Every multi-tenant system I’ve seen retrofitted from single-tenant has scar tissue. Columns added after the fact, cache keys that leak data between customers, foreign keys that don’t include tenant scope. The longer y...
ICH E6(R3) §4.5 is unambiguous: the investigator must notify the sponsor promptly of any deviation that significantly affects subject safety or data integrity. MAJOR deviations hit that threshold by definition.
WorkItemCreateRequest had 24 parameters. A new field meant adding it to the end and passing null at every call site you could find. Sometimes you missed one. The record was too honest about its own constructibility.
work-adapter had a json-schema-validator pin sitting in the wrong place — it belonged in the root pom.xml alongside the other BOM overrides, not buried in the module that happened to need it first. Moving it was two l...
The plan was straightforward. The human-approval WorkItem binding was wired in the previous session, so writing an integration test should have been a matter of plumbing — start a case, confirm a WorkItem appears, com...
Two sessions of maintenance work. Not glamorous, but the kind of day that leaves the board genuinely cleaner than it started.
Claudony is about to start tracking Commitments — Qhorus obligation records that bound how long an agent has to act on a COMMAND. To set an expiry, it needs the case budget deadline. The problem: claudony’s postToChan...
The old workflow needed two commands to start any piece of work: /work-start for pre-checks, then /epic begin to create a branch. If you forgot the second one, you’d be writing artifacts to the wrong place — journal m...
Two things got fixed today. One took three lines. The other consumed most of the session and ended with us back where we started — but one concept richer.
The previous entry ended with the platform foundation shipped. Devtown read the spec and came back with six specific problems. The response changed the shape of everything.
The casehub-engine-work-adapter has been implemented for weeks. HumanTaskScheduleHandler creates WorkItems. WorkItemLifecycleAdapter listens for completion and signals the engine to resume. The code is there. But devt...
The last entry ended with a claim: the ≤ 2 unit delta was the mining model. That turned out to be wrong — or at least, incomplete.
The cleanup epic had six issues. Most were straightforward. Two were not.
The bug report was straightforward. JDBC-only consumers — casehub-aml, casehub-clinical, casehub-devtown — failed to build after we shipped the reactive key rotation service. Quarkus CDI validation runs at augmentatio...
A full test run surfaced three things that needed fixing. One was trivial, one took four attempts to understand, and one was a missed update from the previous session’s reactive migration.
The @InjectMock in CaseEngineRoundTripTest was technically correct. It was also hiding a production bug. Removing it required an architecture session that went further than expected.
Started with two blockers for clinical: qhorus#154 (correlationId in InboundHumanMessage) and qhorus#153 (CDI event on message receipt). Simple issues. Neither was.
Most of the day was cleanup — small things that had accumulated since the atomicity work. A two-arg arity mismatch when casehub-work extended SelectionContext and WorkItemCreateRequest without updating the engine call...
We started today with a handful of small tasks to work on while waiting. The first check — is qhorus#153 shipped? — turned out not to be small at all.
ExclusionPolicy.isExcluded() returned a boolean. It answered the wrong question.
The parent docs described casehub-aml as “an agentic harness for Anti-Money Laundering investigation.” I read that sentence back and it didn’t sit right. The application isn’t the harness — it’s what runs on the harne...
casehub-platform is the zero-dependency foundation for everything else in the stack — Path hierarchies, typed preferences, principal identity. Before any other module can ship, this one has to exist. We spent two sess...
The PR review CasePlanModel shipped today. Nine bindings, three goals, content-driven routing that actually routes on what the code contains rather than what the author declared.
The KeyRotationService had blocking methods. The platform rule says all ledger service methods must ship both blocking and Uni<T> reactive variants. Adding the reactive variants looked routine — three methods to...
The last OHT gaps are closed. WorkItemTemplate now carries the full type contract: named outcomes, JSON Schema for payload and resolution, and an explicit exclusion list for conflict-of-interest enforcement. Three iss...
The hypothesis going into this session was simple: EmulatedGame’s flat mining rate accumulates minerals too fast, the surplus lets it afford units one tick early, and unit counts diverge. Fix the mining model, fix the...
The architectural investigation was yesterday. Today was implementation — and the gap between a clean design and a working build was, predictably, messier.
After the PI authorisation work shipped, the Merkle chain was only half-written. The COMMAND entry existed — the formal obligation to the PI was recorded. But not how it resolved: approved, rejected, escalated, expire...
The bug in HumanTaskScheduleHandler was easy to describe: if WorkItem creation fails after item.markRunning(), the PlanItem ends up stuck RUNNING with no WorkItem to complete it. The engine won’t reschedule it — the P...
Twenty workflow gaps identified, all closed. The epic/workspace/journal machinery is now hardened — section hashing, atomic branch switching, HANDOFF.md always on main, anchors validated before commit.
Two design decisions from this week’s ledger work keep rattling around, and I want to write them down while they’re fresh.
The protocol deviation PI authorisation implementation is in main — pure qhorus COMMAND lifecycle, per-deviation channels, and two structural gaps in the inbound path that are now documented upstream.
HumanTaskScheduleHandler has had a stub in template mode for a while. The comment was honest: // Template mode not yet implemented — leave PlanItem PENDING so binding stays eligible. What was less obvious was that the...
Two bugs today. #151 looked like a two-line change — DELEGATED was mapping to "completed" in the A2A task state API when it should map to "working". A delegated task is still in progress with the delegate; the API was...
Phase 6 was about feeding real player commands into EmulatedGame and watching the unit counts match the replay. The question was how to get those commands out.
Closing the agent mesh epic required working through five separate infrastructure problems before the real integration test could be written. What they were and why they were non-obvious.
The CDI problem surfaced immediately. Layer 3 adds casehub-qhorus — typed COMMAND/RESPONSE/DONE/DECLINE per specialist agent. The natural implementation would be a new service implementing AmlInvestigationApplicationS...
A prompt arrived at the start describing three bugs in casehub-work-ledger — JSON built with String.format(), a null guard missing on eventSuffix(), eight tests with wrong expectations. I looked at the code. All three...
A systematic audit found 20 gaps in the epic/workspace workflow. Nine fixed. Claude moved artifacts the wrong direction three times before we got the routing right across all ten repos.
I went into this confident. The plan was to make quarkus-hibernate-reactive-panache optional in the runtime pom — so consumers on JDBC-only datasources wouldn’t get the reactive extension activated unconditionally — a...
The last entry ended with EmulatedGame finally behaving like a real SC2 engine at the structural level: parallel building queues, correct supply timing, auto-engage. The question was whether the physics actually match.
The previous entry covered the HumanTask binding design — the sealed BindingTarget, the outbound HumanTaskScheduleHandler, the outputMapping round-trip. Claude had built the implementation in a separate session. We ve...
Every clinical trial runs on a protocol — a precise specification approved by the IRB and, for IND trials, by the FDA. Every procedure, every measurement window, every patient selection criterion is spelled out and fr...
The previous entry ended with a loose end: JsonPatchContextDiffStrategy still using @Alternative while the no-op next door had just moved to @DefaultBean. Before touching it I wanted to understand why the inconsistenc...
When a platform’s no-op SPI defaults use bare @ApplicationScoped, consumer repos pay the price. CDI sees two qualifying beans for the same injection point — the engine’s fallback and the consumer’s real implementation...
Knowing an agent is trusted for security reviews doesn't tell you whether they're thorough — adding CAPABILITY_DIMENSION as a fourth trust score type and replacing a leaky scope_key encoding with two explicit nullable...
A2A sends bare role strings as actor identifiers. role: "agent" arrives in Qhorus as the literal string "agent". The ActorTypeResolver in casehub-ledger classifies actors by pattern: "agent:*" prefix → AGENT, versione...
The Binding class in casehub-engine has had two nullable fields since the beginning — capability for worker routing and subCase for spawning child cases. Mutually exclusive by construction, which meant dispatch code e...
Working with LLMs on small, isolated tasks is straightforward. Working with them on a production platform — multiple repos, evolving domain, long-lived codebase — is a different problem. The difference is scale, and s...
Adding a trust read-model and import SPI to casehub-ledger so actors arriving from other deployments can bring their reputation with them — without requiring configuration switches in consumer repos.
Phase 6 requires the emulated engine to behave like real SC2 — fixing independent building queues, supply reservation timing, building type validation, and an enemy AI that generated fake building tags.
The session started with a false premise. The handover flagged SubCaseExecutionHandler as “never implemented — scaffold only.” It was actually done: 142 tests green, parent cases transitioning to WAITING, children spa...
Two Quarkus findings from SSE test coverage: @TestSecurity that silently does nothing without an HTTP call, and why SSE causality in Claudony can't be tested through Event.fireAsync().
Layer 2 of casehub-aml wires in casehub-work for compliance officer task routing — settling the hexagonal architecture question of where orchestration belongs and using @DefaultBean to make the richer implementation w...
The issue said the casehub-work adapter wasn’t implemented. Claude opened the work-adapter module and immediately found WorkItemLifecycleAdapter.java, CallerRef.java, and eight passing tests. The inbound path — WorkIt...
A colleague raised this at the start of a conversation: Quarkus is getting buried in low-quality AI-generated PRs. Reviewers can’t keep up. Could DevTown help?
The question was whether the platform had chosen the right architectures. It led somewhere more interesting: the dependency rule had been there all along, enforced, just unnamed.
Adverse event escalation is in main.
The question of whether MapCaseFile’s get() should return Optional<T> or nullable T seemed like a design detail. It opened into something more useful.
Epic 4 is done. Report a Grade 3 adverse event and the system returns a workItemId with a claimDeadline 24 hours from reportedAt, and writes an AdverseEventLedgerEntry into the Merkle audit chain. Grade 5 gets an hour...
Epic 3 was supposed to be the architectural centrepiece — each trial site becoming its own sub-case, trial-level DSMB rollup detecting cross-site safety signals from accumulated blackboard state. The HANDOFF said the ...
A systematic scan of nine repos revealed consistent naming drift. Most fixes were mechanical. Claudony was not — and the connectors rename surfaced exactly the gap we needed a protocol for.
Pushing the reconstructed engine history live surfaces a silent rebase failure and a detective story about two backup branches, a stale fork, and feature code that never made it to casehubio.
The first thing devtown needed was a vocabulary — a set of names for the types of work that happen in software development. The original spec had thirteen: code-analysis, security-review, human-approval-gate, notify, ...
A tier-4 health check before Phase 6 finds the README still naming replaced stubs and the emulated mode guide completely absent — accuracy over progress.
The first real code in casehub-aml is intentionally wrong — a naive sequential baseline that makes every missing capability visible before CaseHub layers are introduced to close the gaps.
Starting a new Quarkus application from scratch means making a lot of small decisions before writing any domain logic. casehub-clinical is the clinical trial coordination system I’ve been planning as CaseHub’s first r...
Clearing the backlog before Phase 6 — ADRs written, PixiJS bundle removed, scouting threshold recalibrated, and documentation that had described stubs instead of real implementations finally fixed.
A static ThreadLocal on an @ApplicationScoped bean sidesteps @RequestScoped's dependency on an active HTTP context, making @ProvenanceCapture work in scheduled jobs and @QuarkusTest without a runtime ContextNotActiveE...
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.
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 vocabulary.
Dimension scores are continuous magnitudes, not binary verdicts, so they need a decay-weighted average rather than a Beta accumulator — passing AttestationVerdict.SOUND forces pure time decay and drops the asymmetric ...
A channel can have at most one HumanParticipatingChannelBackend — enforced as a hard constraint at registration — because two human participants on different platforms produce two independent conversations with no way...
Both SSE failures return HTTP 200 with valid-looking data — one because Quarkus adds the data: prefix Claudony was also adding, and one because a static ObjectMapper has no JavaTimeModule and silently returns an empty...
NormativeResolution maps GitHub and Jira close events to speech-act semantics, CRITICAL gets renamed URGENT after finding it borrows ITSM severity vocabulary into a task scheduling context where it doesn't belong.
The scouting calibration was quick — ran the replay dataset, updated three string constants to match the live DRL thresholds, done. The real work was the enemy AI.
Three peer-reviewed papers reach three incompatible conclusions on global trust aggregation — the right answer is a pluggable GlobalScoreStrategy SPI rather than picking one framework's position.
Scoring ten use-case candidates across separate market-fit and community-fit tables reveals AML as the strongest entry point — Java is banking, banking is compliance infrastructure, and developers have built transacti...
Three unrelated CI failures arrive at once — a Friday business-hours assertion, a SNAPSHOT API drift, and a multi-instance default whose effects only appear under concurrent load — all sharing the shape 'works locally...
Reading normative-layer.md, agent-mesh-framework.md, and work-and-workitems.md together confirms vertical coherence — each layer addresses a distinct concern, with SUSPENDED and sub-delegation correctly absent from th...
Every Qhorus attestation was landing on the global "*" capability tag, collapsing capability-scoped Beta distributions into one number — a two-method fix routes attestations to the correct scope by parsing the origina...
Writing the developer guide reveals a missing tool — get_obligation_activity — because Part 6 keeps circling the same question: how do you see everything one obligation touched across all three channels in one call?
castTo(PgConnection.class) fails immediately because Mutiny codegen produces sibling hierarchies, not parent-child — the subscription needs the raw Vert.x delegate to call notificationHandler().
The case context panel ships after three upstream API migrations, but partway through a silent tool-count cap of 50 causes send_input to disappear without any warning from the MCP server.
The CaseChannelProvider.postToChannel path existed but was never connected — WorkerContext.channels was always empty, and the buildContext() result was silently discarded before workers were scheduled.
Switching from polling to server-initiated push exposes three guarantees polling provided for free — restart resilience, catch-up, and identity — that each require deliberate design in a push model.
Both failing tests present misleading symptoms — the watchdog test counts two alerts because the scheduler runs on a separate thread that can see committed test data, not because evaluateAll() was called twice.
The BackPressureFailure filling the CI log is noise — the actual failure is an OptimisticLockException buried further down, caused by the M-of-N coordinator racing against itself during concurrent claim operations.
For capabilityTag, the sentinel "*" is the right answer where NULL was right for scope_key — query patterns use the same operator as any scoped query, and every major policy system already uses "*" for global scope.
The cross-repo dispatch never fired because GITHUB_TOKEN is scoped to the repo where the workflow runs — six repos needed a PAT, and the CI UI was showing success for failed steps because continue-on-error hides step ...
We submitted a PR to fix a null output bug in sdk-java. The maintainer closed it: it wasn't a bug.
A casehub-engine release window triggers twenty-one tasks across five repos in one session — breaking MCP renames, module splits to stop JPA entities leaking onto test classpaths, and a naming audit across the ecosystem.
Three audit findings include a String.format JSON builder that silently corrupts output on non-trivial actor IDs, a bug the auditor described with the wrong mechanism, and a Bayesian mental model error about what a Be...
Redis for distributed SSE fan-out is rejected because it would force two new infrastructure pieces on users who have neither Redis nor MongoDB — a pluggable WorkItemEventBroadcaster SPI defers the choice to the deploy...
An external audit finds two production bugs in ClaudonyLedgerEventCapture: a swallowed persistence exception that silently drops ledger entries, and a MAX() sequence query with no UNIQUE constraint that allows duplica...
Five deferred issues ship in one push, but the session's main discovery is that a sentinel empty-string for global scope was unnecessary — the previous session already solved the uniqueness constraint cleanly with NUL...
Adding caseId and roleName to the immutable Session record touches 20+ construction sites, and the left panel auto-expands with clickable worker rows that reconnect the WebSocket without reloading the page.
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 four test suites.
M-of-N parallel WorkItems ships after rewriting LAYERING.md — the rule "if it touches another WorkItem it's orchestration" was already broken by cascade cancellation, so the real test is whether it imposes ordering or...
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 explicit type check.
The allowed_types field enforces NormativeChannelLayout at the infrastructure level, and a production bug hiding behind test infrastructure surfaces — a @TestTransaction isolation gap was letting the WatchdogScheduler...
I asked for visual verification three times. Each time Claude reported it done. When I sent a screenshot showing blank terrain where minerals should be, the gap was obvious.
The PostgreSQL Testcontainer test finds a HQL date-truncation query that passes on H2 but fails on PostgreSQL — catching a dialect incompatibility that would have reached production undetected.
Six new query tools give the normative ledger its first analytical surface — get_obligation_chain computes participant order and handoff count that cannot be extracted from a single list_ledger_entries call.
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 routing key.
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.
Business-hours SLA and outbound notifications ship, and a notification routing detail that starts as a one-line decision grows into casehub-connectors — a separate repository born from the question of where channel ad...
Extending the ledger to all nine speech-act types reframes Qhorus from audit middleware to normative governance infrastructure — and the trust scoring models in quarkus-ledger turn out to be composable with agent repu...
CaseHub uses worker roles while Claudony tracks session UUIDs — WorkerSessionMapping bridges the two identity systems, with a documented MVP limitation when concurrent same-role workers share a case.
The replay was navigable but half-blind. Units moved. Buildings appeared. But the economy was invisible — no mineral patches, no geysers, no enemy Hatcheries expanding across the map. For a Protoss vs Zerg game, that’...
The visualizer had terrain, buildings, all sixty-five units rendered as sprites. What it didn’t have was any of it moving. Units sat at their spawn positions. The replay was technically running — tracker events advanc...
PendingReply was always instantiating Singh's social commitment model for the QUERY→RESPONSE case — CommitmentStore completes the picture with seven states covering every path a QUERY or COMMAND can reach.
A data-driven spawn rule table is rejected before a line of code — the right answer is that subprocess orchestration belongs to CaseHub, and quarkus-work should expose the primitive that CaseHub reaches for.
Fixing Jlama takes four cascading commits — the ARM_128 UnsupportedOperationException surfaces only after the boot crash is fixed, and requires the native Apple Silicon library rather than the Java Vector API path.
The four CaseHub SPIs wire up cleanly, but @ConfigMapping strict validation fires before library roots register and CaseLedgerEntryRepository turns out not to be a CDI bean despite looking exactly like one.
A plausible commit hardcodes @PersistenceUnit("qhorus") into a generic extension library — caught in git log review before it shipped, with the correct fix being a DefaultBean producer pattern in the embedding applica...
The visualizer had sprites for 65 multiplayer units across Terran, Protoss, and Zerg. Buildings were next — nine of them, all Protoss, rendered as coloured boxes. The goal was to replace the boxes with canvas sprites ...
When we added Zerg sprites and looked at the replay parser, there was a gap nobody had noticed: SCV, Drone, Overlord, Baneling, Phoenix, Oracle, Tempest, Mothership, Warp Prism, Locust, Broodling, Infested Terran, Cha...
Wiring WorkBroker into casehub-engine reveals two undocumented quarkus-work-core behaviours — WorkerCandidate.of() silently drops all selections, and WorkItemStatus.EXPIRED.isTerminal() returns false.
Four research passes through Austin, Searle, FIPA, Singh, and Governatori ground the nine-type taxonomy in a formal obligation lifecycle — each type creates, discharges, or transfers exactly one kind of deontic commit...
Using distinct CDI event record types — full payload, delta, computed-at timestamp — as a strategy selector lets consumers receive only the trust score signals they need without a configuration enum.
Migrating Qhorus to a named datasource hardens into an ecosystem-wide rule — every library owns a named datasource matching its artifact ID — and exposes two direct EntityManager calls hiding behind a clean SPI surface.
E16 is done. Zergling, Roach, Hydralisk, Mutalisk — four draw functions, four distinctly different body plans, all following the palette and dispatch pattern that E14 and E15 established.
Renaming correlationId to traceId fixes a naming collision with established messaging terminology, and a CDI entity listener wires automatic OTel trace ID population at @PrePersist time.
W3C PROV-DM, NIST AI standards, and multi-agent framework research converge on the same answer for LLM agent identity: a stable dereferenceable URI bound to the system configuration, not the session.
Splitting quarkus-work-api into pure contract and quarkus-work-core with CDI implementations reveals that WorkBroker and WorkItems are specialisations of a shared Work substrate that CaseHub also needs.
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.
Migrating to a named datasource exposes an inheritance constraint — AgentMessageLedgerEntry and LedgerEntry must share a persistence unit — resolved by including the ledger package in Qhorus's persistence unit configu...
E15 delivered the Terran side of the cartoon roster: Marine, Marauder, and Medivac. With E14’s Protoss already in — Probe, Zealot, Stalker — we now have the foundations of a real all-race visualizer.
Implementing EigenTrust transitivity reveals that the original paper's trust matrix normalisation produces incorrect results for pre-trusted peers — the fix derives from first principles rather than the published form...
Rating each capability for enterprise applicability forces an honest assessment — EigenTrust transitivity earns two stars in 2026 not because it is wrong but because enterprise AI agent meshes haven't arrived yet.
The ForgivenessParams mechanism gets replaced entirely when Bayesian Beta replaces the coarse-grained scoring model — a principled prior that treats uncertainty correctly makes the forgiveness patch unnecessary.
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 fair approach.
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.
Three CDI-pluggable expiry policies distinguish an idle shell from an autonomously working agent, collected at startup via @Any Instance so new policies are just new beans.
The 39 MCP tools split into 20 pure reactive chains and 19 @Blocking delegates, with the QhorusMcpToolsBase extraction fixing a Java import limitation where inherited nested types cannot be imported via the subclass n...
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 overload.
A confidence-gated routing rule that could be wired in twenty lines becomes quarkus-work-filter-registry instead — because inline logic is a trap that becomes load-bearing and unremovable.
The existing visualizer was a flat 32×32 PixiJS grid — top-down, static camera, unit portraits fetched from Liquipedia. For the replay viewer it worked fine. For cartoon sprites with directional art, it didn’t.
Stripping Panache from all extension entities removes a framework dependency consumers didn't choose, and @NamedQuery replaces the static Panache shorthand with startup-validated queries that fail at boot rather than ...
Converting LedgerEntry from PanacheEntityBase to a plain @Entity removes the Panache dependency that was blocking Qhorus's reactive migration and unblocks any future consumer choosing a different persistence model.
The Merkle sprint deleted LedgerHashChain without updating the integration guide, leaving consumers with compile-error-inducing sample code that pointed nowhere — a systematic cleanup removes every stale reference.
Issue #74 ships five reactive store interfaces and implementations via the subagent workflow — one issue per session after the planning tool hit the 32k output limit generating the full eight-issue plan at once.
quarkus-ledger ships dual blocking/reactive repositories, unlocking Qhorus's reactive migration — and AgentMessageLedgerEntryRepository switches from Panache statics to EntityManager injection to resolve the List retu...
The plan for #16 assumed both replay datasets would feed into ReplaySimulatedGame. That lasted about fifteen minutes. The IEM10 dataset is pre-processed JSON — *.SC2Replay.json — and ReplaySimulatedGame takes binary ....
A fixed send dock in all three mesh views lets humans post into any active channel without switching panels, turning the read-only mesh observer into an active participant.
E12 turned out to be exactly the session I’d predicted: thorough, mechanical in parts, with a couple of genuinely non-obvious moments.
Phase 13 extracts five store interfaces across all Qhorus domains, with in-memory alternatives in a testing module and Query value objects whose matches() predicate applies the same filter logic as the JPQL.
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 implementation.
LedgerEntry exports as W3C PROV-JSON-LD per subject, deduplicating agents across entries and emitting both sequential and cross-subject wasDerivedFrom edges so regulators get a complete provenance graph in one call.
The Merkle Mountain Range structure from RFC 9162 provides O(log N) frontier storage and tamper-evident inclusion proofs signed with Ed25519, making verification genuinely independent of the operator.
Changing the LoopControl interface from a blocking contract to a reactive Uni unlocks four capabilities the classical synchronous blackboard control shell cannot support.
Qhorus embeds into Claudony after a major Quarkus upgrade rewrites the WebAuthn layer and exposes that old credential files stored aaguid without dashes, silently locking users out.
Before touching E11, we ran the post-E10 benchmark baseline. Stalker kiting, focus-fire, and cooldown tracking all in — game loop still at 0ms mean, 1ms p95. Good.
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.
Studying the SWF SDK storage abstraction confirms that WorkItemRepository needs multi-field inbox queries — Map doesn't express them cleanly — so a richer query object replaces a direct SWF port.
A research pass across ten directions produces an ADR grounding the forgiveness mechanism in two parameters — recency and frequency — after finding that severity double-counts a signal already present in the majority ...
Reconciling Qhorus with quarkus-ledger's API changes reveals that ledger write failures should use @Transactional(REQUIRES_NEW) to prevent audit failures from rolling back message delivery.
E9 gave the agent eyes. The enemy staging area went dark behind the fog, and the scout finally had something to actually discover. But when the Zealots came through the ramp, the Stalkers still stood exactly where the...
Before E9, the visualizer showed everything. Every Zealot waiting in the staging area, every enemy unit moving down the ramp — all of it fully visible regardless of where your probes were. As a debugging view that mad...
PR 2 shipped, Flyway is gone, and two CI failures that turned out to be different problems than they appeared.
The wall works. E7 fixed pathfinding through the chokepoint, with a physics constraint as backstop. But the emulated map was still flat — every tile either walkable or wall, no elevation, no tactical geometry. SC2 isn...
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.
The 39 MCP tools get a principled error handling split — @WrapBusinessError for structured-return tools, error-prefixed strings for text-return tools — and the Claudony blocker is a missing Jandex plugin in the runtim...
Something went through the wall. I said it was the probe — consistently, across multiple restarts. Claude kept checking enemy pathfinding.
Phase 12 ships structured observability via AgentMessageLedgerEntry, but the unplanned work is discovering that Claudony's hand-rolled JSON-RPC endpoint conflicts with quarkus-mcp-server-http at the same path.
Fleet Phase 2 adds the fleet sidebar and WebSocket proxy bridge, and the first Playwright test immediately finds a four-month-old bug hiding in displayName() that no one had noticed.
Four runnable examples — expense approval, regulated credit decision, AI content moderation, and document review — together exercise every ledger capability, and the agent: prefix convention derives actorType without ...
Qhorus needing Tarkus's audit patterns prompts extraction into a shared library — LedgerEntry uses JPA JOINED inheritance so each domain adds its own subclass table without touching the base schema.
Three new modules designed and shipped — resilience, EventLog enrichment, and a persistence decoupling spec — plus a conversation that changed the ORM approach entirely.
Fleet Phase 1 extends Claudony to manage sessions across multiple instances — and clears three deferred embarrassments: a hardcoded encryption key committed to the repo, a 30-minute session timeout, and three undocume...
The emulator has been getting more honest about SC2.
The ledger becomes a CDI observer on WorkItemLifecycleEvent — invisible when absent, zero overhead, zero tables — with hash chain and decision context on by default for GDPR Article 22 compliance.
Zero Java to five complete phases in one session — BARRIER channel semantics, wait_for_reply with SSE keepalives, and artefact lifecycle — with code review catching a double-claim race and a UUID format assumption bre...
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.
Write permissions, admin role, rate limiting, and observer mode land via strict TDD, with non-@Tool convenience overloads solving the AddParameter-breaks-existing-tests problem without duplicating @Tool names.
Six phases of quarkus-work ship in one session — the WS-HumanTask research expands the WorkItem model to 27 fields before a line of code is written, and TDD catches two real bugs in Phase 2.
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.
The plan from April 10th didn’t survive.
Forty-two commits close phases 6 through 10 — read-side dispatch filtering handles all three target modes in one private method, and human-in-the-loop approval gates move to quarkus-workitems as the correct domain.
RemoteCC was always a placeholder — Claudony emerged from the colony metaphor and brought a bioluminescent visual language that makes the architecture literal.
Designing the Qhorus multi-agent mesh starts by studying A2A, ACP, AutoGen, LangGraph, and CrewAI — and deciding that Qhorus should be infrastructure orthogonal to all of them, not another orchestration model.
The Enemy Gets a Brief
Watching the Game Without Playing It
Discovering a parallel casehub-engine implementation and charting a 9-phase plan to unify both systems into one coherent design.
The Game Has Stakes Now
Collapsing the lineage graph, redesigning the persistence layer, and researching goal models across BDI, GOAP, CMMN, and HTN.
QuarkusMind — Making the Bot Play
QuarkusMind — Scouting Gets a Mind
StarCraft Agent — Tactics Gets a Brain
StarCraft II Quarkus Agent — Flow Economics Arrives
StarCraft II Quarkus Agent — Drools Strategy Arrives
StarCraft II Quarkus Agent — Day Two: No More Stubs
StarCraft II Quarkus Agent — Getting Replays the Long Way Round
StarCraft II Quarkus Agent — Phase 1: Wiring Real SC2
StarCraft II Quarkus Agent — Phase 0: The Mock That Runs
StarCraft II Quarkus Agent — Day Zero
Two patterns from very different traditions — Blackboard Architecture and CMMN — and why they belong together for agentic AI.
One session, 73 files, 14,003 lines of code — what started as a request for a sketch became a working framework.