Skip to content

Releases: sudoitir/artemis-studio

2026.09.14

2026.09.14 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Sep 14:51

Fixed

  • Name the right capability in the console's uncertainty banner (c2add88f)

    The SQL Console is gated on message I/O, which is unproven until a management
    write has been attempted — but the banner said no management read had been
    attempted, which is not what is unknown and not what settles it. It also
    promised the first query would settle it, which a read cannot do.

  • Keep an endpoint box inside the slot the layout reserved for it (d41a3fc7)

    An endpoint whose name wrapped and which carried an error sentence — a stopped
    backup, exactly the case the view exists for — grew taller than the 160px the
    layout allots between the serving and standby rows, so it was drawn on top of
    the box below it and out through its own pair's border.

    The box is now pinned to the geometry layout.ts publishes (260x132) and the
    two variable-length lines clamp to two lines each, with the full text on the
    title and, as before, in the node's accessible name. Split-brain endpoints were
    laid out 150px apart while being 190px wide, so those overlapped too; they are
    now pitched by the box width.

2026.09.13

2026.09.13 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Sep 14:16

Fixed

  • Take the clock from Studio, and let the operator pick the timezone (6a970c39)

    Every duration, expiry check and metric window in the UI was computed against
    the browser's clock. An operator whose workstation ran four minutes fast saw
    every request-reply flow age inflated by four minutes, a live API key rendered
    as expired, and an empty metrics chart with nothing saying why — the window it
    asked the server for had not happened yet.

    Studio already refuses to trust a broker's clock (ADR-0053). The browser is one
    more foreign clock, and it was the only one still taken on faith.

    What changes for you:

    • Ages, staleness labels and token expiry now follow Studio's clock, not the
        machine the browser runs on. On a correctly-synchronised workstation nothing
        moves; on a skewed one, the numbers become right.
    • The metrics window and the queue drawer's chart are quantised on the server's
        clock, so a skewed workstation no longer requests a range the server has no
        samples for.
    • Timestamps now render in your own timezone by default, detected from the
        browser, where they were previously always UTC. Settings → Display picks a
        different one, including UTC to match container and broker logs. The choice is
        per-browser, needs no permission, and is never reset once made.
    • Every absolute timestamp now names the offset it is written in (Z, +03:30)
        and is rendered to whole seconds, where before some carried milliseconds and
        some did not.
    • The metric charts previously drew their axis in the browser's local zone while
        every table beside them was UTC, with nothing disclosing the difference. Both
        now follow the chosen zone.

    How it works: a new GET /api/v1/time returns Studio's clock, and the client
    measures its own offset NTP-style with round-trip bracketing — the same
    estimator and the same constants as ClockOffsetRegistry, so the two halves of
    the system agree about method. A reading is only allowed to teach the estimate
    when its round trip is at or near the best seen; an offset inside its own error
    bar is held at zero rather than correcting by noise. The SSE ping already
    carried the server's clock and the client discarded it; it is now a drift
    detector that asks for a real probe, never a measurement of its own, since a
    one-way frame cannot measure its own latency. A wall-clock step — a laptop
    waking, an NTP correction — is caught by comparing Date.now() against
    performance.now(), the client-side MonotonicClockWatch, and discards the
    estimate rather than slowly unlearning it.

    web/src/app/time.ts states the rule for the whole frontend: durations and
    expiry against a server timestamp use serverNow(); a browser-stamped instant
    entering such a comparison (TanStack's dataUpdatedAt is the only one) is
    normalised with toServerMs() at the boundary; monotonic work keeps using
    performance.now(). Three duplicate "ago" formatters and seven copies of the
    absolute-timestamp formatter are folded into it.

    Known and deliberately out of scope: the queue detail drawer's chart window is
    memoised on the range spec alone, so it is fixed at first render and does not
    advance while the drawer stays open. That predates this change.

2026.09.12

2026.09.12 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Sep 13:09

Added

  • Query messages across a cluster in SQL, with a live tail and an opt-in index (46c44883)

    The SQL Console is a new screen at Clusters → SQL Console. It answers questions
    that previously meant guessing a queue, walking pages by hand, and writing a JMS
    selector that cannot see a message body at all:

    SELECT messageId, timestamp, props.tenant, body
    FROM   "ORDER.*"
    WHERE  priority > 4 AND body->>'orderId' = '4471'
    ORDER BY timestamp DESC
    LIMIT  500
    

    What it costs a broker is stated before it runs. The EXPLAIN strip says which
    predicates the broker evaluates for free, which ones force Studio to read
    messages, and roughly how many that is — and a query over the ceiling is refused
    with the estimate and how to narrow it, rather than being run and truncated. The
    fan-out is the existing browse loop behind the existing per-node rate limiter, so
    a runaway query throttles itself against the broker.

    Every result says what it could not see. A node that did not answer is named
    rather than left out, a result that stopped at a bound says which bound, a body
    the management channel truncated is flagged because a body predicate over it can
    be a false negative, and an empty grid distinguishes "no queue matched" from "the
    queue is empty" from "a node was unreachable".

    Live tail streams matches as they arrive. It is a sample, not a capture: Studio
    re-reads the queues every few seconds, and a message that arrives and is consumed
    between two reads is never seen. The console says so permanently while tailing,
    and reports the observed gap where it can measure one. A dropped connection is
    not silently reopened — reopening would re-run an audited fan-out nobody asked
    for twice.

    The message index is off until you turn it on, per queue, in Settings → Message
    index. It keeps a copy of the messages Studio observes — headers, properties and
    bodies — so the console can still find a message the broker has already handed
    out. Because that is stored application payload, creating a subscription needs
    the settings write permission, is audited, states what it stores before it is
    confirmed, defaults to seven days' retention, and can be deleted with everything
    it captured in one action that tells you the count first. Any indexed row can be
    checked against the live broker: present, gone, or — when the read could not
    settle it — unknown, never a guess.

    Everything here is read-only. Acting on a result row goes back through the
    existing message operations, with their dry run, bulk cap and audit record.

    Requires a database migration (changeset 021), which Studio applies on startup.
    It creates the pg_trgm extension; a database user without permission to do that
    must have it created for them first:

    CREATE EXTENSION IF NOT EXISTS pg_trgm;
    

    New settings live under artemis-studio.sql: target, scan, row and timeout caps,
    the per-user concurrent query limit, the cost ceiling and the tail interval. The
    packaged defaults are deliberately conservative.

2026.09.11

2026.09.11 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Sep 04:39

Added

  • Close a connection, a session, or an address's consumers (b91c6d88)

    Studio could tell you which consumer was holding up a queue and could list
    every connection behind it. It could not do the one thing that finding
    implies. Closing a wedged consumer's connection returns its in-flight
    messages to the queue so a healthy instance can take them — the most common
    3am intervention on an Artemis cluster, and the reason people kept a JMX
    console open next to Studio.

    The connections, sessions and consumers views gain a row action; the
    addresses view gains a cluster-wide "close consumers" action. All four
    preview before they act.

    What to know before you use it:

    • A close by id names a node. This is the one mutating route in Studio
      that is not a cluster-wide fan-out. A connection identifier is issued by,
      and meaningful only on, the node that accepted the connection. Only the
      address-scoped close names a cluster, and it reports per node.
    • A target that has already gone is a success, not an error. Rows come
      from a cache, so by the time you click, the connection may be gone. The
      requested state — that connection is not open — holds. Nothing retries: an
      identifier can be reissued, so a retry may land on a different application.
    • Closing a consumer moves messages. Its in-flight messages return to
      their queue with an increased delivery count, which can push one past its
      maximum delivery attempts and into the dead-letter queue. The confirmation
      states this, with the count where the broker reports it and an explicit
      "not reported" where it does not.
    • You confirm against the client id, not the connection id. An operator
      cannot verify that a3f1c9de is the right connection; they can recognise a
      client id or a remote address. The audit row records the same, read
      immediately before the close, because afterwards the identifier resolves to
      nothing.
    • The address-scoped close is capped. It previews per node and is refused
      above safety.bulk-cap without an explicit override. A node that could not
      be counted also demands the override: an incomplete total is a floor, not a
      figure, and passing the cap on the nodes that happened to answer would wave
      through exactly the close whose blast radius is unknown.

    A new permission, connection:close. Grant it explicitly — no message or
    queue permission implies it. Authority over a cluster's messages says nothing
    about authority to disconnect the applications producing them.

    MCP gains connection_action, declared destructive and not idempotent,
    previewing by default. Its confirmation is the client id the preview
    returned, so a model that guesses cannot close anything.

    There is deliberately no "close all slow consumers". Slow-consumer detection
    has false positives by construction, and an operation that selects its own
    targets from a heuristic turns every one of them into a disconnected
    production application. Detection informs; you name the target.

    See ADR-0057.

2026.09.10

2026.09.10 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Sep 03:54

Added

  • Make refresh, pause and the metric charts tell the truth (b25868e7)

    The shell reported freshness, but three of its claims were wrong, and the
    metrics page was wrong in a way a screenshot hides.

    Refresh now means your refresh. The control's busy state came from
    cache-wide isFetching, so it spun on every background poll — a spinner that
    never stops says nothing. It now tracks only the promise the operator started,
    floored at 350ms so a fast refetch reads as an acknowledgement rather than a
    flicker, and repeated activation joins the running refetch instead of aborting
    and restarting it (cancelRefetch: false).

    Pause now holds. It stopped intervals but not mounts, so pausing and then
    navigating silently resumed. refetchOnMount goes through the same seam, gated
    so a query that has never resolved still fetches once — pausing a screen to stop
    it moving is not asking for an empty one. The paused control also renders
    differently, rather than differing only in aria-pressed.

    Metric charts carry time. The x-axis was array position, so an omitted
    bucket rendered flush against its neighbour — the metrics capability requires a
    cold subject to show a gap, and it could not. The axis is now a numeric time
    scale over the requested window. The live window was also frozen at page-open by
    a useMemo that never re-ran; it now advances, quantized to the bucket width so
    the query key changes once per bucket rather than once per second. A failed read
    rendered as "No samples yet" — an absence presented as a fact — and now states
    the failure.

    The dashboard around them is rebuilt: current depth, added/s, acked/s and
    consumers as stat tiles that say "Not sampled" rather than showing zero; each
    chart a titled panel with its unit; a table view of the window; and ?subject=
    to scope the whole page to one queue, linked from the queue drawer.

    Bounded views. Requests, events, audit and DLQ rendered every row they were
    given. They page now, through one shared pager, with events and audit moved onto
    the virtualised grid. Above 24 nodes the topology canvas collapses each pair to
    one node, drops edge labels, renders only what is visible, and says that detail
    has been reduced.

    Two fixes found while shooting the screenshots. The command palette mounts on
    every route and asked for /clusters//queues outside a cluster — a 400, and one
    errored observed query put the whole shell into its offline state, so every
    cluster-less screen claimed Studio had lost the brokers. And the consumer chart's
    y-axis rounded fractional ticks to integers, printing "0" five times beside bars
    of visibly different heights.

    Colour. The latency panel used the reserved warning and danger colours as
    series colours; p50/p95/p99 are now a validated sequential blue ramp. The depth
    chart's two neutral series failed the normal-vision separation floor and are now
    one hue distinguished by mark shape. Both checked with the palette validator in
    both schemes rather than by eye.

    Release. The Docker Hub description step has failed with Forbidden on every
    release, hidden by continue-on-error. It now points at a real docs/dockerhub.md,
    completes relative URLs so the screenshots resolve, and fails loudly. The
    credential must be a PAT with read, write and delete scope — the description
    endpoint rejects a repo-scoped token. It is the last step of the release job, so
    a failure there cannot burn a version.

    Screenshots are recaptured from a four-node cluster carrying real traffic:
    just demo brings up two live/backup pairs, registers them through Studio's own
    API and drives messages with the broker image's own client — nothing is written
    to metric_sample by hand — and just shots captures the four README images.

    ADR-0055 records the time axis and the quantized window. ADR-0056 records bounded
    views and topology level of detail.

2026.09.9

2026.09.9 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Sep 20:05

Breaking

  • Make discovery a tool, and generate the surface from one catalogue (06945d2d)

    The MCP tool listing is sent to a model on every conversation that touches
    Studio, before it has asked for anything. It is now 1696 tokens across 13 tools,
    down from 2115 across 14 — a fifth off every session — and it gained a discovery
    tool while shrinking.

    studio_help is the new route to the detail the schemas leave out. Call it with
    no topic for an index of every tool, or with a tool name for that tool's accepted
    values, JSON body shapes and semantics.

    ADR-0050 had put that detail in the studio://tools resource, on the reasoning
    that a host fetches a resource once and keeps it. That is true of hosts that read
    resources. resources is an optional server capability and nothing in the MCP
    specification obliges a client to call resources/read — ever. On a host that
    skips them, ADR-0050 did not make discovery progressive; it made it absent, and a
    model was left inferring valid values by triggering rejections. Tools are the one
    part of MCP every host implements, so the detail moved behind one. studio://tools
    remains as a generated mirror that nothing depends on.

    Because that channel is now reliable, every other schema dropped the hedging text
    it carried in case the resource was never read — spelled defaults, type codes,
    "see studio://tools" pointers. The help tool costs about thirty-five tokens and
    licensed stripping several hundred, which is why the listing is smaller despite
    being one tool larger.

    Rejections now name studio_help alongside the values they would have accepted,
    so a wrong guess is a recovery rather than a retry loop.

    The server instructions block is generated from the same catalogue instead of
    being retyped in application.yml. The hand-written one had already drifted: it
    omitted queue_lifecycle and message_body and never named a discovery route.
    Under a host that searches tools rather than sending the whole listing, that text
    is the only thing guaranteed to be read, so a stale copy did not merely go out of
    date — it told a model that two capabilities the product has did not exist. The
    build now fails when a registered tool is missing from the catalogue.

    Two further checks are enforced: no tool may declare itself both read-only and
    destructive, and a tool's declared posture must match the catalogue's. A host
    gates a whole tool on one destructiveHint, so a read reachable through a tool
    that can purge would make every read prompt the operator — which is how an
    operator is trained to reflex-approve the purge.

    The budget ceilings ratchet down with the win rather than banking it as headroom:
    per-tool 200 → 175, average 160 → 135, calibrated against a measured run.

Added

  • Make discovery a tool, and generate the surface from one catalogue (06945d2d)

    The MCP tool listing is sent to a model on every conversation that touches
    Studio, before it has asked for anything. It is now 1696 tokens across 13 tools,
    down from 2115 across 14 — a fifth off every session — and it gained a discovery
    tool while shrinking.

    studio_help is the new route to the detail the schemas leave out. Call it with
    no topic for an index of every tool, or with a tool name for that tool's accepted
    values, JSON body shapes and semantics.

    ADR-0050 had put that detail in the studio://tools resource, on the reasoning
    that a host fetches a resource once and keeps it. That is true of hosts that read
    resources. resources is an optional server capability and nothing in the MCP
    specification obliges a client to call resources/read — ever. On a host that
    skips them, ADR-0050 did not make discovery progressive; it made it absent, and a
    model was left inferring valid values by triggering rejections. Tools are the one
    part of MCP every host implements, so the detail moved behind one. studio://tools
    remains as a generated mirror that nothing depends on.

    Because that channel is now reliable, every other schema dropped the hedging text
    it carried in case the resource was never read — spelled defaults, type codes,
    "see studio://tools" pointers. The help tool costs about thirty-five tokens and
    licensed stripping several hundred, which is why the listing is smaller despite
    being one tool larger.

    Rejections now name studio_help alongside the values they would have accepted,
    so a wrong guess is a recovery rather than a retry loop.

    The server instructions block is generated from the same catalogue instead of
    being retyped in application.yml. The hand-written one had already drifted: it
    omitted queue_lifecycle and message_body and never named a discovery route.
    Under a host that searches tools rather than sending the whole listing, that text
    is the only thing guaranteed to be read, so a stale copy did not merely go out of
    date — it told a model that two capabilities the product has did not exist. The
    build now fails when a registered tool is missing from the catalogue.

    Two further checks are enforced: no tool may declare itself both read-only and
    destructive, and a tool's declared posture must match the catalogue's. A host
    gates a whole tool on one destructiveHint, so a read reachable through a tool
    that can purge would make every read prompt the operator — which is how an
    operator is trained to reflex-approve the purge.

    The budget ceilings ratchet down with the win rather than banking it as headroom:
    per-tool 200 → 175, average 160 → 135, calibrated against a measured run.

2026.09.8

2026.09.8 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Sep 19:30
Release 2026.09.8

2026.09.7

2026.09.7 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Sep 19:17

Added

  • Queues and addresses can now be created, destroyed, reconfigured, paused and
    resumed from Studio
    , without dropping to the artemis CLI 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=true names 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 same
    safety.bulk-cap as any other bulk destructive operation and needs the same
    explicit override above it.
  • Four new permissionsqueue:create, queue:delete, queue:update and
    queue:pause — grantable globally, per environment, or per cluster. Holding
    queue:purge does 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 the
    cluster://{id}/nodes/{nodeId}/settings resource. 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

  • managementWrite is no longer inferred from a read. It was reported as
    available whenever a read-only listNetworkTopology() 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 the
    broker.xml that would grant it.

    A connection previously shown as AVAILABLE on inference alone will now read
    UNKNOWN until 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://tools resource that a client reads only when it needs them
    (ADR-0050). No tool was removed.

Added

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 !== AVAILABLE and 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)

    useMetrics passes number | false to poll() so an absolute (non-live)
    chart range never polls, but poll() only accepted number, so the frontend
    build failed to typecheck. Widening the parameter keeps the pause seam intact:
    a false interval stays disabled whether or not polling is paused.

