2026.10.64 — 2026-10-29
Breaking
An unreported depth is unknown, not zero (8a229a29)
A backlog, a dead-letter depth or a group lag the broker did not report is left empty. Totals add only the depths that were reported, and a slow-consumer rule does not fire on a placeholder. A Kafka group with no committed offset has no lag to report; one whose topics are only partly known says how many it left out. Health no longer treats partitions that have not been sampled as a failed read.
Recreate the database. The scrape baseline no longer stores an unknown backlog as 0.
Store message deliveries as a count per destination and interval, not one row per message (a584e0d4)
A message delivery is the one broker notification sent per message, and every one of them was a broker_event row: two hours of demo traffic wrote 1.1 million rows (1.1 GB). Deliveries are now counted in memory per destination and subscription, and each flush writes one openbroker.message.delivered row per destination that saw deliveries, with the count and the interval (from, to) in its data. Every other event type is still stored verbatim, and request-reply tracing still sees each delivery live.
Name the check failure for brokers that advertise an address Rahdar cannot reach (9a46f38f)
When the bootstrap server accepts a connection and the check still times out, the brokers advertise addresses Rahdar cannot reach. The failure's cause was TIMEOUT with only its next step precise; it is now ADVERTISED_UNREACHABLE, and its message opens with 'Brokers advertise addresses Rahdar cannot reach.'
List a Kafka cluster's transactions, and abort only one the coordinator has missed (c6314b97)
An assistant could abort a transaction but not find one. kafka_list_transactions lists a Kafka cluster's transactional ids with state, start, timeout, whether each hangs and the partitions it holds back, bounded by a limit and a cursor, with hangingOnly to keep the ones that matter.
The coordinator aborts an open transaction past its timeout by itself within seconds, so an open one is information, not an incident. A transaction now counts as hanging, and can be aborted, only when it is still open a minute past its timeout, which means the coordinator has missed it; the preview says so otherwise. The design and the specs record the model, and the planned hanging-transaction find that will join the list.
Browse a group's subscription, and report what a log purge skips (45e34f19)
A partitioned subscription's id (kafka.group-topic/<group>%2F<topic>, or a share group's) answered 400 on browse and on a record's detail, because the route wanted a destination. It now browses and opens the records of the topic the subscription reads, found from the driver's own breakdown, and the page says where the group stands on the partition (log.subscriptionPosition: its committed offset, or a share group's start offset).
A purge of a partitioned subscription moves the position and deletes nothing. It now reports the records it passes over as skippedCount (single purge) and as skipped (a bulk item, expected in the plan and reported once run), while affectedCount and affected keep meaning what was destroyed, which is 0 here. The bulk cap counts destroyed messages only, so a log purge is not capped, needs no override and adds nothing to a bulk run's estimate.
Give every API schema a name of its own (64902fd7)
Five pairs of different records were published under one schema name, so the document described only one of each pair and an endpoint of the other showed the wrong shape. They are renamed: the system listing's SystemView is SupportedSystemView, the configuration's FindingView is ConfigFindingView, the query console's PlanView is QueryPlanView, the flow's Delivery is FlowDelivery and the job's Outcome is JobOutcome. ApiSchemaNamesTest now has no exceptions. Also ticks 4.1 to 4.3 and drops a stale exemption of the coverage test.
Abort only a transaction that is open and past its timeout (91942f2b)
An abort fenced whichever transaction was named, including one whose producer was still working. It is now refused (409) unless the transaction is open and has outlived its timeout, which is the one that holds readers back, before the approval gate and the audit row, and again when an approved request replays. The preview says which it is and why a transaction is not aborted.
Say which topics a part-way offset reset moved (41308015)
A reset of a group over several topics that failed after some topics moved audited the whole reset as failed with nothing about what had moved, and answered with the error alone. The audit row now records the topics that moved and those that did not, with their offsets before and after, and the answer is a partial outcome naming both with the cause. A reset that fails on its first topic is refused as before.
Give the Kafka group and quorum schemas names of their own (4da59e46)
Two different records were published as PartitionLag, so the document showed one shape for both and a group's partition reason was typed as a required string. The group's partition lag is now GroupPartitionLag, and the broker quorum is BrokerQuorum with QuorumVoter. A test fails when two API types share a schema name, so the next clash is caught when it is written.
Pin a truncate to the preview it was confirmed from (ab3d2bc7)
A real truncate re-previewed and used that preview's own etag, so the cut an operator confirmed was never tied to what they were shown. The dry run now returns an etag, and a real run needs it: a log that moved since is refused as stale (412) and an approved replay carries it. A cut that names a negative offset or a partition the log does not have is a 400 before anything is cut, and any failure closes the audit row as failed rather than leaving it open. A stale preview is now one shared 412 for every feature.
Select and act on subscriptions by their full id (92c4a122)
A bulk action sends the ids of the subscriptions it acts on (kind/path, such as kafka.group-topic/billing/orders) instead of their names, and a subscription selection handed to a feature is { kind: 'ids', ids }. A Kafka group that reads two topics is two subscriptions, named in the preview and the run as group/topic. A purge of a log shows what it skips and that nothing is deleted, an active group is refused with its members, and a group that began rebalancing is a failed item with the driver's reason.
Act on each subscription by its id, and purge a log through the log purge (205daf09)
A bulk run named a subscription by its queue name and purged it through the queue purge on every node. On a Kafka cluster that bypassed the log purge's approval gate and its active-members refusal, and two subscriptions of one group (one group reading two topics) collided on the same name.
- Bulk items are keyed by the subscription's canonical id (artemis.queue/orders, kafka.group-topic/billing/payments). The preview request and the selection take
idsin place ofnames; an id that is not one is a 400. - A purge of a subscription of a partitioned log goes through the log purge and its gate, once for the cluster, and audited like a single purge. A group with members is refused in the preview with the member count; a rebalancing group is that item's failed outcome with the driver's detail. The estimate says how many records the purge skips, and that none is deleted.
- Pausing, resuming and deleting a log subscription are refused in the preview. Artemis queues behave as before.
- Bulk items are keyed by the subscription's canonical id (artemis.queue/orders, kafka.group-topic/billing/payments). The preview request and the selection take
Read Kafka consumer groups through plugin messaging (e6b8ded9)
A plugin names the subscription it receives from by its shared-API id, so a registration can read a Kafka consumer group as well as an Artemis queue.
- RegistrationSpec.source, MessageRegistration.source and PluginMessage.source are a SubscriptionId(kind, path) instead of a ResourceRef. ResourceRef stays the key of a permission check and the target of a send.
- A partitioned log is read once for the whole cluster, by the instance that owns it: MessageRef.nodeId is null and the registration has one node state named "whole cluster". Artemis queues are still read on every serving node.
- Records keep their order by group id or key, rejected records are retried by the broker or the SDK, and MessageRegistration.releasesCounted says whether a release counts as a delivery attempt (Kafka share groups do).
- A tap is refused at registration, naming the system, where the cluster cannot copy traffic (Kafka).
- Raises Contract.VERSION to 18 and the plugin template with it.
- Cluster details read their resource kinds outside the registration and read transactions.
The Kafka ITs run on apache/kafka:4.4.0; the ZooKeeper and cp-kafka ITs run in CI.
Open a subscription by its id, and keep a confirmation's focus in the dialog (f8580435)
The estate and the Subscriptions view open a subscription's detail by its whole id in the address (?subscription=<kind>/<path>), so a Kafka group that reads two topics opens the one that was meant; the old name-only address no longer opens anything.
A confirmation that opened while its caller was busy (taking the estimate it states) had a disabled Cancel that could not hold focus, so focus fell to the page, and nothing gave it back once the caller settled. Cancel takes it then. That race made the row menu's keyboard-only delete test fail whenever the estimate arrived after the dialog was focused.
Browse a partition of a log by offset or time (21b29f03)
GET .../resources/{kind}/{path}/messages on a destination whose kind reads a partitioned log takes partition, from (earliest, latest, offset or time) and value. The page says where in the partition it sits: its start and end offsets, the offset to continue from, whether retention already removed the offset asked for (it is read from the start), and that records of open or aborted transactions are not shown. An offset past the end is an empty page that states the end, and latest is the last page. A tombstone is marked, a record's key is shown, and a filter is refused with the driver's reason. GET .../messages/{offset} with partition expands one record.
One connection check and one edit shape for every system (0dfaa17f)
Both dry runs, the registration's and the edit's, answer 200 with the same ConnectionCheck for Artemis and Kafka: the nodes with their reach and cause, what the account may do, the version, and a failure with its cause and next action when no broker could be reached. Brokers a registered cluster already holds are reported as alreadyRegistered instead of a 409 on the dry run. The Artemis check adds its adoption preview, its management URL pattern, its feature contributions and, per node, its pair role and each account's result.
PATCH /api/v1/clusters/{id} takes {name?, description?, environmentId?, connection?} for both systems; the connection's system must be the cluster's. A Kafka cluster's capabilities now list every capability its driver assessed, with the driver's own reasons. Kafka registration reads the cluster version, its mode and each unreachable broker's advertised address and cause from the driver (OpenBroker 0.5.0-SNAPSHOT), so Kafka 3.0 and later is registered. KindView says whether a kind reads a partitioned log, and the subscriptions sort key depth is now backlog.
Say how far a subscription's backlog can be trusted (20405f80)
A subscription's depth is now a backlog: {value, accuracy, reason, breakdown}. Artemis counts exactly. A system that can only estimate says so with its reason, and one that cannot know the figure says UNAVAILABLE and gives no value, never a zero. GET /api/v1/clusters/{id}/subscriptions/{kind}/{path}/backlog lists a partitioned log's backlog by partition, slowest first, with the committed offset, the end offset, the lag and, where a partition has no position or its end could not be read, the reason.
Register a cluster per system, from its own connection (00cd793d)
POST /api/v1/clusters now takes the cluster's system and a connection shaped by it: {system: artemis, seedUrls, credentials, coreCredentials, tlsBundle, managementUrlPattern} or {system: kafka, bootstrapServers, securityProtocol, saslMechanism, credentials, tlsBundle, clientId}. A system Rahdar does not load, or a connection shaped for another, answers 400 unsupported-system naming the systems it supports. The dry run of a Kafka registration reports the version found (a lower bound where the brokers cannot say more), every broker with its advertised address and whether Rahdar reached it, the controller quorum, what the account may do and, on failure, the cause (DNS, REFUSED, TIMEOUT, TLS, AUTHENTICATION, AUTHORIZATION, UNSUPPORTED_VERSION) with the next action. A cluster is registered once, by the id its brokers report. PATCH /api/v1/clusters/{id} takes {connection} for a Kafka cluster; an omitted secret keeps the stored one, and a changed server, protocol, mechanism or account needs it again. Secrets are sealed and never returned. The cluster screen, its capabilities and its health now work for a Kafka cluster, and an estate read of the health of a system that asks its brokers no longer runs inside a database transaction.
Health is judged per system on one scale: Artemis from its HA pairs as before, Kafka from its brokers serving, replicas in sync and the controller quorum (a quorum that cannot be read is stated in the notes, not counted as healthy).
Name resource kinds as their driver does (49dd18a3)
A kind's label is now {singular, plural} from the broker driver ("Topic" and "Topics", "Queue" and "Queues") instead of a sentence-cased id. Rahdar no longer derives it.
Register a cluster on its own page, per broker system (57f8fee8)
Registration is now a page at /clusters/new?system=<id>, outside any cluster, with the way back in the line above it. Choose the system from the drivers Rahdar loads, give its connection, check it, then name the cluster and register. The dialog is gone: the cluster switcher, the Clusters settings section and the empty estate link to the page.
- Apache Kafka: bootstrap servers (host:port, one or several, the port defaults to 9092, a scheme or an account is refused), security protocol, SASL mechanism and credentials only where the protocol uses them, a TLS bundle, and a warning (not a block) for SASL over plaintext. Host name verification is stated as always on.
- The connection check shows the version with its lower bound and mode, every broker with its advertised address and whether it was reached, the controller quorum, what the account cannot do, and for a failure its cause (name, refusal, timeout, certificate, authentication, authorization, version) with the next action. A cluster reached in part may be registered after a warning; one registered already is linked and cannot be registered again. Register stays disabled, with its reason, until a check passed on exactly the entered inputs.
- Settings, Connection edits a Kafka cluster with the same fields; a stored secret is kept when left empty and asked for again when the connection goes somewhere new.
- Fixed: a second management URL typed into the same Artemis box was silently dropped; every host is kept and shown as normalised.
- An Artemis version gate now reads "Needs version X".
Reach every cluster through the driver of its own system (56741c3a)
The broker gateway builds each connection from the cluster's system, through a per-system connection-options extension, instead of assuming Artemis. Apache Kafka joins as a loaded driver (openbroker-kafka) with its own module and a kafka_connection table for the bootstrap servers, security protocol, SASL mechanism and client id. GET /api/v1/systems lists the loaded drivers with how each registers its clusters (jolokia-seeds or bootstrap).
Added
Find hanging transactions on demand and abort them one partition at a time (db34fa00)
The Transactions page gains a Hanging transactions section: Find looks for the transactions the coordinator does not know (the cluster, or one topic) when asked, and lists topic, partition, producer, records held back and time since the last write, with a figure the broker did not give said as not reported. Each is previewed (naming the fenced producer and what it holds back), aborted after a hold against the preview, and a changed one asks for a fresh preview. A search that could not run is never read as an empty answer. The coordinator's own list is informational.
Say what a delivery summary event reports, in words (e9579a60)
An openbroker.message.delivered event is the deliveries on one destination and subscription over one flush interval. The grid and the detail show it as "N messages delivered on <destination>/<subscription> between <from> and <to>", and the type filter calls it "Messages delivered (summary)".
Find hanging transactions on demand and abort them per partition (8a052c80)
The coordinator aborts an open transaction past its timeout by itself, so the transactions an operator must deal with are the ones it does not know: open on a partition, holding the last stable offset back for ever (KIP-664). They are found on demand, for the cluster or one topic, with the records each holds back and its age, and aborted one partition at a time: previewed, pinned to the state previewed, held, gated and audited.
POST hanging-transactions:find, :abort-preview and :abort do it over the API; kafka_list_transactions returns the coordinator's open transactions and, with hangingOnly, the hanging ones, and kafka_abort_transaction takes the id of a hanging transaction as it takes a transactional id. Needs OpenBroker 0.6.2 for the hanging-transaction kind; the find test skips against an older driver.
Show where a group stands in a browsed log, what a log purge skips, and the advertised-address failure (40694b5c)
A log read through a group's subscription says where the group stands on the partition. A purge of a log reports the records it passes over (the new skipped figures) in its dialogs, its bulk plan and its result, and the connection check names brokers that advertise addresses Rahdar cannot reach.
List a Kafka cluster's transactions, and abort only one the coordinator has missed (c6314b97)
An assistant could abort a transaction but not find one. kafka_list_transactions lists a Kafka cluster's transactional ids with state, start, timeout, whether each hangs and the partitions it holds back, bounded by a limit and a cursor, with hangingOnly to keep the ones that matter.
The coordinator aborts an open transaction past its timeout by itself within seconds, so an open one is information, not an incident. A transaction now counts as hanging, and can be aborted, only when it is still open a minute past its timeout, which means the coordinator has missed it; the preview says so otherwise. The design and the specs record the model, and the planned hanging-transaction find that will join the list.
Browse a group's subscription, and report what a log purge skips (45e34f19)
A partitioned subscription's id (kafka.group-topic/<group>%2F<topic>, or a share group's) answered 400 on browse and on a record's detail, because the route wanted a destination. It now browses and opens the records of the topic the subscription reads, found from the driver's own breakdown, and the page says where the group stands on the partition (log.subscriptionPosition: its committed offset, or a share group's start offset).
A purge of a partitioned subscription moves the position and deletes nothing. It now reports the records it passes over as skippedCount (single purge) and as skipped (a bulk item, expected in the plan and reported once run), while affectedCount and affected keep meaning what was destroyed, which is 0 here. The bulk cap counts destroyed messages only, so a log purge is not capped, needs no override and adds nothing to a bulk run's estimate.
Show a part-way offset reset and refuse aborting a live transaction (c03029fa)
A reset that stopped part way now shows which topics moved and how far, which stayed where they were, and why it stopped. The abort of a transaction that is not open past its timeout is disabled with the reason, and a refusal at run time shows the system's detail.
Show the controller voters and whether the quorum has a majority (5af7ec8a)
The brokers page lists each controller voter with its lag and whether it is caught up, and states in words whether the caught-up voters are a majority. A quorum with no majority is shown as a critical state.
Run a truncate against its preview (0572dc81)
The truncate dialog sends the preview's etag with the run. When the log changed since the preview, the run is refused as stale: the dialog stays open, says so, and asks for a fresh preview before it can be confirmed.
State why a topic's configuration is read-only (beaa7133)
A topic whose configuration Kafka reports as read-only now shows the reason in a notice at the top of the configuration page, and every Change control is disabled with that reason.
Read and change a Kafka cluster through eight kafka_ tools* (0f653bfe)
An agent can now work a Kafka cluster over MCP: kafka_list_groups, kafka_describe_group, kafka_preview_offset_reset, kafka_topic_config and kafka_list_acls read; kafka_reset_offsets, kafka_set_topic_config and kafka_abort_transaction change it. They are offered only to a key that can read a Kafka cluster, and a call that names a cluster of another system is a tool error naming both.
Each calls the service its screen calls, so the permission check, the approval gate and the audit row are the same: a change the gate holds is answered as held, not as a failure. A reset runs only against the etag of its kafka_preview_offset_reset preview with confirm equal to the group; kafka_set_topic_config and kafka_abort_transaction preview by default and need the etag and confirm for a real run. A stale preview is a conflict that says to preview again. The mutating tools are hidden while the installation is read-only.
Change a topic's settings after the broker validated them, and show each group member's partitions (6a1eeaf3)
A topic's settings are listed with their source (topic override, broker default, static, default), their default and whether they are read-only; a sensitive setting is shown as set and never sent. Changing or removing an override is previewed with the broker's own validation, then applied through the approval gate and audited. A group's detail lists its members with the partitions each holds.
Select and act on subscriptions by their full id (92c4a122)
A bulk action sends the ids of the subscriptions it acts on (kind/path, such as kafka.group-topic/billing/orders) instead of their names, and a subscription selection handed to a feature is { kind: 'ids', ids }. A Kafka group that reads two topics is two subscriptions, named in the preview and the run as group/topic. A purge of a log shows what it skips and that nothing is deleted, an active group is refused with its members, and a group that began rebalancing is a failed item with the driver's reason.
Say on a registration that a release counts as a delivery attempt (0c0391ec)
A delivering registration on a subscription whose system counts a release as a delivery attempt (a Kafka share group) now says so in its detail, next to releasesCounted, so a plugin author sees that a message it keeps releasing is dead-lettered by the broker.
Tests on apache/kafka:4.4.0: a record that is always rejected on a consumer group is retried in place, dead-lettered, and passed by the group only then; a released share-group record is redelivered with its count raised; a share group with no dead-letter topic fails the registration with the broker's precondition.
Read Kafka consumer groups through plugin messaging (e6b8ded9)
A plugin names the subscription it receives from by its shared-API id, so a registration can read a Kafka consumer group as well as an Artemis queue.
- RegistrationSpec.source, MessageRegistration.source and PluginMessage.source are a SubscriptionId(kind, path) instead of a ResourceRef. ResourceRef stays the key of a permission check and the target of a send.
- A partitioned log is read once for the whole cluster, by the instance that owns it: MessageRef.nodeId is null and the registration has one node state named "whole cluster". Artemis queues are still read on every serving node.
- Records keep their order by group id or key, rejected records are retried by the broker or the SDK, and MessageRegistration.releasesCounted says whether a release counts as a delivery attempt (Kafka share groups do).
- A tap is refused at registration, naming the system, where the cluster cannot copy traffic (Kafka).
- Raises Contract.VERSION to 18 and the plugin template with it.
- Cluster details read their resource kinds outside the registration and read transactions.
The Kafka ITs run on apache/kafka:4.4.0; the ZooKeeper and cp-kafka ITs run in CI.
A Kafka broker that joins the cluster is added to its nodes (db554781)
The scrape adds a broker the cluster reports and Rahdar does not store, with the name and address the cluster gives it, so the nodes stay true without re-registering. A broker the cluster no longer lists is marked with the error and keeps its last state.
Say when a Kafka broker advertises an address Rahdar cannot reach (5576d4ef)
A check that fails with a timeout or a refusal after the bootstrap server accepted a TCP connection now says the brokers advertise addresses Rahdar cannot reach and to set advertised.listeners to one it can (not localhost inside a container), instead of blaming the bootstrap server. With two brokers, the check reaches the first and names the second with the address it advertises and why it cannot be reached.
Purge a log by moving its position, and open a group's topic by its whole id (5d4ec7d2)
The purge of a log subscription says it moves the group's position to the end and deletes no record, and a refusal when it runs (a group that began rebalancing since the estimate) stays in the dialog, which stays open and disabled. A subscription whose name does not say which it is, a Kafka group that reads several topics, is opened by its whole id, so its row menu, its detail and its messages reach the right topic.
Kafka subscriptions in the subscriptions table, with an estimated backlog (308b94c9)
The scrape reads a Kafka cluster's subscriptions (a group on a topic, a share group on a topic) in one batched read on tier B and keeps them in the snapshot cache, so the subscriptions table lists them beside Artemis's. A subscription is of the kind it was scraped as and its id has the segments its system gives it; its name is the group, which is what a team owns, and its destination the topic. A backlog that is only an estimate says so with the system's reason and whether it has a breakdown by partition.
Read a Kafka cluster's brokers on the scrape schedule (695ffa43)
A cluster whose system is read as a whole rather than node by node over Jolokia is handed to its system's scrape on tier A: one batched read of every broker, after which each stored broker shows whether it serves (a fenced one is stopped and not live), and one that did not answer keeps its last state with the error. The same cycle counts the partitions that have no leader, and a Kafka cluster with any is critical; a cluster whose leaders cannot be read says so instead of passing as fine.
Refuse a per-record action on a log with the driver's reason (421284e3)
Moving, retrying, expiring or deleting single records of a partitioned log answers 409 action-unavailable with the system's own reason (a log is append-only; truncate from its start or produce the record again), instead of failing on a queue that does not exist.
Purge a log subscription, refused while its group has members (f14365db)
Purging the subscription of a partitioned log (POST .../resources/{kind}/{path}:purge) moves its position to the end instead of deleting records. The dry run answers the records it would skip, and a group that has active members is refused with a 409 problem naming them (a rebalancing group is refused when it runs, with the driver's reason). The run passes the approval gate as subscription.purge-log and is audited. The node of the purge answers is null where the system has none.
Truncate a destination's log before an offset or a time (143aaa51)
POST /api/v1/clusters/{id}/destinations/{kind}/{path}:truncate cuts the oldest records off a destination whose kind has the truncate verb, before an offset in each named partition or before a time. The answer, for ?dryRun=true and for the run, is {records, groups: [{group, records}]}: every group that loses records it has not read, with the count, biggest first. A compacted topic is refused as a conflict with the driver's reason. It needs destination:truncate on the destination, passes the approval gate as destination.truncate (its state key is the log start of each partition, so a truncate that ran since is refused), and is audited with the log start of each partition before and after.
Read a log as the API answers it (85495493)
A partition browse uses the window the server reports: where the log starts and ends, whether retention moved the start, and the offset to continue from, offered as "Next records". A record shows its key, and the columns an Artemis message has and a record does not (priority, durability, properties) are left out. A record opens by its offset in its partition.
Browse a partition of a log by offset or time (21b29f03)
GET .../resources/{kind}/{path}/messages on a destination whose kind reads a partitioned log takes partition, from (earliest, latest, offset or time) and value. The page says where in the partition it sits: its start and end offsets, the offset to continue from, whether retention already removed the offset asked for (it is read from the start), and that records of open or aborted transactions are not shown. An offset past the end is an empty page that states the end, and latest is the last page. A tombstone is marked, a record's key is shown, and a filter is refused with the driver's reason. GET .../messages/{offset} with partition expands one record.
Bring the newer-release warning and the remedies back to the connection check (abced586)
A node that runs a release newer than Rahdar has tested is named in a warning, and registering still goes ahead. An access finding that has a remedy shows it: the broker.xml an Artemis capability needs, or the command that grants a Kafka account what it lacks, and a version gate is listed with the release it needs. Registering and editing use the generated request types.
Read consumer groups, ACLs, transactions and brokers, and reset group offsets (b4e2bb7a)
Under /clusters/{id}/kafka/: groups with their lag and per-partition standing, an offset reset that is previewed (records skipped or read again, a time past the end, an offset out of range, members, a rebalance) and then run against the preview's state key through the approval gate with the offsets audited before and after, ACLs with the effective access before and after a change, transactions with the ones open past their timeout and the partitions they block, and the brokers with the controller quorum.
One connection check panel for every system (f6495e91)
Registering and editing a connection show the same check for Artemis and Kafka: why it failed and what to do, the version, every node with where Rahdar reached it (an Artemis node says what each of its two accounts did), the quorum, and what the account cannot do. Editing sends the one shape {name, description, environmentId, connection}. A Kafka cluster's capabilities list the driver's own findings with its own reasons.
The warning for an Artemis release newer than Rahdar has tested and the per-capability broker.xml snippets of the registration check are gone with the old check; the check no longer carries what they were read from.
Permissions for seeking, truncating and the Kafka resources (55bd8b02)
New permissions: subscription:seek, destination:update and destination:truncate on resources, and access-rule:read, access-rule:write, transaction:read and transaction:abort on a Kafka cluster. The built-in operator role gains the seek, update, truncate, transaction and ACL-read permissions, and the viewer gains transaction:read and access-rule:read; admin holds all of them already. Operators recreate the database.
One connection check and one edit shape for every system (0dfaa17f)
Both dry runs, the registration's and the edit's, answer 200 with the same ConnectionCheck for Artemis and Kafka: the nodes with their reach and cause, what the account may do, the version, and a failure with its cause and next action when no broker could be reached. Brokers a registered cluster already holds are reported as alreadyRegistered instead of a 409 on the dry run. The Artemis check adds its adoption preview, its management URL pattern, its feature contributions and, per node, its pair role and each account's result.
PATCH /api/v1/clusters/{id} takes {name?, description?, environmentId?, connection?} for both systems; the connection's system must be the cluster's. A Kafka cluster's capabilities now list every capability its driver assessed, with the driver's own reasons. Kafka registration reads the cluster version, its mode and each unreachable broker's advertised address and cause from the driver (OpenBroker 0.5.0-SNAPSHOT), so Kafka 3.0 and later is registered. KindView says whether a kind reads a partitioned log, and the subscriptions sort key depth is now backlog.
Run Apache Kafka in the dev and demo stacks, and seed it (8b94a435)
The dev stack gains a single-node Kafka (KRaft, share groups on, an authoriser), published on localhost:9094. The demo stack replaces it with a three-broker KRaft cluster. The demo seed registers it as "events" through the per-system registration shape, and with the Kafka image's own tools creates topics (one compacted, with a tombstone), a group that keeps up, a lagging empty group, an empty group behind on payments, a share group, ACLs and one transaction left open, then keeps writing while it drives the Artemis traffic. The Artemis registration uses the new shape too.
Say how far a subscription's backlog can be trusted (20405f80)
A subscription's depth is now a backlog: {value, accuracy, reason, breakdown}. Artemis counts exactly. A system that can only estimate says so with its reason, and one that cannot know the figure says UNAVAILABLE and gives no value, never a zero. GET /api/v1/clusters/{id}/subscriptions/{kind}/{path}/backlog lists a partitioned log's backlog by partition, slowest first, with the committed offset, the end offset, the lag and, where a partition has no position or its end could not be read, the reason.
Consumer groups, offset reset, topic configuration, ACLs, transactions and brokers (d8542d3a)
A Kafka cluster gets the views of its system, listed only for it:
- Consumer groups: type, state, members and lag read a page at a time, and a group's page with every partition's position, a lag that could not be read stated with its reason, a deleted topic called gone, and its members.
- Reset offsets: choose topics and where to move, preview what each partition skips or reads again and which members still hold the group, then confirm by pressing and holding. A group with members or in a rebalance, a stale preview and an offset out of range each say why.
- Topic configuration: where each value comes from, sensitive values never shown, changes collected, reviewed (before, after, the fallback of a removed setting, the system's validation) and applied against the review.
- ACLs: listed, or the reason there is no authoriser; additions and removals reviewed for the access each principal gains and loses.
- Transactions: hanging ones flagged with the partitions they hold back, and an abort that names its effect and is confirmed by holding.
- Brokers: reach, leaders and under-replicated partitions, and the controller quorum, or that it is unknown on a ZooKeeper cluster.
Every change shows disabled, with the reason, to someone without the permission.
Register a cluster per system, from its own connection (00cd793d)
POST /api/v1/clusters now takes the cluster's system and a connection shaped by it: {system: artemis, seedUrls, credentials, coreCredentials, tlsBundle, managementUrlPattern} or {system: kafka, bootstrapServers, securityProtocol, saslMechanism, credentials, tlsBundle, clientId}. A system Rahdar does not load, or a connection shaped for another, answers 400 unsupported-system naming the systems it supports. The dry run of a Kafka registration reports the version found (a lower bound where the brokers cannot say more), every broker with its advertised address and whether Rahdar reached it, the controller quorum, what the account may do and, on failure, the cause (DNS, REFUSED, TIMEOUT, TLS, AUTHENTICATION, AUTHORIZATION, UNSUPPORTED_VERSION) with the next action. A cluster is registered once, by the id its brokers report. PATCH /api/v1/clusters/{id} takes {connection} for a Kafka cluster; an omitted secret keeps the stored one, and a changed server, protocol, mechanism or account needs it again. Secrets are sealed and never returned. The cluster screen, its capabilities and its health now work for a Kafka cluster, and an estate read of the health of a system that asks its brokers no longer runs inside a database transaction.
Health is judged per system on one scale: Artemis from its HA pairs as before, Kafka from its brokers serving, replicas in sync and the controller quorum (a quorum that cannot be read is stated in the notes, not counted as healthy).
Truncate a destination's records before a cut (d8edffce)
Destinations of a kind whose system can truncate offer "Truncate…": the cut is given as an offset per partition or a time, previewed first with the number of records it removes and every group that would lose records it has not read, and confirmed by pressing and holding a button that names the count. A cut the system refuses, such as on a compacted topic, shows its reason and leaves the confirmation disabled. Approval holds are announced like any other held operation.
Say why a system refuses a purge, and disable per-record actions its kinds lack (02e09ad2)
A purge the system refuses (a group with members, or rebalancing) shows the system's own reason in the confirmation and leaves it disabled. Moving, retrying, deleting and expiring messages, one at a time, in a selection or by selector, are disabled with the system's words when the subscription's kind lacks the verb, before any reason about permission.
Browse a partitioned log by partition, offset or time (ce3c265b)
On a system whose kinds are partitioned logs, the message browser asks for a partition and a start (the earliest record, the latest, an offset or a time) instead of a node and a page, and shows the offset as the record's id. The selector is disabled with the reason. The page says when an offset is past the end of the log, when retention moved the start, that records of an open or aborted transaction are not shown, and shows a record with a key and no value as "Tombstone (no value)".
Show a subscription's backlog with its accuracy, and name kinds as their system does (8f9e40e3)
The Depth column of the estate and subscriptions tables is now Backlog. An exact figure is plain. An estimate reads "≈ 12 400" with "estimate" in its accessible name, and a backlog that could not be read says "Unavailable" instead of 0. The reason is a popover on the figure itself, so a keyboard reaches it, and where the system has a per-partition breakdown the popover offers "Show partitions": a drawer listing the partitions slowest first, with how old the sample is and the reason for any partition whose lag could not be read.
Kind names (Queue and Queues, Topic and Topics) come from each system with the kind, in every table, menu and refusal ("Apache Kafka ACLs cannot be purged"); the web no longer pluralises them itself.
The table of subscriptions leaves out its lowest-priority column, Scheduled, in a window with a scroll bar's width to spare, because Backlog is a character wider than Depth was.
Name resource kinds as their driver does (49dd18a3)
A kind's label is now {singular, plural} from the broker driver ("Topic" and "Topics", "Queue" and "Queues") instead of a sentence-cased id. Rahdar no longer derives it.
Register a cluster on its own page, per broker system (57f8fee8)
Registration is now a page at /clusters/new?system=<id>, outside any cluster, with the way back in the line above it. Choose the system from the drivers Rahdar loads, give its connection, check it, then name the cluster and register. The dialog is gone: the cluster switcher, the Clusters settings section and the empty estate link to the page.
- Apache Kafka: bootstrap servers (host:port, one or several, the port defaults to 9092, a scheme or an account is refused), security protocol, SASL mechanism and credentials only where the protocol uses them, a TLS bundle, and a warning (not a block) for SASL over plaintext. Host name verification is stated as always on.
- The connection check shows the version with its lower bound and mode, every broker with its advertised address and whether it was reached, the controller quorum, what the account cannot do, and for a failure its cause (name, refusal, timeout, certificate, authentication, authorization, version) with the next action. A cluster reached in part may be registered after a warning; one registered already is linked and cannot be registered again. Register stays disabled, with its reason, until a check passed on exactly the entered inputs.
- Settings, Connection edits a Kafka cluster with the same fields; a stored secret is kept when left empty and asked for again when the connection goes somewhere new.
- Fixed: a second management URL typed into the same Artemis box was silently dropped; every host is kept and shown as normalised.
- An Artemis version gate now reads "Needs version X".
Reach every cluster through the driver of its own system (56741c3a)
The broker gateway builds each connection from the cluster's system, through a per-system connection-options extension, instead of assuming Artemis. Apache Kafka joins as a loaded driver (openbroker-kafka) with its own module and a kafka_connection table for the bootstrap servers, security protocol, SASL mechanism and client id. GET /api/v1/systems lists the loaded drivers with how each registers its clusters (jolokia-seeds or bootstrap).
Changed
Merge dependabot/npm_and_yarn/web/npm-minor-patch-182aad3db4 into claude/19e4-kafka (264645fa)
Merge dependabot/maven/maven-minor-patch-1575aeef6f into claude/19e4-kafka (b825e0a0)
Merge dependabot/github_actions/actions-8732fb71db into claude/19e4-kafka (2209615f)
Merge origin/main into claude/19e4-kafka (c3150b20)
Conflicts:
docs/adr/README.md
src/main/java/io/github/sudoitir/rahdar/feature/plugins/messaging/PluginMessagingService.java
src/main/java/io/github/sudoitir/rahdar/platform/broker/BrokerGateway.java
Preview an ACL change over the ACLs it touches, not the cluster's whole set (4d00b5f0)
A preview read every ACL of the cluster, 100 000 of them on a large one. It now reads the rules of the principals and resource types the change names, up to 20 000, and says so in its notes when the cap cut the read short.
Store message deliveries as a count per destination and interval, not one row per message (a584e0d4)
A message delivery is the one broker notification sent per message, and every one of them was a broker_event row: two hours of demo traffic wrote 1.1 million rows (1.1 GB). Deliveries are now counted in memory per destination and subscription, and each flush writes one openbroker.message.delivered row per destination that saw deliveries, with the count and the interval (from, to) in its data. Every other event type is still stored verbatim, and request-reply tracing still sees each delivery live.
Revert "build(kafka): keep the seed's hanging transaction hanging in the dev and demo stacks" (206e531e)
This reverts commit 52eb322b4649cf0d6c75daa37d18b3100f82fb30.
List groups with one broker read, and count the scrape's driver reads (271eaf63)
The groups list asked the cluster for the lag of every group on the page in a query of its own, which the driver answers with a full read each: a page of a hundred groups was a hundred reads. A page is now one listing of the groups, with their lag taken from the scrape's last sample, as the estate list does. A group's detail no longer reads each topic's end offsets apart, since a subscription carries every partition's committed offset and lag. An ACL preview now reads every page of the cluster's ACLs, where it stopped at the first.
The scrape counts its driver reads as rahdar.kafka.scrape.rounds, by cluster and call, and each tier's pass is timed as rahdar.scrape.cycle, so a cycle that grew with the size of the cluster, or one longer than its interval, shows.
Fixed
Clear the static-analysis findings outside the Kafka package (3ebdf107)
Clear the static-analysis findings on the Kafka screens (75e13856)
Clear the static-analysis findings in the Kafka module (77931953)
A longer health summary stays on one line (ef41f138)
The sentence above consumer health truncates instead of wrapping under the filter, including at 200% zoom, so the table does not jump down as the rows arrive.
An unreported dead-letter depth shows as Unknown (7edea7f2)
A depth no node reported shows as Unknown. A total that leaves nodes out names how many, so those nodes are not read as empty.
Null clears the Core account (10d283b8)
Sending null for the Core account clears it, so Core uses the management account. Leaving the field out keeps it. The document said the field was an account only, so a generated client rejected the null the console sends.
A nullable reference keeps the text that says when it is null. A dead-letter depth is null when no node reported one, and the total names how many nodes it left out. A Kafka field left unset is omitted; the server already reads that the same way as null.
Read the clusters a system scrapes whole side by side, each bounded (df042283)
A Kafka cluster that stopped answering held the scrape of every cluster after it, because the scheduler read them one after another on its own thread with no limit. Each cluster is now read on the pool, a cluster still being read is not read again, and the pass waits ten seconds at most in all: a cluster that has not finished by then has its nodes marked as not answering and finishes on its own.
Let each member of a connection union stand alone so the Java client compiles (173b506c)
The cluster connection (and its update) is a oneOf keyed by system whose members also said allOf the union, a cycle. openapi-generator made each member extend the union and override the other member's properties, and the generated Java client did not compile. Members now carry their own properties and the union only its oneOf and discriminator. The TypeScript names are unchanged.
Bound a browse page by bytes, say how a key is written and why a time start is empty (925585cd)
A browse page was bounded by count only, so 500 one-megabyte records could hold over a gigabyte. A page now stops at 8 MB of body, says it was cut short (truncated) and, on a log, names the first record left out as the next offset. A streamed value is read to the browse limit and no further. A key says whether it is TEXT or BASE64 (keyEncoding). A log read from a time in the future is refused with the reason, and an empty read from a time says where the partition's last record is. A message with no produce time is null, in the message views and the SQL console, never 1970-01-01.
Answer health from what the scrape wrote, never from a call to a broker (4fd49bfa)
Health used to ask the brokers for their nodes on the request thread, so a slow or blocked cluster held the request. The scrape now writes the verdict it forms each cycle (when it changes, and every 30 seconds otherwise) to kafka_health, and every replica reads that row. A cluster the scrape has not read, or has not read for two minutes, is unknown, with the reason stated.
Hold a state alert's resolution for two minutes so a flapping broker is one alert (15a090b0)
A broker that flapped every minute resolved and fired its node-down alert on every flap, sending a notification each time. A state rule's alert now resolves once its condition has been false for two minutes.
Cancel the open requests of a cluster that was deleted (65359360)
A held or approved request for a cluster that no longer exists stayed open until its own expiry and could never run. It is now cancelled, with the reason stated, when the cluster is deleted and by the expiry sweep.
An unreported depth is unknown, not zero (8a229a29)
A backlog, a dead-letter depth or a group lag the broker did not report is left empty. Totals add only the depths that were reported, and a slow-consumer rule does not fire on a placeholder. A Kafka group with no committed offset has no lag to report; one whose topics are only partly known says how many it left out. Health no longer treats partitions that have not been sampled as a failed read.
Recreate the database. The scrape baseline no longer stores an unknown backlog as 0.
Follow the dependency bump: the jsdom box the virtualizer reads, and aria-disabled on a menu item (dae5e730)
react-virtual 3.14.15 and later read the scroll element's client size where they read its offset size, so the table tests, which gave jsdom a box through the offset size only, saw no rows; the box now has a client height too. Mantine 9.7.4's Menu.Item writes aria-disabled itself after the props it is given, so an unavailable action no longer carried it; it is set on the element, and the item stays in keyboard navigation. The cluster's view list is empty until the cluster says which system it runs, so it does not jump when the list is replaced.
Keep the messages page and the growing dialogs from jumping, and make the record detail scrollable by keyboard (4632ae0f)
A partitioned log's standing notices move to places where their arrival shifts nothing: the one about committed records into the header, where the group stands into the toolbar. A dialog whose consequence grows as it is read (the reset and abort previews, the truncate cut) keeps its top edge instead of re-centring. The count of hanging transactions sits under the list. The record detail's scroll area takes focus, and the By selector menu drops Mantine's focus placeholder, which axe reads as a child a menu may not have when every item is unavailable.
Say a system has no such list, instead of a conflict (9e761337)
A view of connections, producers, channels or consumers on a Kafka cluster answered 409 and read as "This conflicts with the current state". It now reads as what it is: the system has none of that, and to choose another view.
Bound the Kafka group, offset-reset and topic-config tools (0aadb35f)
kafka_describe_group and kafka_preview_offset_reset answered every partition, about 80 000 tokens at 3 000 partitions. They now return a total per topic and the 20 slowest or biggest-moving partitions with truncated and a note, and an optional topic argument pages one topic's partitions with a cursor. kafka_topic_config returns only the overridden settings unless onlyOverridden is false, and keys names the settings wanted. The REST API is unchanged.
Keep an offset reset's audit row small at thousands of partitions (5c797e31)
Above 200 partitions the row stores a count and the lowest and highest offset per topic, marked summarised, instead of every partition's offset before and after. The reset's target (to, value) is kept as before.
Keep the cluster-id change where every replica reads it (76ab9251)
The warning that a Kafka cluster at a registered address reports another cluster id was held in memory on the replica that scraped it, so another replica's health showed the cluster as fine. It is now written to the stored brokers' last error, which every replica reads.
Drop a deleted cluster's health readings, partition counts and scrape meters (a40cefb3)
A replica kept the health and offline-partition readings, the cluster-id warning and a set of per-cluster scrape meters for every Kafka cluster it had ever seen. They are released when the cluster is deleted on any replica.
Read a cluster's offline partitions on the scrape, never on a health request (31517291)
Health used to page through every partition of the cluster on the caller's thread when its reading was stale, hundreds of broker reads at hundreds of thousands of partitions. The scrape now reads them at most every 30 seconds and health only reads the kept count, which is unknown once it is two minutes old.
Retire a broker the cluster stopped listing (2a3a4fc9)
A broker replaced or removed from a Kafka cluster used to stay in the node list as unreachable for ever. After ten minutes of the cluster answering without it, the node is removed with the rows that hang on it, and the audit trail records that the broker left the cluster.
Delete a message registration's node rows when the node is removed (b9a90596)
Report a cluster re-provisioned at the same address instead of reading it as the registered one (d99cf67a)
Keep the messages controls still as a log's notices arrive, and underline the request link in a toast (313deb6a)
The notices a partitioned log has (where the group stands, retention moved the start, only committed records are shown) arrive with the first page of records. They now sit under the controls, so the controls and the table frame do not jump down when they appear. The held request's link in a toast is underlined, not told apart by colour alone.
Answer a refused reset with its reason alone, not a table of moves it will not make (d2f5883b)
Count a log purge's figures from what it skips, not from what it destroys (cb23d46c)
Name the check failure for brokers that advertise an address Rahdar cannot reach (9a46f38f)
When the bootstrap server accepts a connection and the check still times out, the brokers advertise addresses Rahdar cannot reach. The failure's cause was TIMEOUT with only its next step precise; it is now ADVERTISED_UNREACHABLE, and its message opens with 'Brokers advertise addresses Rahdar cannot reach.'
List a Kafka cluster's destinations, and answer no shared read route with a server error (b4ffc79f)
The destinations list went down a path that needs a node with a management URL, which a Kafka cluster's brokers do not have, and answered 502. A system whose brokers have none is now read as one cluster through the SDK, every page of it. A list of a kind the system does not have (connections, producers, channels and so on) answers 409 saying so, the routes list is empty for a system with no routes, the dead-letter view is empty for a system that keeps no dead-letter configuration in its brokers, and the consumer-health verdict no longer reads the cluster's kinds inside a database transaction, which answered 500.
A test registers a Kafka cluster against a real broker and walks every read route of a cluster, asserting none answers with a server error.
Close the backlog popover over the breakdown it opens, and give the reset preview room for every column (f3a69847)
Opening a group's partition breakdown left the figure's popover on top of the drawer; it now closes. The offset reset dialog is wider, so the preview shows what the group would skip and what it would read again together, not one of them.
Word a purge of a log as skipping records, and do not retry an answered failure (d1049df0)
A purge of a partitioned subscription, single or in bulk, now says it moves the group to the end of its log and skips N records, that no record is deleted, and its confirmation reads "Skip N records" rather than "Purge". It no longer says destroy or cannot be undone.
A query that failed with an answer from Rahdar, such as a 502 for a broker that cannot be reached, is no longer retried: the page shows the cause at once instead of asking again.
Follow the renamed query plan schema (502c0c3b)
Give every API schema a name of its own (64902fd7)
Five pairs of different records were published under one schema name, so the document described only one of each pair and an endpoint of the other showed the wrong shape. They are renamed: the system listing's SystemView is SupportedSystemView, the configuration's FindingView is ConfigFindingView, the query console's PlanView is QueryPlanView, the flow's Delivery is FlowDelivery and the job's Outcome is JobOutcome. ApiSchemaNamesTest now has no exceptions. Also ticks 4.1 to 4.3 and drops a stale exemption of the coverage test.
Name blocked partitions with a real plural in the abort preview (bec41cfa)
Record what an ACL change left on the cluster (3bd576f6)
An ACL change's audit row recorded the calls it meant to make as if they had all worked. It now asks the cluster what it holds afterwards and records the ACLs that are missing or remain, as a failure when they do. A change that stops part way records what was added and removed and what was not, instead of a bare failure.
An ACL preview lists the access lost on every resource a prefixed rule covers (89492113)
A prefixed rule, or a literal *, was previewed against the one resource named in the rule, so a deny on orders- showed nothing lost although it takes the grants on orders-eu and orders-us away. The preview now evaluates every resource of the type that the cluster's other rules name and the rule covers, and says so when it shows only the first hundred.
Abort only a transaction that is open and past its timeout (91942f2b)
An abort fenced whichever transaction was named, including one whose producer was still working. It is now refused (409) unless the transaction is open and has outlived its timeout, which is the one that holds readers back, before the approval gate and the audit row, and again when an approved request replays. The preview says which it is and why a transaction is not aborted.
Say which topics a part-way offset reset moved (41308015)
A reset of a group over several topics that failed after some topics moved audited the whole reset as failed with nothing about what had moved, and answered with the error alone. The audit row now records the topics that moved and those that did not, with their offsets before and after, and the answer is a partial outcome naming both with the cause. A reset that fails on its first topic is refused as before.
Give the Kafka group and quorum schemas names of their own (4da59e46)
Two different records were published as PartitionLag, so the document showed one shape for both and a group's partition reason was typed as a required string. The group's partition lag is now GroupPartitionLag, and the broker quorum is BrokerQuorum with QuorumVoter. A test fails when two API types share a schema name, so the next clash is caught when it is written.
Never print a password or token from a record (2540f02c)
The records that carry a cluster account, a stored credential, a new user's password or a re-authentication password now print the name and a mask instead of the secret, alone and inside the request that holds them. A test registers, checks and edits a SCRAM cluster with a password and confirms it appears in no response, failure message or audit row.
Refuse a per-record action on a log before any broker call, from every caller (a2431a3b)
The message_action tool reached the queue purge by name and the per-record move, retry, delete and expire without the log's refusal, which only the REST screen applied. The refusal now lives in the service, so every caller gets the 409 with the system's reason before a broker call, and the tool purges a subscription of a log through the log purge and its gate. A bulk purge of a log reports its one outcome for the whole cluster with no node.
Refuse a system's internal topics, and check every segment of a subscription (a418db56)
A plugin could register a subscription whose topic segment was reserved, because only the first segment was checked, and could register or send to a Kafka cluster's internal topics. Every segment is now checked against the names Rahdar reserves and against the cluster system's own: Kafka reserves topics that start with two underscores (__consumer_offsets, __transaction_state, __share_group_state). A send to such a topic is refused too.
Pin a truncate to the preview it was confirmed from (ab3d2bc7)
A real truncate re-previewed and used that preview's own etag, so the cut an operator confirmed was never tied to what they were shown. The dry run now returns an etag, and a real run needs it: a log that moved since is refused as stale (412) and an approved replay carries it. A cut that names a negative offset or a partition the log does not have is a 400 before anything is cut, and any failure closes the audit row as failed rather than leaving it open. A stale preview is now one shared 412 for every feature.
Probe at most three bootstrap servers together, and accept at most 32 (68051a55)
The check that says the brokers advertise an address Rahdar cannot reach probed every bootstrap server in turn, each for up to three seconds. It now probes the first three together under one deadline. A request may carry at most 32 bootstrap servers; more is a 400. Also imports the classes the Kafka code had qualified inline.
Act on each subscription by its id, and purge a log through the log purge (205daf09)
A bulk run named a subscription by its queue name and purged it through the queue purge on every node. On a Kafka cluster that bypassed the log purge's approval gate and its active-members refusal, and two subscriptions of one group (one group reading two topics) collided on the same name.
- Bulk items are keyed by the subscription's canonical id (artemis.queue/orders, kafka.group-topic/billing/payments). The preview request and the selection take
idsin place ofnames; an id that is not one is a 400. - A purge of a subscription of a partitioned log goes through the log purge and its gate, once for the cluster, and audited like a single purge. A group with members is refused in the preview with the member count; a rebalancing group is that item's failed outcome with the driver's detail. The estimate says how many records the purge skips, and that none is deleted.
- Pausing, resuming and deleting a log subscription are refused in the preview. Artemis queues behave as before.
- Bulk items are keyed by the subscription's canonical id (artemis.queue/orders, kafka.group-topic/billing/payments). The preview request and the selection take
Open a subscription by its id, and keep a confirmation's focus in the dialog (f8580435)
The estate and the Subscriptions view open a subscription's detail by its whole id in the address (?subscription=<kind>/<path>), so a Kafka group that reads two topics opens the one that was meant; the old name-only address no longer opens anything.
A confirmation that opened while its caller was busy (taking the estimate it states) had a disabled Cancel that could not hold focus, so focus fell to the page, and nothing gave it back once the caller settled. Cancel takes it then. That race made the row menu's keyboard-only delete test fail whenever the estimate arrived after the dialog was focused.
Keep node versions, remedies and wire discriminators in the connection check (6cd0addf)
Each node of a connection check carries its release and where it sits against the range the system's driver is tested on (supported, newer than tested, below the minimum, unknown); the below-minimum refusal stays. Each access finding carries the snippet that makes a capability available (the broker.xml for Artemis, the driver's command for Kafka) and the driver's remedy, and an Artemis check lists its version gates as findings. The connection unions name their systems on the wire as artemis and kafka, so the generated request types accept what the API takes.
Register Artemis clusters with the per-system request (480e547e)
The QA, capture, configuration, MCP, load and HA failover scripts sent the old flat registration body, which the API no longer accepts. They send the system and a connection shaped for it.
Read a Kafka cluster's connection and check as the API answers them (6907ba8c)
The connection edit reads the stored Kafka settings from the cluster's connection (the account's name, never a secret), a check that reached no broker says so instead of failing to render, and an Artemis check is recognised by not being a Kafka one.
Say a system's supported versions in words, and keep Artemis wording to Artemis (8c00c714)
The registration page writes a driver's version range as "3.0 and later". Settings, Connection capabilities no longer mentions Jolokia or broker.xml for a cluster of another system.
Read the systems list from its paged answer (32b33834)
Security
Raise the Kafka client's snappy and lz4 codecs past their advisories (7da4e1a7)
kafka-clients brings snappy-java 1.1.10.7 and lz4-java 1.11.2, which carry high-severity advisories (GHSA-gwq9-9ffj-mvrv, GHSA-q233-g92q-qxp6, GHSA-mcr4-qmvw-px4g). Rahdar now ships snappy-java 1.1.10.9 and lz4-java 1.11.4.
Never show a sensitive topic setting's value, old or new (cb7004da)
A topic's settings list returned a sensitive setting's value as the broker answered it, and a change preview showed the new value, the broker's complaint about it and, for a removal, the value it falls back to. The list now returns no value or fallback for a sensitive setting, a preview masks all of them, and the approval row of a held change masks the value and redacts the set from the copy approvers' providers see. The audit row and the MCP answer carry the preview, so they are masked too.