This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 20535aae4d74 CAMEL-26727: camel-chaos - what to try: chaos rules 
suggested per route from what the route does (#29397)
20535aae4d74 is described below

commit 20535aae4d744cc0adb1479852483b4bdf16c816
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Nov 8 09:13:04 2026 +0100

    CAMEL-26727: camel-chaos - what to try: chaos rules suggested per route 
from what the route does (#29397)
    
    ChaosAdvisor suggests rules per route from the running routes (their remote 
sends, circuit breakers, dead letter channel, input, and hand-offs between 
routes), each a known rule of the chaos model with its target filled in and why 
it is worth trying, the most worth trying first. camel cmd chaos-suggest prints 
them with the command that adds each; w on the chaos screen lists them and 
types the picked one in. The camel-chaos page has a new section, What to try.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../org/apache/camel/catalog/docs/chaos.adoc       |  44 ++++
 components/camel-chaos/src/main/docs/chaos.adoc    |  44 ++++
 .../apache/camel/component/chaos/ChaosAdvisor.java | 245 +++++++++++++++++++++
 .../apache/camel/component/chaos/ChaosManager.java |  27 +++
 .../camel/component/chaos/ChaosAdvisorTest.java    | 117 ++++++++++
 design/chaos.adoc                                  |   4 +
 .../modules/ROOT/pages/camel-jbang-managing.adoc   |   3 +
 .../ROOT/pages/camel-jbang-tui-observe.adoc        |   3 +
 .../camel-jbang-cmd-chaos-suggest.adoc             |  26 +++
 .../ROOT/pages/jbang-commands/camel-jbang-cmd.adoc |   1 +
 .../apache/camel/cli/connector/ChaosAction.java    |   8 +-
 .../LocalCliConnectorChaosActionTest.java          |  11 +
 .../META-INF/camel-jbang-commands-metadata.json    |   2 +-
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   1 +
 .../commands/action/CamelChaosSuggestAction.java   |  79 +++++++
 .../core/commands/action/CamelChaosActionTest.java |  31 ++-
 .../src/test/resources/golden/cli-help.txt         |  30 +++
 .../src/test/resources/golden/cli-parse.txt        |   7 +
 .../dsl/jbang/core/commands/tui/ChaosControl.java  |  91 +++++++-
 .../jbang/core/commands/tui/ChaosSuggestList.java  | 163 ++++++++++++++
 .../src/main/resources/tui/help/chaos.md           |   5 +
 .../jbang/core/commands/tui/ChaosControlTest.java  |  38 +++-
 22 files changed, 974 insertions(+), 6 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/chaos.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/chaos.adoc
index 743afbc5e3a6..bfc599944098 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/chaos.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/chaos.adoc
@@ -124,6 +124,7 @@ camel cmd chaos-remove myapp --id=r1
 camel cmd chaos-clear
 camel cmd chaos-clear myapp --reset
 camel cmd chaos-load chaos/outage.chaos
+camel cmd chaos-suggest
 camel get chaos
 camel get chaos myapp --report
 ----
@@ -179,6 +180,49 @@ switched on in the integration (see 
<<_switching_it_on,Switching it on>>): they
 The `chaos` developer console (`/q/dev/chaos` with `camel run --console`) 
shows the same rules and report, as text or
 JSON. It only reads: a rule cannot be added, changed or removed over HTTP.
 
+=== What to try
+
+Where to start with a route you did not write? `camel cmd chaos-suggest` asks 
the running integration, and it suggests
+rules per route from what the routes do, the most worth trying first. Each is 
a known rule (see
+<<_the_model_of_the_rules,The model of the rules>>) with the endpoint or route 
filled in, why it is worth trying, and
+the command that adds it. Nothing is added.
+
+[source]
+----
+$ camel cmd chaos-suggest
+Chaos rules to try, the most worth trying first:
+
+1. route orders: Returns an error (HTTP status) (errors)
+   an HTTP call to http://stock/check without a circuit breaker: what does the 
route do when the service answers 503?
+   camel cmd chaos-add --rule='endpoint=http://stock/check error status=503 
rate=0.25 until=10m'
+
+2. route orders: The route after a hand-off fails (lost)
+   route orders hands the message to route shipping over seda and does not 
wait: when shipping fails, is the message lost?
+   camel cmd chaos-add --rule='route=shipping error rate=0.2 until=2m 
expect=orders->shipping:lost<=0 within=3m'
+----
+
+[cols="2,3"]
+|===
+|What a route does |What is suggested
+
+|An HTTP call, without a circuit breaker |The service answers with an error 
(`status=503`), and does not answer in time
+(`timeout`)
+|An HTTP call, in a route with a circuit breaker |The service is down for a 
while (`outage`): does the breaker open, and
+does the fallback answer?
+|A call over another protocol |The connection is refused, and the call is slow
+|An input that can deliver a message again (Kafka, JMS, AMQP, SQS and more, or 
a consumer that reads a failed message
+again, such as a file without `moveFailed`) |The call out is made twice 
(`duplicate`): is it safe to repeat?
+|A dead letter channel |It fails too (`at=dlq`): is the message then lost? Add 
it with a rule that fails the route.
+|A hand-off to another route over `seda`, `vm` or `disruptor` |The next route 
fails, with an expectation that no
+message is lost between the two routes (see 
<<_expectations_on_time_and_loss,Expectations on time and loss>>)
+|An input from outside (not `direct` or `seda`) |The route fails at its entry 
(what does the sender see: a rollback, a
+retry, an error?), or the polls fail for a polling consumer; and the route 
stalls for a while
+|===
+
+The rules leave the query of the endpoint out: its options do not tell which 
endpoint it is, and may hold a secret.
+`ChaosManager.suggest()` gives the same as JSON (`suggestions`: `route`, 
`kind`, `recipe`, `title`, `rule`, `why`), and
+the chaos screen of the Camel TUI lists them (key `w`), where Enter types the 
rule in to change or add.
+
 === From an AI agent (MCP)
 
 The Camel MCP server (`camel mcp`, see xref:manual::camel-jbang-mcp.adoc[Camel 
MCP server]) has the same operations
diff --git a/components/camel-chaos/src/main/docs/chaos.adoc 
b/components/camel-chaos/src/main/docs/chaos.adoc
index 743afbc5e3a6..bfc599944098 100644
--- a/components/camel-chaos/src/main/docs/chaos.adoc
+++ b/components/camel-chaos/src/main/docs/chaos.adoc
@@ -124,6 +124,7 @@ camel cmd chaos-remove myapp --id=r1
 camel cmd chaos-clear
 camel cmd chaos-clear myapp --reset
 camel cmd chaos-load chaos/outage.chaos
+camel cmd chaos-suggest
 camel get chaos
 camel get chaos myapp --report
 ----
@@ -179,6 +180,49 @@ switched on in the integration (see 
<<_switching_it_on,Switching it on>>): they
 The `chaos` developer console (`/q/dev/chaos` with `camel run --console`) 
shows the same rules and report, as text or
 JSON. It only reads: a rule cannot be added, changed or removed over HTTP.
 
+=== What to try
+
+Where to start with a route you did not write? `camel cmd chaos-suggest` asks 
the running integration, and it suggests
+rules per route from what the routes do, the most worth trying first. Each is 
a known rule (see
+<<_the_model_of_the_rules,The model of the rules>>) with the endpoint or route 
filled in, why it is worth trying, and
+the command that adds it. Nothing is added.
+
+[source]
+----
+$ camel cmd chaos-suggest
+Chaos rules to try, the most worth trying first:
+
+1. route orders: Returns an error (HTTP status) (errors)
+   an HTTP call to http://stock/check without a circuit breaker: what does the 
route do when the service answers 503?
+   camel cmd chaos-add --rule='endpoint=http://stock/check error status=503 
rate=0.25 until=10m'
+
+2. route orders: The route after a hand-off fails (lost)
+   route orders hands the message to route shipping over seda and does not 
wait: when shipping fails, is the message lost?
+   camel cmd chaos-add --rule='route=shipping error rate=0.2 until=2m 
expect=orders->shipping:lost<=0 within=3m'
+----
+
+[cols="2,3"]
+|===
+|What a route does |What is suggested
+
+|An HTTP call, without a circuit breaker |The service answers with an error 
(`status=503`), and does not answer in time
+(`timeout`)
+|An HTTP call, in a route with a circuit breaker |The service is down for a 
while (`outage`): does the breaker open, and
+does the fallback answer?
+|A call over another protocol |The connection is refused, and the call is slow
+|An input that can deliver a message again (Kafka, JMS, AMQP, SQS and more, or 
a consumer that reads a failed message
+again, such as a file without `moveFailed`) |The call out is made twice 
(`duplicate`): is it safe to repeat?
+|A dead letter channel |It fails too (`at=dlq`): is the message then lost? Add 
it with a rule that fails the route.
+|A hand-off to another route over `seda`, `vm` or `disruptor` |The next route 
fails, with an expectation that no
+message is lost between the two routes (see 
<<_expectations_on_time_and_loss,Expectations on time and loss>>)
+|An input from outside (not `direct` or `seda`) |The route fails at its entry 
(what does the sender see: a rollback, a
+retry, an error?), or the polls fail for a polling consumer; and the route 
stalls for a while
+|===
+
+The rules leave the query of the endpoint out: its options do not tell which 
endpoint it is, and may hold a secret.
+`ChaosManager.suggest()` gives the same as JSON (`suggestions`: `route`, 
`kind`, `recipe`, `title`, `rule`, `why`), and
+the chaos screen of the Camel TUI lists them (key `w`), where Enter types the 
rule in to change or add.
+
 === From an AI agent (MCP)
 
 The Camel MCP server (`camel mcp`, see xref:manual::camel-jbang-mcp.adoc[Camel 
MCP server]) has the same operations
diff --git 
a/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosAdvisor.java
 
b/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosAdvisor.java
new file mode 100644
index 000000000000..0decbcc9fdca
--- /dev/null
+++ 
b/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosAdvisor.java
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.chaos;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointAware;
+import org.apache.camel.Processor;
+import org.apache.camel.Route;
+import org.apache.camel.model.CircuitBreakerDefinition;
+import org.apache.camel.model.ProcessorDefinitionHelper;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.errorhandler.DeadLetterChannelDefinition;
+import org.apache.camel.support.ScheduledPollConsumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * What to try (CAMEL-26727): chaos rules suggested per route from what the 
route does, ranked, each a known rule of the
+ * chaos model ({@link ChaosModel#recipeList()}) with its target filled in and 
a line that says why. The facts come from
+ * the running routes: their sends, their circuit breakers, their dead letter 
channel, their input, and the hand-offs
+ * between them.
+ */
+final class ChaosAdvisor {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ChaosAdvisor.class);
+
+    /** The most suggestions in all, so a big integration does not flood a 
tool. */
+    static final int MAX = 40;
+
+    // the inputs that can deliver a message again (at least once), so a call 
out may be made twice
+    private static final Set<String> AT_LEAST_ONCE = Set.of(
+            "kafka", "jms", "activemq", "activemq6", "amqp", "sjms", "sjms2", 
"aws2-sqs", "google-pubsub",
+            "spring-rabbitmq", "rabbitmq", "nats", "paho", "paho-mqtt5", 
"azure-servicebus", "ibm-mq");
+    // a hand-off to another route of the same application, which does not 
wait for it
+    private static final Set<String> HAND_OFF = Set.of("seda", "vm", 
"disruptor", "disruptor-vm");
+
+    /** The kinds of faults, which the report also uses for what has been 
tried. */
+    enum Kind {
+        ERRORS("errors"),
+        SLOW("slow"),
+        LOST("lost"),
+        CORRUPT("corrupt"),
+        DUPLICATE("duplicate"),
+        CONSUMER("consumer"),
+        LIFECYCLE("lifecycle"),
+        DEAD_LETTER("dead letter channel");
+
+        final String key;
+
+        Kind(String key) {
+            this.key = key;
+        }
+    }
+
+    /**
+     * A rule to try.
+     *
+     * @param route  the route it is about
+     * @param kind   the kind of fault
+     * @param recipe the id of the known rule it comes from (null for one of 
its own)
+     * @param title  the known rule in plain words, such as "Returns an error 
(HTTP status)"
+     * @param rule   the rule, ready to add
+     * @param why    why it is worth trying for this route
+     * @param rank   higher is tried first
+     */
+    record Suggestion(String route, Kind kind, String recipe, String title, 
String rule, String why, int rank) {
+    }
+
+    private ChaosAdvisor() {
+    }
+
+    /** The rules to try for the routes of the context, the most worth trying 
first, at most {@link #MAX}. */
+    static List<Suggestion> suggest(CamelContext camelContext) {
+        Map<String, ChaosModel.Recipe> recipes = new LinkedHashMap<>();
+        for (ChaosModel.Recipe recipe : ChaosModel.recipeList()) {
+            recipes.put(recipe.id(), recipe);
+        }
+        List<Route> routes = camelContext.getRoutes();
+        // the routes that consume an endpoint, for the hand-offs
+        Map<String, String> consumers = new LinkedHashMap<>();
+        for (Route route : routes) {
+            if (route.getEndpoint() != null) {
+                consumers.put(uri(route.getEndpoint()), route.getRouteId());
+            }
+        }
+        List<Suggestion> answer = new ArrayList<>();
+        for (Route route : routes) {
+            try {
+                suggest(route, recipes, consumers, answer);
+            } catch (RuntimeException e) {
+                // the route changed while it was read (such as a reload): 
nothing to say for it now
+                LOG.debug("No chaos suggestions for route {}: {}", 
route.getRouteId(), e.getMessage(), e);
+            }
+        }
+        answer.sort(Comparator.comparingInt(Suggestion::rank).reversed());
+        return answer.size() > MAX ? List.copyOf(answer.subList(0, MAX)) : 
answer;
+    }
+
+    private static void suggest(
+            Route route, Map<String, ChaosModel.Recipe> recipes, Map<String, 
String> consumers, List<Suggestion> answer) {
+        String id = route.getRouteId();
+        Endpoint from = route.getEndpoint();
+        boolean breaker = route.getRoute() instanceof RouteDefinition 
definition
+                && 
!ProcessorDefinitionHelper.filterTypeInOutputs(definition.getOutputs(), 
CircuitBreakerDefinition.class)
+                        .isEmpty();
+        boolean atLeastOnce = from != null
+                && 
(AT_LEAST_ONCE.contains(ChaosPatterns.scheme(from.getEndpointUri())) || 
ChaosConsumers.keepsFailed(from));
+
+        // the sends: each endpoint once
+        Set<String> seen = new LinkedHashSet<>();
+        for (Processor processor : route.filter("*")) {
+            if (!(processor instanceof EndpointAware aware) || 
aware.getEndpoint() == null) {
+                continue;
+            }
+            Endpoint to = aware.getEndpoint();
+            String uri = uri(to);
+            if (!seen.add(uri)) {
+                continue;
+            }
+            String scheme = ChaosPatterns.scheme(uri);
+            if (HAND_OFF.contains(scheme) && consumers.containsKey(uri) && 
!id.equals(consumers.get(uri))) {
+                String next = consumers.get(uri);
+                answer.add(new Suggestion(
+                        id, Kind.LOST, "route-error", "The route after a 
hand-off fails",
+                        "route=" + next + " error rate=0.2 until=2m expect=" + 
id + "->" + next + ":lost<=0 within=3m",
+                        "route " + id + " hands the message to route " + next 
+ " over " + scheme + " and does not wait:"
+                                                                               
                                         + " when "
+                                                                               
                                         + next
+                                                                               
                                         + " fails, is the message lost?",
+                        85));
+                continue;
+            }
+            if (!to.isRemote()) {
+                continue;
+            }
+            if (ChaosRuleParser.HTTP_SCHEMES.contains(scheme)) {
+                if (breaker) {
+                    add(answer, recipes, "outage", id, Kind.ERRORS, 
Map.of("endpoint", uri),
+                            "a call to " + uri + " in a route with a circuit 
breaker: when the service is down for a"
+                                                                               
              + " while, does the breaker open, and does the fallback answer?",
+                            70);
+                } else {
+                    add(answer, recipes, "http-error", id, Kind.ERRORS, 
Map.of("endpoint", uri),
+                            "an HTTP call to " + uri + " without a circuit 
breaker: what does the route do when the"
+                                                                               
                  + " service answers 503?",
+                            90);
+                }
+                add(answer, recipes, "timeout", id, Kind.SLOW, 
Map.of("endpoint", uri),
+                        "a call to " + uri + " that may not answer in time: 
does the route give up, and retry?", 65);
+            } else {
+                add(answer, recipes, "connection-refused", id, Kind.ERRORS, 
Map.of("endpoint", uri),
+                        "a call to " + uri + ": what does the route do when 
the system is not there?", 75);
+                add(answer, recipes, "slow", id, Kind.SLOW, Map.of("endpoint", 
uri),
+                        "a call to " + uri + ": what does a slow answer do to 
the route and its input?", 50);
+            }
+            if (atLeastOnce) {
+                add(answer, recipes, "duplicate", id, Kind.DUPLICATE, 
Map.of("endpoint", uri),
+                        "the input of route " + id + " can deliver a message 
again: is the call to " + uri
+                                                                               
                + " safe to make twice?",
+                        80);
+            }
+        }
+
+        // the dead letter channel of the route
+        if (route.getErrorHandlerFactory() instanceof 
DeadLetterChannelDefinition dlc && dlc.getDeadLetterUri() != null) {
+            String dead = dlc.getDeadLetterUri().indexOf('?') > 0
+                    ? dlc.getDeadLetterUri().substring(0, 
dlc.getDeadLetterUri().indexOf('?')) : dlc.getDeadLetterUri();
+            add(answer, recipes, "dlq-unreachable", id, Kind.DEAD_LETTER, 
Map.of("endpoint", dead),
+                    "route " + id + " sends what fails to the dead letter 
channel " + dead
+                                                                               
                     + ": when that fails too, is the message lost? Add it with 
a rule that fails the route",
+                    78);
+        }
+
+        // the input of the route
+        if (from != null && from.isRemote()) {
+            if (route.getConsumer() instanceof ScheduledPollConsumer) {
+                add(answer, recipes, "poll-error", id, Kind.CONSUMER, 
Map.of("endpoint", uri(from)),
+                        "route " + id + " polls " + uri(from)
+                                                                               
                      + ": does it poll again after a failed poll?",
+                        55);
+            } else {
+                add(answer, recipes, "route-error", id, Kind.CONSUMER, 
Map.of("route", id),
+                        "route " + id + " is called from outside (" + 
ChaosPatterns.scheme(from.getEndpointUri())
+                                                                               
             + "): what does the sender see when it fails, a rollback, a retry"
+                                                                               
             + " or an error?",
+                        60);
+            }
+            add(answer, recipes, "stall", id, Kind.LIFECYCLE, Map.of("route", 
id),
+                    "route " + id + " stops taking messages for a while: does 
the sender wait, retry or lose them?", 30);
+        }
+    }
+
+    /**
+     * The URI of an endpoint as a rule targets it, without its query: the 
options say nothing of which endpoint it is,
+     * and may hold a secret.
+     */
+    private static String uri(Endpoint endpoint) {
+        String uri = ChaosPatterns.endpointUri(endpoint);
+        int query = uri.indexOf('?');
+        return query > 0 ? uri.substring(0, query) : uri;
+    }
+
+    /** A suggestion from a known rule, with its placeholders filled in: the 
given values, else their defaults. */
+    private static void add(
+            List<Suggestion> answer, Map<String, ChaosModel.Recipe> recipes, 
String recipeId, String route, Kind kind,
+            Map<String, String> values, String why, int rank) {
+        ChaosModel.Recipe recipe = recipes.get(recipeId);
+        if (recipe == null) {
+            return;
+        }
+        String rule = recipe.rule();
+        for (ChaosModel.Placeholder p : recipe.placeholders()) {
+            String value = values.getOrDefault(p.name(), p.defaultValue());
+            if (value == null) {
+                // a placeholder without a value, such as the header to 
remove: not a rule to add as it is
+                return;
+            }
+            rule = rule.replace("${" + p.name() + "}", value);
+        }
+        answer.add(new Suggestion(route, kind, recipe.id(), recipe.title(), 
rule, why, rank));
+    }
+}
diff --git 
a/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosManager.java
 
b/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosManager.java
index 44834b350280..e258ff01ddd4 100644
--- 
a/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosManager.java
+++ 
b/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosManager.java
@@ -461,6 +461,33 @@ public final class ChaosManager {
         }
     }
 
+    /**
+     * What to try (CAMEL-26727): rules suggested per route from what the 
routes do, the most worth trying first, each
+     * with the known rule it comes from and why, such as an HTTP call without 
a circuit breaker, a dead letter channel,
+     * or a hand-off to another route over seda.
+     *
+     * @return {@code suggestions}: a list of {@code route}, {@code kind}, 
{@code recipe}, {@code title}, {@code rule}
+     *         and {@code why}
+     */
+    public Map<String, Object> suggest() {
+        JsonArray list = new JsonArray();
+        for (ChaosAdvisor.Suggestion s : ChaosAdvisor.suggest(camelContext)) {
+            JsonObject jo = new JsonObject();
+            jo.put("route", s.route());
+            jo.put("kind", s.kind().key);
+            if (s.recipe() != null) {
+                jo.put("recipe", s.recipe());
+            }
+            jo.put("title", s.title());
+            jo.put("rule", s.rule());
+            jo.put("why", s.why());
+            list.add(jo);
+        }
+        JsonObject answer = new JsonObject();
+        answer.put("suggestions", list);
+        return answer;
+    }
+
     /**
      * Removes a rule. It stays in the report, and its expectation, if not 
decided yet, is cancelled.
      *
diff --git 
a/components/camel-chaos/src/test/java/org/apache/camel/component/chaos/ChaosAdvisorTest.java
 
b/components/camel-chaos/src/test/java/org/apache/camel/component/chaos/ChaosAdvisorTest.java
new file mode 100644
index 000000000000..9939da651eb3
--- /dev/null
+++ 
b/components/camel-chaos/src/test/java/org/apache/camel/component/chaos/ChaosAdvisorTest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.chaos;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * CAMEL-26727: what to try, the rules suggested per route from what the 
routes do.
+ */
+class ChaosAdvisorTest extends ChaosTestSupport {
+
+    @BindToRegistry("http")
+    private final TestHttpComponent http = new TestHttpComponent();
+
+    @BindToRegistry("testpoll")
+    private final TestPollComponent poll = new TestPollComponent();
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:orders").routeId("orders")
+                        .to("http://stock/check?throwExceptionOnFailure=true";)
+                        .to("seda:shipping");
+                from("seda:shipping?pollTimeout=10").routeId("shipping")
+                        .errorHandler(deadLetterChannel("seda:dlq"))
+                        .to("mock:ship");
+                from("seda:dlq?pollTimeout=10").routeId("dlq").to("mock:dead");
+                from("direct:pay").routeId("pay")
+                        .circuitBreaker()
+                        .to("http://pay/charge";)
+                        .onFallback().setBody(constant("later"))
+                        .end();
+                
from("testpoll:inbox?delay=100000&initialDelay=100000").routeId("inbox").to("mock:inbox");
+            }
+        };
+    }
+
+    private static Map<String, String> rules(List<ChaosAdvisor.Suggestion> 
suggestions) {
+        Map<String, String> answer = new LinkedHashMap<>();
+        suggestions.forEach(s -> answer.put(s.route() + " " + s.recipe() + " " 
+ s.kind().key, s.rule()));
+        return answer;
+    }
+
+    @Test
+    void whatToTryPerRouteFromWhatTheRoutesDo() {
+        List<ChaosAdvisor.Suggestion> suggestions = 
ChaosAdvisor.suggest(context);
+        Map<String, String> rules = rules(suggestions);
+
+        assertThat(rules)
+                .containsEntry("orders http-error errors", 
"endpoint=http://stock/check error status=503 rate=0.25 until=10m")
+                .containsEntry("orders timeout slow",
+                        "endpoint=http://stock/check error after=5s 
exception=java.net.SocketTimeoutException rate=0.1 until=10m")
+                // a hand-off over seda: the next route fails, and nothing may 
be lost between the two
+                .containsEntry("orders route-error lost",
+                        "route=shipping error rate=0.2 until=2m 
expect=orders->shipping:lost<=0 within=3m")
+                .containsEntry("shipping dlq-unreachable dead letter channel", 
"endpoint=seda:dlq error at=dlq")
+                // a circuit breaker: the service is down for a while
+                .containsEntry("pay outage errors", 
"endpoint=http://pay/charge error rate=burst:10s/1m until=10m")
+                .containsEntry("inbox poll-error consumer", 
"endpoint=testpoll://inbox error at=poll rate=0.5 until=10m")
+                .containsEntry("inbox stall lifecycle", "route=inbox stall 
duration=20s");
+        // no HTTP error without a breaker for the call inside the breaker, 
and the query is left out
+        assertThat(rules).doesNotContainKey("pay http-error errors");
+        assertThat(rules.values()).noneMatch(r -> 
r.contains("throwExceptionOnFailure"));
+        // an internal input (direct) is not a consumer to fail
+        assertThat(rules).doesNotContainKey("orders route-error consumer");
+
+        // the most worth trying first
+        assertThat(suggestions.get(0).recipe()).isEqualTo("http-error");
+        assertThat(suggestions.get(0).why()).contains("without a circuit 
breaker");
+    }
+
+    @Test
+    void everySuggestedRuleIsValid() {
+        for (ChaosAdvisor.Suggestion s : ChaosAdvisor.suggest(context)) {
+            String id = chaos().addRule(s.rule());
+            chaos().removeRule(id);
+        }
+    }
+
+    @Test
+    void theManagerGivesThemAsJson() {
+        JsonArray list = (JsonArray) chaos().suggest().get("suggestions");
+        JsonObject first = (JsonObject) list.get(0);
+        assertThat(first.getString("route")).isEqualTo("orders");
+        assertThat(first.getString("kind")).isEqualTo("errors");
+        assertThat(first.getString("recipe")).isEqualTo("http-error");
+        assertThat(first.getString("title")).isEqualTo("Returns an error (HTTP 
status)");
+        
assertThat(first.getString("rule")).startsWith("endpoint=http://stock/check 
error status=503");
+        assertThat(first.getString("why")).isNotBlank();
+    }
+}
diff --git a/design/chaos.adoc b/design/chaos.adoc
index c49fb05054ae..e8640c4ec29d 100644
--- a/design/chaos.adoc
+++ b/design/chaos.adoc
@@ -397,6 +397,10 @@ framework, so camel-test does not depend on camel-chaos; 
the rules come from the
 - A `chaos` dev console lists the rules and shows the report, so it is 
`@DevConsole(readOnly = true)`. It does not add,
   change or remove: the flag is metadata only, and `/q/dev/*` 
(`ManagementHttpServer`) takes GET and POST with the
   options in the query string, without checking it. So over HTTP chaos only 
lists and reports.
+- What to try (stage 2, CAMEL-26727): `ChaosManager.suggest()` and `camel cmd 
chaos-suggest` suggest rules per route
+  from the running routes (their sends, circuit breakers, dead letter channel, 
input and hand-offs), each a recipe of
+  the chaos model with its target filled in and why. The About screen hints 
(CAMEL-26716) are meant to be one shared
+  rule set; these facts come from the running context, and can become the 
chaos part of that set.
 - A `chaos` action of the CLI connector (`LocalCliConnector`) adds, changes 
and removes rules through the
   `ChaosManager`. The CLI has the flat verb-noun shape of every `camel cmd` 
today (`stop-route`, `stub`), with the
   reads under `camel get` (as `camel get circuit-breaker`): `camel cmd 
chaos-add`, `chaos-change`, `chaos-remove`,
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
index f7f162c01096..4a22dbc61675 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
@@ -905,6 +905,9 @@ only integration that runs, or the only one with chaos 
switched on, and otherwis
 integrations. `chaos-add` prints the rule in plain words too (`fail 30% of the 
sends to kafka:orders*, for 1 minute`),
 and with `--dry-run` it adds nothing, and prints what the rule would hit now: 
the sends, polls, routes or steps, with
 their route.
+`camel cmd chaos-suggest` suggests rules to try per route from what the routes 
do (an HTTP call without a circuit
+breaker, a dead letter channel, a hand-off over seda, an input from outside), 
the most worth trying first, each with
+why and the `chaos-add` command that adds it.
 `camel get chaos` lists the current rules with their id, version, state, 
matches and the faults that fired, and
 `--report` shows the report: the verdict, the seed, every version of every 
rule and the counts per route. Chaos is for
 development only: it stays off with profile `prod`, and the commands cannot 
switch it on.
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-observe.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-observe.adoc
index 18ac3e5c79c4..76ddebd9f680 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-observe.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-observe.adoc
@@ -328,6 +328,9 @@ values start with a default, and the rule is shown as it is 
built. The last entr
 (`endpoint=kafka:orders* error rate=0.1 until=5m`).
 +
 image::jbang/camel-tui-chaos-recipes.png[Adding a chaos rule from the known 
rules: the HTTP endpoint of the route is picked]
+* *w* shows what to try: the integration suggests rules per route from what 
its routes do, the most worth trying
+first, each with why (see the camel-chaos documentation, "What to try"). Enter 
types the selected rule in, to change
+or add.
 * *e* changes the selected rule, starting from the rule as it is.
 * *!* on the Endpoint tab, the Consumers tab or a node of the Diagram opens 
the known rules for what is selected, with
 it filled in: for a `to` or an endpoint the routes send to, the faults of that 
endpoint (an HTTP status only for an
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd-chaos-suggest.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd-chaos-suggest.adoc
new file mode 100644
index 000000000000..10589a3cd196
--- /dev/null
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd-chaos-suggest.adoc
@@ -0,0 +1,26 @@
+
+// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
+= camel cmd chaos-suggest
+
+Suggest chaos rules to try in a running integration, per route (camel-chaos, 
for development only)
+
+
+== Usage
+
+[source,bash]
+----
+camel cmd chaos-suggest [options]
+----
+
+
+
+== Options
+
+[cols="2,5,1,2",options="header"]
+|===
+| Option | Description | Default | Type
+| `--timeout` | How long to wait for the integration to answer, in millis or 
as a duration such as 30s | 10000 | long
+| `-h,--help` | Display the help and sub-commands |  | boolean
+|===
+
+
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd.adoc
index e4902c686875..f6a8cd0288cb 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd.adoc
@@ -24,6 +24,7 @@ camel cmd [options]
 | xref:jbang-commands/camel-jbang-cmd-chaos-clear.adoc[chaos-clear] | Remove 
all chaos rules of running integrations (camel-chaos, for development only)
 | xref:jbang-commands/camel-jbang-cmd-chaos-load.adoc[chaos-load] | Load a 
chaos scenario into a running integration (camel-chaos, for development only)
 | xref:jbang-commands/camel-jbang-cmd-chaos-remove.adoc[chaos-remove] | Remove 
a chaos rule of a running integration (camel-chaos, for development only)
+| xref:jbang-commands/camel-jbang-cmd-chaos-suggest.adoc[chaos-suggest] | 
Suggest chaos rules to try in a running integration, per route (camel-chaos, 
for development only)
 | 
xref:jbang-commands/camel-jbang-cmd-disable-processor.adoc[disable-processor] | 
Disable Camel processor
 | xref:jbang-commands/camel-jbang-cmd-enable-processor.adoc[enable-processor] 
| Enable Camel processor
 | xref:jbang-commands/camel-jbang-cmd-gc.adoc[gc] | Trigger Java Memory 
Garbage Collector
diff --git 
a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/ChaosAction.java
 
b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/ChaosAction.java
index 78c2dca86370..07e1fc7fcb2b 100644
--- 
a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/ChaosAction.java
+++ 
b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/ChaosAction.java
@@ -82,6 +82,12 @@ final class ChaosAction {
                 answer.put("version", 1);
                 descriptions(type, chaos, ids, answer);
                 warnings(type, chaos, ids, answer);
+            } else if ("suggest".equals(command)) {
+                // what to try: rules suggested per route from what the routes 
do (read only)
+                Method suggest = type.getMethod("suggest");
+                @SuppressWarnings("unchecked")
+                Map<String, Object> suggested = (Map<String, Object>) 
suggest.invoke(chaos);
+                answer.putAll(suggested);
             } else if ("load".equals(command)) {
                 String text = root.getString("text");
                 if (isBlank(text)) {
@@ -136,7 +142,7 @@ final class ChaosAction {
                     answer.put("reset", true);
                 }
             } else {
-                output.error("Unknown chaos command: " + command + " (add, 
check, change, remove, clear or load)");
+                output.error("Unknown chaos command: " + command + " (add, 
check, change, remove, clear, load or suggest)");
                 return;
             }
         } catch (IllegalArgumentException | IllegalStateException e) {
diff --git 
a/dsl/camel-cli-connector/src/test/java/org/apache/camel/cli/connector/LocalCliConnectorChaosActionTest.java
 
b/dsl/camel-cli-connector/src/test/java/org/apache/camel/cli/connector/LocalCliConnectorChaosActionTest.java
index f2d09f45975c..5e5c827e7a8b 100644
--- 
a/dsl/camel-cli-connector/src/test/java/org/apache/camel/cli/connector/LocalCliConnectorChaosActionTest.java
+++ 
b/dsl/camel-cli-connector/src/test/java/org/apache/camel/cli/connector/LocalCliConnectorChaosActionTest.java
@@ -211,6 +211,17 @@ class LocalCliConnectorChaosActionTest {
         assertThat(reportRules()).hasSize(2);
     }
 
+    @Test
+    void suggestWhatToTry() throws Exception {
+        start(null, Map.of("camel.chaos.enabled", "true"));
+
+        CliActionOutcome suggested = chaos("suggest", null, null);
+        assertThat(suggested.error()).isNull();
+        // the route of the test only calls local endpoints: nothing to 
suggest, and nothing was added
+        assertThat((JsonArray) 
suggested.result().get("suggestions")).isNotNull();
+        assertThat(reportRules()).isEmpty();
+    }
+
     @Test
     void rulesAreAddedTogetherWithWarningsForTheOnesThatMatchNothing() throws 
Exception {
         start(null, Map.of("camel.chaos.enabled", "true"));
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index 172347fb8b8b..ce4287ac149b 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -3,7 +3,7 @@
     { "name": "ask", "fullName": "ask", "description": "Ask a question about a 
running Camel application using AI", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Ask", "options": [ { "names": 
"--api-key", "description": "API key. Also reads ANTHROPIC_API_KEY, 
OPENAI_API_KEY, WATSONX_APIKEY, or LLM_API_KEY env vars", "javaType": 
"java.lang.String", "type": "string" }, { "names": "--api-type", "description": 
"API type: 'ollama', 'openai', 'anthropic', or 'watsonx'", "javaType":  [...]
     { "name": "bind", "fullName": "bind", "description": "DEPRECATED: Bind 
source and sink Kamelets as a new Camel integration", "deprecated": true, 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.bind.Bind", "options": 
[ { "names": "--error-handler", "description": "Add error handler 
(none|log|sink:<endpoint>). Sink endpoints are expected in the format 
\"[[apigroup\/]version:]kind:[namespace\/]name\", plain Camel URIs or Kamelet 
name.", "javaType": "java.lang.String", "type": " [...]
     { "name": "catalog", "fullName": "catalog", "description": "List artifacts 
from Camel Catalog", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.catalog.CatalogCommand", "options": [ 
{ "names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"component", "fullName": "catalog component", "description": "List components 
from the Camel Catalog", "sourceClass": "org.apache.camel.dsl.jbang.co [...]
-    { "name": "cmd", "fullName": "cmd", "description": "Performs commands in 
the running Camel integrations, such as start\/stop route, or change logging 
levels.", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.action.CamelAction", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"browse", "fullName": "cmd browse", "description": "Browse pending messages on 
endpoints [...]
+    { "name": "cmd", "fullName": "cmd", "description": "Performs commands in 
the running Camel integrations, such as start\/stop route, or change logging 
levels.", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.action.CamelAction", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"browse", "fullName": "cmd browse", "description": "Browse pending messages on 
endpoints [...]
     { "name": "completion", "fullName": "completion", "description": "Generate 
completion script for bash\/zsh", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Complete", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
     { "name": "config", "fullName": "config", "description": "Get and set user 
configuration values", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.config.ConfigCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "get", 
"fullName": "config get", "description": "Display user configuration value", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.config. [...]
     { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "How [...]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 48391d19f438..fb056fd2da4e 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -264,6 +264,7 @@ public class CamelJBangMain implements Callable<Integer> {
                     .addSubcommand("chaos-clear", new CommandLine(new 
CamelChaosClearAction(this)))
                     .addSubcommand("chaos-load", new CommandLine(new 
CamelChaosLoadAction(this)))
                     .addSubcommand("chaos-remove", new CommandLine(new 
CamelChaosRemoveAction(this)))
+                    .addSubcommand("chaos-suggest", new CommandLine(new 
CamelChaosSuggestAction(this)))
                     .addSubcommand("disable-processor", new CommandLine(new 
CamelProcessorDisableAction(this)))
                     .addSubcommand("enable-processor", new CommandLine(new 
CamelProcessorEnableAction(this)))
                     .addSubcommand("gc", new CommandLine(new 
CamelGCAction(this)))
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosSuggestAction.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosSuggestAction.java
new file mode 100644
index 000000000000..f8378239071a
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosSuggestAction.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.action;
+
+import java.util.List;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.ProcessFinder.CamelProcess;
+import org.apache.camel.util.json.JsonObject;
+import picocli.CommandLine;
+
[email protected](name = "chaos-suggest",
+                     description = "Suggest chaos rules to try in a running 
integration, per route (camel-chaos, for development only)",
+                     sortOptions = false, showDefaultValues = true,
+                     footer = {
+                             "%nThe rules come from what the routes do: an 
HTTP call without a circuit breaker",
+                             "(the service answers with an error, or does not 
answer in time), a circuit",
+                             "breaker (the service is down for a while), a 
call that the input may repeat",
+                             "(Kafka, JMS: the call is made twice), a dead 
letter channel (it fails too), a",
+                             "hand-off to another route over seda (the next 
route fails, and no message may",
+                             "be lost between the two), an input from outside 
(the route fails at its entry,",
+                             "the polls fail, the route stalls). The most 
worth trying come first, each with",
+                             "why and the command that adds it. Nothing is 
added.",
+                             "%nWithout a name or pid, the only integration 
that runs, or the only one with",
+                             "chaos switched on.",
+                             "%nExamples:",
+                             "  camel cmd chaos-suggest",
+                             "  camel cmd chaos-suggest myApp" })
+public class CamelChaosSuggestAction extends CamelChaosAction {
+
+    @CommandLine.Parameters(description = "Name or pid of the running Camel 
integration (must match one); without it,"
+                                          + " the only one running, or the 
only one with chaos switched on",
+                            arity = "0..1")
+    String name;
+
+    public CamelChaosSuggestAction(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer doCall() throws Exception {
+        CamelProcess process = findChaosTarget(name);
+        printer().println(describe(chaos(process, "suggest", null)));
+        return 0;
+    }
+
+    @Override
+    protected String describe(JsonObject answer) {
+        List<Object> suggestions = answer.getCollection("suggestions");
+        if (suggestions == null || suggestions.isEmpty()) {
+            return "Nothing to suggest: the routes call nothing remote, and 
have no input from outside, dead letter"
+                   + " channel or hand-off to another route";
+        }
+        StringBuilder sb = new StringBuilder("Chaos rules to try, the most 
worth trying first:");
+        int n = 0;
+        for (Object o : suggestions) {
+            JsonObject s = (JsonObject) o;
+            sb.append("\n\n").append(++n).append(". route 
").append(s.getString("route")).append(": ")
+                    .append(s.getString("title")).append(" 
(").append(s.getString("kind")).append(')');
+            sb.append("\n   ").append(s.getString("why"));
+            sb.append("\n   camel cmd chaos-add 
--rule='").append(s.getString("rule")).append('\'');
+        }
+        return sb.toString();
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosActionTest.java
index b5e9d6af07ec..612dbeadb814 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosActionTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosActionTest.java
@@ -36,8 +36,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 /**
- * camel cmd chaos-add, chaos-change, chaos-remove, chaos-clear and 
chaos-load: the chaos action they send, what they
- * print, and that a refused rule is an error with the reason of the 
integration.
+ * camel cmd chaos-add, chaos-change, chaos-remove, chaos-clear, chaos-load 
and chaos-suggest: the chaos action they
+ * send, what they print, and that a refused rule is an error with the reason 
of the integration.
  */
 @ExtendWith(MockitoExtension.class)
 class CamelChaosActionTest extends ActionCommandTestSupport {
@@ -99,6 +99,33 @@ class CamelChaosActionTest extends ActionCommandTestSupport {
                 .hasMessageStartingWith("Chaos is off in this integration");
     }
 
+    @Test
+    void suggestPrintsWhatToTryWithTheCommandThatAddsIt() throws Exception {
+        writeStatusFile(TEST_PID, "orders");
+        JsonObject suggestion = new JsonObject(
+                Map.of("route", "orders", "kind", "errors", "recipe", 
"http-error",
+                        "title", "Returns an error (HTTP status)",
+                        "rule", "endpoint=http://stock/check error status=503 
rate=0.25 until=10m",
+                        "why", "an HTTP call to http://stock/check without a 
circuit breaker: what does the route do when the"
+                               + " service answers 503?"));
+        JsonObject answer = new JsonObject(Map.of("suggestions", new 
JsonArray(List.of(suggestion))));
+
+        assertThat(callWithResponse(command(new 
CamelChaosSuggestAction(main()), "orders"), answer)).isZero();
+
+        
assertThat(readActionFile(TEST_PID).getString("command")).isEqualTo("suggest");
+        assertThat(printer.getLines()).contains("Chaos rules to try, the most 
worth trying first:",
+                "1. route orders: Returns an error (HTTP status) (errors)",
+                "camel cmd chaos-add --rule='endpoint=http://stock/check error 
status=503 rate=0.25 until=10m'");
+    }
+
+    @Test
+    void suggestSaysWhenThereIsNothingToTry() throws Exception {
+        writeStatusFile(TEST_PID, "orders");
+        assertThat(callWithResponse(command(new 
CamelChaosSuggestAction(main()), "orders"),
+                new JsonObject(Map.of("suggestions", new 
JsonArray())))).isZero();
+        assertThat(printer.getOutput()).startsWith("Nothing to suggest");
+    }
+
     @Test
     void loadSendsTheScenario(@TempDir Path dir) throws Exception {
         writeStatusFile(TEST_PID, "orders");
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-help.txt 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-help.txt
index 77e2357f62b9..51a4c91f3dc1 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-help.txt
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-help.txt
@@ -562,6 +562,8 @@ Commands:
                        (camel-chaos, for development only)
   chaos-remove       Remove a chaos rule of a running integration (camel-chaos,
                        for development only)
+  chaos-suggest      Suggest chaos rules to try in a running integration, per
+                       route (camel-chaos, for development only)
   disable-processor  Disable Camel processor
   enable-processor   Enable Camel processor
   gc                 Trigger Java Memory Garbage Collector
@@ -790,6 +792,34 @@ Examples:
   camel cmd chaos-remove --id=r1
   camel cmd chaos-remove myApp --id=r1
 
+== camel cmd chaos-suggest --help
+Usage: camel cmd chaos-suggest [-h] [--timeout=<timeout>] [<name>]
+Suggest chaos rules to try in a running integration, per route (camel-chaos,
+for development only)
+      [<name>]              Name or pid of the running Camel integration (must
+                              match one); without it, the only one running, or
+                              the only one with chaos switched on
+  -h, --help                Display the help and sub-commands
+      --timeout=<timeout>   How long to wait for the integration to answer, in
+                              millis or as a duration such as 30s
+                              Default: 10000
+
+The rules come from what the routes do: an HTTP call without a circuit breaker
+(the service answers with an error, or does not answer in time), a circuit
+breaker (the service is down for a while), a call that the input may repeat
+(Kafka, JMS: the call is made twice), a dead letter channel (it fails too), a
+hand-off to another route over seda (the next route fails, and no message may
+be lost between the two), an input from outside (the route fails at its entry,
+the polls fail, the route stalls). The most worth trying come first, each with
+why and the command that adds it. Nothing is added.
+
+Without a name or pid, the only integration that runs, or the only one with
+chaos switched on.
+
+Examples:
+  camel cmd chaos-suggest
+  camel cmd chaos-suggest myApp
+
 == camel cmd disable-processor --help
 Usage: camel cmd disable-processor [-h] [--id=<id>] [--timeout=<timeout>]
                                    [<name>]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-parse.txt 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-parse.txt
index eb2dc03c90b6..dbae4927d33f 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-parse.txt
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-parse.txt
@@ -567,6 +567,13 @@
   timeoutOption.timeout=10000
 > cmd chaos-remove --id v --timeout 7
   timeoutOption.timeout=7
+> cmd chaos-suggest
+  cmd:helpRequested=false
+  helpRequested=false
+  name=null
+  timeoutOption.timeout=10000
+> cmd chaos-suggest --timeout 7
+  timeoutOption.timeout=7
 > cmd disable-processor
   cmd:helpRequested=false
   helpRequested=false
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosControl.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosControl.java
index 0b4e76b4bcf4..e951863834b7 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosControl.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosControl.java
@@ -59,6 +59,8 @@ final class ChaosControl {
         NONE,
         // the known rules to pick from, and the form of the one picked
         RECIPES,
+        // what to try, the rules the integration suggests (null while it is 
asked)
+        SUGGEST,
         INPUT,
         CONFIRM,
         RESULT
@@ -86,6 +88,7 @@ final class ChaosControl {
     private ChaosRecipes recipes;
     private boolean recipesLoaded;
     private ChaosRecipeForm form;
+    private volatile ChaosSuggestList suggestions;
     // set by the background task that sends the action, read when the screen 
is drawn
     private volatile Step step = Step.NONE;
     private Command command;
@@ -127,7 +130,7 @@ final class ChaosControl {
 
     boolean isTextInputActive() {
         // the list of known rules takes the keys too, so a digit or a letter 
does not leave the screen
-        return step == Step.INPUT || step == Step.RECIPES;
+        return step == Step.INPUT || step == Step.RECIPES || step == 
Step.SUGGEST;
     }
 
     boolean isConfirming() {
@@ -150,6 +153,9 @@ final class ChaosControl {
             case RECIPES -> {
                 return handleRecipeKey(ke);
             }
+            case SUGGEST -> {
+                return handleSuggestKey(ke);
+            }
             case INPUT -> {
                 return handleInputKey(ke);
             }
@@ -215,6 +221,11 @@ final class ChaosControl {
             ask(Command.RESET);
             return true;
         }
+        if (ke.isChar('w')) {
+            // what to try: the rules the integration suggests from what its 
routes do (CAMEL-26727)
+            askWhatToTry();
+            return true;
+        }
         if (ke.isChar('s') && !info.chaos.rules.isEmpty()) {
             // the rules as a scenario of the project, for chaos-load and 
camel run --chaos=<file>
             describing = info;
@@ -252,6 +263,61 @@ final class ChaosControl {
         }
     }
 
+    /** Asks the integration what to try, in the background; the list shows 
when it answers. */
+    private void askWhatToTry() {
+        suggestions = null;
+        step = Step.SUGGEST;
+        JsonObject request = new JsonObject();
+        request.put("action", "chaos");
+        request.put("command", "suggest");
+        String target = pid;
+        String of = name;
+        Runnable task = () -> {
+            JsonObject reply = sender != null ? sender.apply(request) : 
ctx.executeAction(target, request, 5000);
+            if (step != Step.SUGGEST) {
+                // closed while it was asked
+                return;
+            }
+            if (reply == null || reply.getString("error") != null) {
+                step = Step.NONE;
+                resultLines.clear();
+                rule = null;
+                command = Command.ADD;
+                result("What to try", true, reply == null
+                        ? "The integration " + of + " did not answer"
+                        : reply.getString("error"));
+                return;
+            }
+            suggestions = new ChaosSuggestList(of, reply);
+        };
+        if (sender != null) {
+            task.run();
+        } else {
+            ctx.backgroundExecutor.execute(task);
+        }
+    }
+
+    private boolean handleSuggestKey(KeyEvent ke) {
+        ChaosSuggestList list = suggestions;
+        if (list == null) {
+            if (ke.isCancel()) {
+                close();
+            }
+            return true;
+        }
+        switch (list.handleKey(ke)) {
+            case CLOSED -> close();
+            case PICKED -> {
+                id = null;
+                openInput(Command.ADD, list.selected().rule());
+            }
+            default -> {
+                // the list used the key
+            }
+        }
+        return true;
+    }
+
     /** Opens a rule typed as one line, to change before Enter: a rule that 
makes a real error again (CAMEL-26723). */
     void openRule(IntegrationInfo info, String text) {
         if (!ChaosHere.available(info)) {
@@ -391,6 +457,10 @@ final class ChaosControl {
             // the form goes back to the list, the list closes
             return handleRecipeKey(KeyEvent.ofKey(KeyCode.ESCAPE));
         }
+        if (step == Step.SUGGEST) {
+            close();
+            return true;
+        }
         close();
         return true;
     }
@@ -399,6 +469,7 @@ final class ChaosControl {
         step = Step.NONE;
         input = null;
         form = null;
+        suggestions = null;
         describing = null;
     }
 
@@ -521,6 +592,15 @@ final class ChaosControl {
     void render(Frame frame, Rect area) {
         switch (step) {
             case RECIPES -> form.render(frame, area);
+            case SUGGEST -> {
+                ChaosSuggestList list = suggestions;
+                if (list != null) {
+                    list.render(frame, area);
+                } else {
+                    DialogHelper.renderConfirm(frame, area, "What to Try", 
"Asking " + name + " what to try...", null,
+                            "Esc", "cancel", null, null);
+                }
+            }
             case INPUT -> {
                 if (command == Command.DESCRIBE) {
                     DialogHelper.renderInputDialog(frame, area, "Describe the 
chaos you want in " + name, input,
@@ -611,6 +691,14 @@ final class ChaosControl {
     void renderFooter(List<Span> spans, boolean hasRules) {
         switch (step) {
             case RECIPES -> form.renderFooter(spans);
+            case SUGGEST -> {
+                ChaosSuggestList list = suggestions;
+                if (list != null) {
+                    list.renderFooter(spans);
+                } else {
+                    TuiHelper.hint(spans, "Esc", "cancel");
+                }
+            }
             case INPUT -> {
                 TuiHelper.hint(spans, "Enter",
                         command == Command.DESCRIBE ? "ask the AI" : command 
== Command.SAVE ? "save" : "confirm");
@@ -624,6 +712,7 @@ final class ChaosControl {
             default -> {
                 TuiHelper.hint(spans, "Esc", "back");
                 TuiHelper.hint(spans, "a", "add");
+                TuiHelper.hint(spans, "w", "what to try");
                 if (hasRules) {
                     TuiHelper.hint(spans, "e", "change");
                     TuiHelper.hint(spans, "x", "remove");
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosSuggestList.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosSuggestList.java
new file mode 100644
index 000000000000..8915cff7450b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosSuggestList.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.tui;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import dev.tamboui.layout.Constraint;
+import dev.tamboui.layout.Layout;
+import dev.tamboui.layout.Rect;
+import dev.tamboui.style.Overflow;
+import dev.tamboui.style.Style;
+import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.Line;
+import dev.tamboui.text.Span;
+import dev.tamboui.text.Text;
+import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.widgets.Clear;
+import dev.tamboui.widgets.block.Block;
+import dev.tamboui.widgets.block.BorderType;
+import dev.tamboui.widgets.block.Borders;
+import dev.tamboui.widgets.paragraph.Paragraph;
+import org.apache.camel.util.json.JsonObject;
+
+/**
+ * What to try ({@code w} on the Chaos screen, CAMEL-26727): the rules the 
integration suggests per route from what its
+ * routes do, the most worth trying first, each with why. Enter types the 
selected rule in, to change or add.
+ */
+final class ChaosSuggestList {
+
+    /** What a key did to the list. */
+    enum Outcome {
+        NONE,
+        CLOSED,
+        PICKED
+    }
+
+    /** A suggestion, as the chaos action of the integration gives it. */
+    record Item(String route, String kind, String title, String rule, String 
why) {
+    }
+
+    private final String name;
+    private final List<Item> items = new ArrayList<>();
+    private int selected;
+
+    ChaosSuggestList(String name, JsonObject reply) {
+        this.name = name;
+        if (reply != null && reply.getCollection("suggestions") != null) {
+            for (Object o : reply.getCollection("suggestions")) {
+                if (o instanceof JsonObject jo && jo.getString("rule") != 
null) {
+                    items.add(new Item(
+                            jo.getString("route"), jo.getString("kind"), 
jo.getString("title"),
+                            jo.getString("rule"), jo.getString("why")));
+                }
+            }
+        }
+    }
+
+    List<Item> items() {
+        return items;
+    }
+
+    /** The selected suggestion, or null when there are none. */
+    Item selected() {
+        return items.isEmpty() ? null : items.get(selected);
+    }
+
+    Outcome handleKey(KeyEvent ke) {
+        if (ke.isCancel()) {
+            return Outcome.CLOSED;
+        }
+        if (ke.isUp() && selected > 0) {
+            selected--;
+        } else if (ke.isDown() && selected < items.size() - 1) {
+            selected++;
+        } else if (ke.isConfirm() && !items.isEmpty()) {
+            return Outcome.PICKED;
+        }
+        return Outcome.NONE;
+    }
+
+    void render(Frame frame, Rect area) {
+        int width = Math.min(area.width() - 4, 150);
+        int height = Math.min(area.height() - 2, 30);
+        Rect popup = DialogHelper.centered(area, width, height);
+        frame.renderWidget(Clear.INSTANCE, popup);
+        Block outer = 
Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL).borderStyle(Theme.warning())
+                .title(" What to try in " + name + " ").build();
+        frame.renderWidget(outer, popup);
+        Rect inner = outer.inner(popup);
+        if (items.isEmpty()) {
+            
frame.renderWidget(Paragraph.builder().overflow(Overflow.WRAP_WORD).text(Text.from(List.of(Line.empty(),
+                    Line.from(Span.styled(" Nothing to suggest: the routes 
call nothing remote, and have no input from"
+                                          + " outside, dead letter channel or 
hand-off to another route",
+                            Theme.muted())))))
+                    .build(),
+                    inner);
+            return;
+        }
+        List<Rect> cols = Layout.horizontal()
+                .constraints(Constraint.length(Math.min(56, inner.width() / 
2)), Constraint.fill())
+                .split(inner);
+        renderList(frame, cols.get(0));
+        renderDetail(frame, cols.get(1));
+    }
+
+    private void renderList(Frame frame, Rect area) {
+        List<Line> lines = new ArrayList<>();
+        lines.add(Line.from(Span.styled(" The most worth trying first", 
Style.EMPTY.bold())));
+        int selectedLine = 0;
+        for (int i = 0; i < items.size(); i++) {
+            Item item = items.get(i);
+            boolean sel = i == selected;
+            if (sel) {
+                selectedLine = lines.size();
+            }
+            Style style = sel ? Theme.selectionBg().bold() : Style.EMPTY;
+            List<Span> spans = new ArrayList<>();
+            spans.add(Span.styled((sel ? " > " : "   ") + item.title(), 
style));
+            spans.add(Span.styled("  " + item.route(), Theme.muted()));
+            lines.add(Line.from(spans));
+        }
+        // keep the selected one in sight
+        int scroll = Math.max(0, selectedLine - (area.height() - 2));
+        
frame.renderWidget(Paragraph.builder().text(Text.from(lines)).scroll(scroll)
+                
.block(Block.builder().borders(EnumSet.of(Borders.RIGHT)).borderStyle(Theme.border()).build()).build(),
 area);
+    }
+
+    private void renderDetail(Frame frame, Rect area) {
+        Item item = selected();
+        List<Line> lines = new ArrayList<>();
+        lines.add(Line.from(Span.styled(" " + item.title(), 
Style.EMPTY.bold()),
+                Span.styled("  route " + item.route() + " · " + item.kind(), 
Theme.muted())));
+        lines.add(Line.empty());
+        lines.add(Line.from(Span.raw(" " + item.why())));
+        lines.add(Line.empty());
+        lines.add(Line.from(Span.styled(" " + item.rule(), Theme.warning())));
+        
frame.renderWidget(Paragraph.builder().overflow(Overflow.WRAP_WORD).text(Text.from(lines)).build(),
 area);
+    }
+
+    void renderFooter(List<Span> spans) {
+        if (!items.isEmpty()) {
+            TuiHelper.hint(spans, "↑↓", "choose");
+            TuiHelper.hint(spans, "Enter", "type it in");
+        }
+        TuiHelper.hint(spans, "Esc", "close");
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/help/chaos.md 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/help/chaos.md
index 7e7be29d76be..3ee695aad9a6 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/help/chaos.md
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/help/chaos.md
@@ -73,6 +73,11 @@ error handler (HAND) and the redeliveries (REDEL).
   the rule is shown as it is built. The last entry, "Write the rule
   yourself", types it as one line, such as
   `endpoint=kafka:orders* error rate=0.1 until=5m`
+- **w** — What to try: the integration suggests rules per route from what
+  its routes do (an HTTP call without a circuit breaker, a dead letter
+  channel, a hand-off over seda, an input from outside), the most worth
+  trying first, each with why. Enter types the selected rule in, to change
+  it or add it after you confirm
 - **e** — Change the selected rule: the line starts with the rule as it is
 - **x** — Remove the selected rule
 - **c** — Clear: remove all rules (the report keeps what they did)
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosControlTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosControlTest.java
index dbca4cfb092a..6f6daeacbc72 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosControlTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosControlTest.java
@@ -225,6 +225,41 @@ class ChaosControlTest {
         assertThat(footer.stream().map(Span::content).reduce("", 
String::concat)).doesNotContain("add");
     }
 
+    @Test
+    void whatToTryListsTheSuggestionsAndTypesThePickedOneIn() throws Exception 
{
+        reply = (JsonObject) Jsoner.deserialize("""
+                {"suggestions": [
+                  {"route": "orders", "kind": "errors", "recipe": 
"http-error", "title": "Returns an error (HTTP status)",
+                   "rule": "endpoint=http://stock/check error status=503 
rate=0.25 until=10m",
+                   "why": "an HTTP call to http://stock/check without a 
circuit breaker"},
+                  {"route": "shipping", "kind": "dead letter channel", 
"recipe": "dlq-unreachable",
+                   "title": "The dead letter channel is unreachable", "rule": 
"endpoint=seda:dlq error at=dlq",
+                   "why": "route shipping sends what fails to the dead letter 
channel seda:dlq"}]}
+                """);
+        key('w');
+        assertThat(requests).singleElement().satisfies(r -> 
assertThat(r.getString("command")).isEqualTo("suggest"));
+        String screen = TuiTestHelper.renderToString(tab, 160, 40);
+        assertThat(screen).contains("What to try in 
chaosdemo").contains("Returns an error (HTTP status)")
+                .contains("without a circuit breaker").contains("The dead 
letter channel is unreachable");
+
+        tab.handleKeyEvent(KeyEvent.ofKey(KeyCode.DOWN, KeyModifiers.NONE));
+        enter();
+        assertThat(tab.isTextInputActive()).isTrue();
+        assertThat(TuiTestHelper.renderToString(tab, 160, 40)).contains("Add a 
chaos rule to chaosdemo")
+                .contains("endpoint=seda:dlq error at=dlq");
+        // only added after Enter and the confirmation
+        assertThat(requests).hasSize(1);
+    }
+
+    @Test
+    void whatToTryWithNothingToSuggest() throws Exception {
+        reply = (JsonObject) Jsoner.deserialize("{\"suggestions\": []}");
+        key('w');
+        assertThat(TuiTestHelper.renderToString(tab, 160, 
40)).contains("Nothing to suggest");
+        tab.handleKeyEvent(KeyEvent.ofKey(KeyCode.ESCAPE, KeyModifiers.NONE));
+        assertThat(tab.control().isOpen()).isFalse();
+    }
+
     @Test
     void saveTheRulesAsAScenarioOfTheProject(@TempDir Path dir) throws 
Exception {
         info.directory = dir.toString();
@@ -292,7 +327,8 @@ class ChaosControlTest {
         List<Span> footer = new ArrayList<>();
         tab.renderFooter(footer);
         assertThat(footer.stream().map(Span::content).reduce("", 
String::concat))
-                
.contains("add").contains("change").contains("remove").contains("clear").contains("save
 as scenario")
+                .contains("add").contains("what to 
try").contains("change").contains("remove").contains("clear")
+                .contains("save as scenario")
                 .contains("new experiment");
         key('x');
         footer.clear();

Reply via email to