2026.09.6

2026.09.6 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Sep 14:25
Release 2026.09.6

2026.09.4

2026.09.4 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Sep 13:56

Breaking

  • An expectation's reply address is now a set of patterns. The request-reply
    expectation API field replyAddress (a single string) is replaced by
    replyAddresses (an array of strings) on the create, update and read payloads.
    Any client posting replyAddress must send replyAddresses: ["<the old value>"]
    instead, or [] where it previously sent nothing. Stored expectations migrate
    themselves — an existing reply address becomes a one-entry set — so no operator
    action is required in the UI.

Added

  • One expectation can trace reply queues you cannot list in advance. Reply
    addresses are now a set, and each entry may be a pattern: orders.reply.* covers
    a reply queue per responder, including ones created after you declared it. This is
    what makes tracing work against a deployment whose reply queue is named after the
    broker node or the client host, where any fixed list is stale as soon as something
    is redeployed. * matches any run of characters and matching is anchored at both
    ends; Artemis's # is not a wildcard here. The form shows what a pattern currently
    resolves to as you type it, and says so when it matches nothing yet — which is
    normal, not an error.

  • A completed flow records which reply queue answered it. When more than one
    reply address is in play, the flow takes its reply destination from the reply that
    joined it, so you can see which responder served a given exchange.

  • "Check connection" now tests the Core connection too, and registration waits for
    it.
    The check opened no Core connection at all, so it reported nothing about the
    channel that carries notifications and faithful message I/O — a wrong Core account, or
    the same wrong password entered twice, passed the check and only failed after the
    cluster was registered. The check now opens and closes a real subscription to
    activemq.notifications, and Register cluster stays disabled until a check of the
    exact details in the form has passed, saying which of those it is waiting for. Editing
    a URL, a username or a password invalidates the previous check rather than carrying it
    over.

  • A separate broker account for the Core connection. Settings can now rotate the
    Core-protocol credentials independently of the management (Jolokia) ones. Set these
    when your management account is also the broker's <cluster-user>: Artemis reserves
    that account for inter-node traffic and refuses it over Core with AMQ229099, which
    previously left the notification subscription failing with no way to fix it short of
    re-registering the cluster.

  • Pick an address instead of typing it. The request and reply address fields on the
    Requests screen now suggest the cluster's own addresses as you type, each with its
    routing type, current depth and how many nodes carry it — enough to tell a request
    queue from a reply queue without leaving the form. You can still type a name that does
    not exist yet; the field says it matched nothing rather than refusing it. The
    suggestions can be narrowed to anycast or multicast.

