2026.09.7 — 2026-09-06
Added
- Queues and addresses can now be created, destroyed, reconfigured, paused and resumed from Studio, without dropping to the
artemisCLI or a JMX console. A command names a cluster, not a node: Artemis cluster nodes each own their own queues, so the operation fans out to every live node and the result is a per-node outcome rather than a single yes or no. A node that was not live is reported as skipped, never as a failure, and re-running after a partial application converges. Nothing is rolled back on a partial failure — a destroyed queue cannot be restored, and a compensating create would be a different state dressed up as the original — so the divergence is reported and left in your hands. - Every lifecycle command has a preview.
?dryRun=truenames the target nodes and, for a destroy, the messages that would be lost on each, without touching any broker. Destroying a queue destroys its messages, so it is counted against the samesafety.bulk-capas any other bulk destructive operation and needs the same explicit override above it. - Four new permissions —
queue:create,queue:delete,queue:updateandqueue:pause— grantable globally, per environment, or per cluster. Holdingqueue:purgedoes not imply any of them: emptying a queue and destroying it are different authorities. They appear in the role editor with no upgrade step. - One MCP tool,
queue_lifecycle, covering every kind. It previews by default, and turning the preview off for a destructive kind additionally requires a confirmation matching the target's name. - A node's effective broker configuration is now readable on its own — the settings it is actually running with, as the broker resolves them — at
GET /api/v1/clusters/{id}/nodes/{nodeId}/config, and to an MCP client as thecluster://{id}/nodes/{nodeId}/settingsresource. Previously configuration could only be seen by diffing two nodes against each other. - A paused queue is now identifiable as paused in the cluster's queue view, including when it is paused on some nodes and not others.
Changed
managementWriteis no longer inferred from a read. It was reported as available whenever a read-onlylistNetworkTopology()call succeeded, which proves only that Jolokia is not under a read-only policy — not that any particular operation is permitted. It is now unknown until a management write has actually been attempted on that connection, available once one has succeeded, and unavailable once one has been refused for an authorization reason, with thebroker.xmlthat would grant it.A connection previously shown as
AVAILABLEon inference alone will now readUNKNOWNuntil its first write. This is a correction, not a regression — the previous value was not evidence-backed. Write operations are still offered while it is unknown, with the uncertainty stated: absence of evidence must not block you. A write that fails for any other reason — an unreachable broker, an argument the broker rejects — leaves the assessment alone, so one bad request cannot permanently disable a button.Warning and danger text is legible in the light theme. Measured against the WCAG 2.2 AA floor rather than assumed: warning text was 2.13:1 and danger text 3.84:1 on white, both under the 4.5:1 minimum for body text. They are now 6.67:1 and 5.46:1, keeping their hue. Purely graphical marks — chart axes, graph edges, the alert dot — are unchanged, since the text floor does not apply to them.
The MCP tool listing budget now scales with the number of tools rather than being a fixed ceiling, and enum values and JSON body shapes moved out of the tool schemas into a
studio://toolsresource that a client reads only when it needs them (ADR-0050). No tool was removed.
Added
- Clock and rr fix (b8a33d32)
Changed
Add queue and address lifecycle across a cluster (77ed26bf)
Studio could read every queue in a cluster and mutate every message in one, and could not create, delete, pause or reconfigure the queue itself. That was the largest remaining gap between an observability tool and a management tool, and the one the product name already promises.
A lifecycle command names a CLUSTER, not a node. Artemis cluster nodes each own their own queues, so the operation fans out to every live node — resolved from polled topology, never from configuration — and the result is a per-node outcome list rather than a boolean. A node that was not live is reported as skipped, not failed: it never received the command. Nothing is rolled back on a partial failure, because a destroyed queue cannot be restored and a compensating create would be a different state dressed up as the original; the divergence is reported instead, and one audit row carries the whole fan-out.
Verified against the broker rather than assumed, which changed the design three times (ADR-0049, and the change's design.md records the method):
- Every positional createQueue/updateQueue overload is deprecated as of 2.56; the current API is JSON QueueConfiguration, and createQueue(cfg, ignoreIfExists) supplies the already-in-state semantics directly.
- updateQueue REPLACES rather than merges. A document omitting a field clears it, so sending only an operator's changed fields silently destroyed the queue's filter. The update path now reads, merges, and sends the whole config.
- The filter is mutable; only the routing type is not. The spec asserted both were immutable and has been corrected.
managementWrite stops being inferred from a read-only listNetworkTopology() call, which proves only that Jolokia is not under a read-only policy. Nothing depended on that guess until a create button did. It is now UNKNOWN until a write has been attempted, AVAILABLE once one succeeds, and UNAVAILABLE only on an authorization refusal — so one malformed request cannot permanently disable a button. Evidence is persisted on the cluster, because the probe makes no write and must not. Three existing screens gated on
!== AVAILABLEand would have locked operators out of working brokers; they now block only on a known refusal and state the uncertainty otherwise.Also folded in, at the maintainer's request:
- A node's effective broker configuration is readable on its own, over HTTP and as an MCP resource. ConfigReader already read exactly this for the two-node diff and had no endpoint of its own.
- The MCP listing budget scales per tool instead of a flat ceiling, and enum members and body shapes move to a studio://tools resource a client reads only once it has chosen a tool (ADR-0050). The flat 2000-token limit had no headroom left, so any new capability would have failed it. No tool was removed.
Light-theme warning and danger text were measured, not assumed, and failed: 2.13:1 and 3.84:1 against a 4.5:1 AA floor. No shade of Mantine's yellow or orange ramp reaches 4.5:1 on white, so the warning needed a dark amber literal. Now 6.67:1 and 5.46:1; graphical marks stay on the bright ramp.
Propose MCP tool grouping and progressive discovery (3bd1b31b)
The MCP surface is 14 tools and ~2100 tokens of tools/list, re-sent on every conversation before a model has asked for anything. Four more roadmap changes each add tools, so the listing roughly doubles on the current trajectory — at which point cost matters and, more importantly, so does selection accuracy: a model choosing between thirty flat tools picks worse than one choosing a domain and then an operation. On a surface that can destroy a queue, that is a safety property.
This decides the shape before the surface gets there rather than after.
Deliberately a thin proposal — nothing is implemented. The answer depends on what the MCP specification actually guarantees about tools/list_changed and what the Spring AI MCP version here actually supports, and both are facts to verify rather than assume. proposal.md records that the change must be brainstormed first, the protocol and library checked through ctx7, tasks.md rewritten to match, and only then implemented.
design.md frames six open questions rather than answering them, and records the constraints any answer must survive: no capability leaves the surface, progressive discovery may not be mandatory, discriminators stay validated server-side, and the budget stays enforced by a test.
Fixed
Accept a disabled interval in the poll() pausable-refetch helper (adb10625)
useMetricspassesnumber | falsetopoll()so an absolute (non-live) chart range never polls, butpoll()only acceptednumber, so the frontend build failed to typecheck. Widening the parameter keeps the pause seam intact: afalseinterval stays disabled whether or not polling is paused.