diff --git a/fleetd/src/main/java/dev/ltms/fleet/Fleetd.java b/fleetd/src/main/java/dev/ltms/fleet/Fleetd.java index cc9191d..3372f49 100644 --- a/fleetd/src/main/java/dev/ltms/fleet/Fleetd.java +++ b/fleetd/src/main/java/dev/ltms/fleet/Fleetd.java @@ -669,11 +669,9 @@ public final class Fleetd { var configured = config.get().profiles().get(profile); return configured == null ? null : configured.effectiveCredentialId(); }, quarantine, profile -> { - // fleetd #395: read live off the current config, like credentialIdFor above — an - // exhaustedPattern edit takes effect on the next fleet_profiles/fleet_list call, no - // restart needed, same as the credential-id lookup it sits beside. - var configured = config.get().profiles().get(profile); - return configured != null && configured.hasExhaustedPattern(); + // fleetd #404: use the compiled startup map that CompletionResolver reads. An + // exhaustedPattern edit is deferred, so this stays aligned with detection until restart. + return exhaustedPatternsByProfile.containsKey(profile); }); FleetMcp.OutageSource outageSource = new FleetMcp.OutageSource(profile -> { var configured = config.get().profiles().get(profile); diff --git a/fleetd/src/test/java/dev/ltms/fleet/FleetdExhaustionDetectionArmedWiringTest.java b/fleetd/src/test/java/dev/ltms/fleet/FleetdExhaustionDetectionArmedWiringTest.java new file mode 100644 index 0000000..0d28635 --- /dev/null +++ b/fleetd/src/test/java/dev/ltms/fleet/FleetdExhaustionDetectionArmedWiringTest.java @@ -0,0 +1,87 @@ +package dev.ltms.fleet; + +import dev.ltms.fleet.config.ConfigRef; +import dev.ltms.fleet.config.FleetConfig; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * fleetd #404: {@code exhaustionDetectionArmed} must describe the startup pattern map that + * {@code CompletionResolver} actually uses, not the reloaded config snapshot. + * + *
This test needs a reload. At startup the two snapshots agree, so a test of only a newly
+ * started daemon would not detect a live {@code config.get()} lookup in the report field.
+ */
+class FleetdExhaustionDetectionArmedWiringTest {
+
+ private static final String NO_PATTERN = """
+ bind:
+ host: 127.0.0.1
+ port: 8765
+ herdrSocket: ~/.config/herdr/herdr.sock
+ profiles:
+ terra:
+ baseUrl: http://gx00.gw:8000
+ model: terra
+ guard:
+ offSubscriptionHosts:
+ - gx00.gw
+ """;
+
+ private static final String WITH_PATTERN = """
+ bind:
+ host: 127.0.0.1
+ port: 8765
+ herdrSocket: ~/.config/herdr/herdr.sock
+ profiles:
+ terra:
+ baseUrl: http://gx00.gw:8000
+ model: terra
+ exhaustedPattern: "usage limit"
+ guard:
+ offSubscriptionHosts:
+ - gx00.gw
+ """;
+
+ private static Map