Changed

  • The broker-capabilities notice can be dismissed. It stays dismissed for the rest of
    your session and comes back when you sign out, when someone else signs in, or when a
    different capability starts falling short — so waving away a known gap never hides a
    new one.

Fixed

  • Every node serving a traced address is now sampled. Studio browsed only the
    first active node of a cluster, so in a multi-primary cluster the request and reply
    traffic on the other nodes was never read and the correlation identity that only
    browsing supplies was missing for most exchanges.

  • A reply consumed faster than the sampler ticks is no longer missed. A delivery
    on a declared reply address now counts as a reply observation, alongside the
    existing browse. It carries no correlation id, so it completes a flow only where
    sampling already identified the request — coverage, not a replacement for browsing.

  • Request-reply sampling failures are reported. A failure was swallowed at debug
    level, so a correctly-configured-looking expectation produced no flows and said
    nothing about why. Failures now log a warning naming the expectation and the node,
    rate-limited so a node that is down for an hour does not flood the log.

  • Capabilities are assessed against a live node. Studio probed whichever node sorted
    first by name. On a cluster whose backup sorts before its primary that meant probing a
    passive backup, which registers no acceptor and no address MBeans — so Studio reported
    "CORE acceptor not found" and "activemq.notifications address not found" about a broker
    where both were present.

  • A Jolokia agent that labels its JSON text/plain is understood. The agent bundled
    with Artemis 2.39 answers a valid Jolokia response with
    Content-Type: text/plain;charset=utf-8 where 2.44 sends application/json. Studio's
    client only accepted the JSON content types, so every response from the older broker
    failed to convert and a healthy cluster was reported as "the broker answered, but not
    with a Jolokia response".

  • The MCP client configuration example is valid. It omitted "type": "http", which
    clients reject.

  • A broker that refuses the connection now says so. Registering a cluster against an
    Artemis console that rejects the credentials reported "The broker answered, but not with
    a Jolokia response"
    — a message that sent operators looking for a proxy or a CORS problem
    that was not there. Studio now classifies the refusal from the HTTP status rather than
    from an exception subclass, and repeats what the broker itself said: the
    Hawtio-Forbidden-Reason header the Artemis console sets on its bare 403, and any
    WWW-Authenticate challenge.

  • A management URL pointing at the console instead of the agent is named as such. Studio
    no longer follows redirects to the console's login page and then reports the resulting
    HTML as a bad Jolokia response; a redirect is reported as the wrong path, with the
    location the broker sent. A seed typed as host:port/console is completed to
    /console/jolokia rather than left to fail.

  • Tracing an already-traced request address returns a conflict, not a server error.
    Adding the same request address twice failed with an HTTP 500 whose body said nothing;
    it now returns 409 naming the address, and the Requests screen shows that message. The
    enable/disable switch and the remove button on that screen also report their failures
    instead of appearing to do nothing.

  • The config diff table is readable again. Long acceptor values no longer take the whole
    row and squeeze the key and status columns to one character per line; wide values scroll
    inside the section, and a key too long for its column is revealed on hover.