diff --git a/bridged/bridged.example.yaml b/bridged/bridged.example.yaml index eb58a85..7c6ad88 100644 --- a/bridged/bridged.example.yaml +++ b/bridged/bridged.example.yaml @@ -179,7 +179,7 @@ herdrSocket: ~/.config/herdr/herdr.sock # bridged now propagates ITS OWN PATH to every worker by default; set `env:` # only to override that or add more (JAVA_HOME, …). Since the default is the # daemon's PATH, make sure the daemon is started with a good one — see the PATH -# lines in deploy/dev.ltms.bridged.plist and deploy/bridged.service. +# lines in deploy/dev.ltms.fleet.plist and deploy/bridged.service. # # Adapter-owned variables always win over `env:`: ANTHROPIC_BASE_URL and the # rest of the ANTHROPIC_*/CLAUDE_* wiring are applied after it, so an `env:` @@ -224,7 +224,7 @@ profiles: # subscription path no guard would vet the URL, so allowing both would be a way around the # guard rather than a configuration. # - # GOTCHA 1 — it is invisible to the startup secret check. `Bridged.reportRequiredSecrets` + # GOTCHA 1 — it is invisible to the startup secret check. `Fleetd.reportRequiredSecrets` # skips subscription profiles on purpose (they need no token), so a boot log that reports # every secret as fine says nothing about these profiles. # @@ -342,7 +342,7 @@ placement: weighted # / credentialId. Those are hot because the placement policy (and, for credentialId, # the CB-578 stage B quarantine check) reads them through a supplier — being config is # not by itself enough to make a key hot. -# EXCEPT `fleet.leaders`: Bridged.main reads it once at startup to build the lead tab +# EXCEPT `fleet.leaders`: Fleetd.main reads it once at startup to build the lead tab # scanner and launcher, and neither is rebuilt on reload. A changed/added/removed # `fleet.leaders` entry is silently accepted — the reload reports "config reloaded" # with nothing in the deferred list — but has NO effect until you restart. Treat it diff --git a/bridged/docs/CB-307-Push-Loop.md b/bridged/docs/CB-307-Push-Loop.md index beb9197..fef72d5 100644 --- a/bridged/docs/CB-307-Push-Loop.md +++ b/bridged/docs/CB-307-Push-Loop.md @@ -57,7 +57,7 @@ Populate it from the **orchestration-side** MCP tools — `fleet_send`, `fleet_s session in `SessionManager`. That caller is, by construction, the primary. Worker-side tools (`fleet_reply`, `fleet_ask`) never set it. -- **Config override / pin:** a `primary: { terminal: "" }` block in `BridgedConfig` +- **Config override / pin:** a `primary: { terminal: "" }` block in `FleetConfig` (nested record, same shape as `Broker`). Lets an operator pin it, or supply it when derivation can't (see degrade case). - **Degrade:** if the primary is off-host or in a non-herdr terminal, `terminalForPid` @@ -106,7 +106,7 @@ in v1; the stop-on-empty loop is sufficient. resolved terminal is non-null **and not a registered worker session**, seen on an orchestration-side tool. This never mislabels a worker (workers are in `SessionManager`) and needs no new env var or argument (identity stays connection-derived, per the existing - `BridgeMcp` invariant). + `FleetMcp` invariant). 2. **Readiness-gate mismatch → dedicated loop.** The existing `Injector` gates delivery on `ready.test(target)` = `WorkerPresence` (the *worker's* MCP connected). The primary is not diff --git a/bridged/pom.xml b/bridged/pom.xml index b252fab..cc5a2fa 100644 --- a/bridged/pom.xml +++ b/bridged/pom.xml @@ -5,17 +5,17 @@ 4.0.0 dev.ltms - bridged + fleetd 1.0.0 jar - bridged - claude-bridge message server: sole gateway between primary/worker Claude sessions and herdr + fleetd + fleet message server: sole gateway between a lead session, its members, and herdr 25 UTF-8 - dev.ltms.bridged.Bridged + dev.ltms.fleet.Fleetd 2.19.0 6.7.0 @@ -161,6 +161,9 @@ + bridged diff --git a/bridged/src/main/java/dev/ltms/bridged/Bridged.java b/bridged/src/main/java/dev/ltms/fleet/Fleetd.java similarity index 89% rename from bridged/src/main/java/dev/ltms/bridged/Bridged.java rename to bridged/src/main/java/dev/ltms/fleet/Fleetd.java index 0cb9022..74b35c6 100644 --- a/bridged/src/main/java/dev/ltms/bridged/Bridged.java +++ b/bridged/src/main/java/dev/ltms/fleet/Fleetd.java @@ -1,52 +1,52 @@ -package dev.ltms.bridged; +package dev.ltms.fleet; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.config.ConfigRef; -import dev.ltms.bridged.config.ConfigWatcher; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.HerdrClient; -import dev.ltms.bridged.herdr.HerdrException; -import dev.ltms.bridged.herdr.LeadTabScanner; -import dev.ltms.bridged.lead.LeadLauncher; -import dev.ltms.bridged.herdr.PaneLocator; -import dev.ltms.bridged.herdr.UnixSocketHerdrClient; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.inject.CompletionResolver; -import dev.ltms.bridged.inject.ExhaustedPatternLookup; -import dev.ltms.bridged.inject.ExhaustionSink; -import dev.ltms.bridged.inject.Injector; -import dev.ltms.bridged.inject.StatusPoller; -import dev.ltms.bridged.inject.TurnListener; -import dev.ltms.bridged.inject.MemberPresence; -import dev.ltms.bridged.auth.MemberRegistry; -import dev.ltms.bridged.auth.CallerResolver; -import dev.ltms.bridged.mcp.BridgeMcp; -import dev.ltms.bridged.mcp.ConnectionIdentity; -import dev.ltms.bridged.metrics.BridgedMetrics; -import dev.ltms.bridged.metrics.Metrics; -import dev.ltms.bridged.health.FleetHealthMonitor; -import dev.ltms.bridged.mcp.PrimaryRegistry; -import dev.ltms.bridged.mcp.LsofPeerPidLookup; -import dev.ltms.bridged.mcp.LsofProcessCwdLookup; -import dev.ltms.bridged.msg.AmqpReplyInbox; -import dev.ltms.bridged.msg.InMemoryReplyInbox; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.msg.ReplyInbox; -import dev.ltms.bridged.msg.LeadHeartbeatLoop; -import dev.ltms.bridged.msg.ReplyPushLoop; -import dev.ltms.bridged.rest.BridgedApp; -import dev.ltms.bridged.session.GitWorktrees; -import dev.ltms.bridged.session.MemberSession; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.peer.PeerLauncher; -import dev.ltms.bridged.session.SessionReaper; -import dev.ltms.bridged.member.ClaudeCodeLauncher; -import dev.ltms.bridged.member.CompositePeerLauncher; -import dev.ltms.bridged.member.HerdrPeerLauncher; -import dev.ltms.bridged.member.OpenCodeLauncher; -import dev.ltms.bridged.placement.BackendQuarantine; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.config.ConfigRef; +import dev.ltms.fleet.config.ConfigWatcher; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.HerdrClient; +import dev.ltms.fleet.herdr.HerdrException; +import dev.ltms.fleet.herdr.LeadTabScanner; +import dev.ltms.fleet.lead.LeadLauncher; +import dev.ltms.fleet.herdr.PaneLocator; +import dev.ltms.fleet.herdr.UnixSocketHerdrClient; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.inject.CompletionResolver; +import dev.ltms.fleet.inject.ExhaustedPatternLookup; +import dev.ltms.fleet.inject.ExhaustionSink; +import dev.ltms.fleet.inject.Injector; +import dev.ltms.fleet.inject.StatusPoller; +import dev.ltms.fleet.inject.TurnListener; +import dev.ltms.fleet.inject.MemberPresence; +import dev.ltms.fleet.auth.MemberRegistry; +import dev.ltms.fleet.auth.CallerResolver; +import dev.ltms.fleet.mcp.FleetMcp; +import dev.ltms.fleet.mcp.ConnectionIdentity; +import dev.ltms.fleet.metrics.FleetMetrics; +import dev.ltms.fleet.metrics.Metrics; +import dev.ltms.fleet.health.FleetHealthMonitor; +import dev.ltms.fleet.mcp.PrimaryRegistry; +import dev.ltms.fleet.mcp.LsofPeerPidLookup; +import dev.ltms.fleet.mcp.LsofProcessCwdLookup; +import dev.ltms.fleet.msg.AmqpReplyInbox; +import dev.ltms.fleet.msg.InMemoryReplyInbox; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.msg.ReplyInbox; +import dev.ltms.fleet.msg.LeadHeartbeatLoop; +import dev.ltms.fleet.msg.ReplyPushLoop; +import dev.ltms.fleet.rest.FleetApp; +import dev.ltms.fleet.session.GitWorktrees; +import dev.ltms.fleet.session.MemberSession; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.peer.PeerLauncher; +import dev.ltms.fleet.session.SessionReaper; +import dev.ltms.fleet.member.ClaudeCodeLauncher; +import dev.ltms.fleet.member.CompositePeerLauncher; +import dev.ltms.fleet.member.HerdrPeerLauncher; +import dev.ltms.fleet.member.OpenCodeLauncher; +import dev.ltms.fleet.placement.BackendQuarantine; import io.javalin.Javalin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,9 +72,9 @@ import java.util.stream.Collectors; * starts listening. Before anything else it asserts its own environment is clean — * {@code bridged} is not a Claude process and must never carry a base_url. */ -public final class Bridged { +public final class Fleetd { - private static final Logger log = LoggerFactory.getLogger(Bridged.class); + private static final Logger log = LoggerFactory.getLogger(Fleetd.class); /** CB-504: how long to wait at startup for herdr's socket before serving degraded. */ private static final long HERDR_WAIT_SECONDS = 30; @@ -82,7 +82,7 @@ public final class Bridged { static void main(String[] args) { Path configPath = Path.of(args.length > 0 ? args[0] : "bridged.yaml"); - BridgedConfig cfg = BridgedConfig.load(configPath); + FleetConfig cfg = FleetConfig.load(configPath); // CB-594: report which secret env vars the config actually needs, by name, before anything // else can fail on a silently-empty one. A daemon started without a login shell (launchd) // boots fine either way — this is the only thing that says so out loud. @@ -127,8 +127,8 @@ public final class Bridged { // CB-402: one adapter per configured peer kind, fronted by a composite router. A profile's // `kind:` selects its adapter — claude-code (the default) and opencode partition the profile // set — and the composite dispatches each SPI call to the adapter that owns the profile/pane. - Map claudeProfiles = new LinkedHashMap<>(); - Map opencodeProfiles = new LinkedHashMap<>(); + Map claudeProfiles = new LinkedHashMap<>(); + Map opencodeProfiles = new LinkedHashMap<>(); cfg.profiles().forEach((name, w) -> { if (w.isOpenCode()) { opencodeProfiles.put(name, w); @@ -157,7 +157,7 @@ public final class Bridged { AtomicReference> liveCountRef = new AtomicReference<>(_ -> 0); // CB-578 stage B: one quarantine tracker for the whole daemon, shared between the launcher // (checked at spawn) and the exhaustion sink wired in below (written on BACKEND_EXHAUSTED). - // The cooldown is deferred (see BridgedConfig#quarantineCooldownSeconds): it is read once + // The cooldown is deferred (see FleetConfig#quarantineCooldownSeconds): it is read once // here, at startup, and a config reload only changes it for a daemon restart. BackendQuarantine quarantine = new BackendQuarantine(System::nanoTime, TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds())); @@ -227,7 +227,7 @@ public final class Bridged { var leaders = cfg.fleet().leaders(); if (!leaders.isEmpty()) { Set memberSpaces = cfg.profiles().values().stream() - .map(BridgedConfig.Profile::workspace) + .map(FleetConfig.Profile::workspace) .filter(Objects::nonNull) .collect(Collectors.toSet()); Map tabToName = new LinkedHashMap<>(); @@ -332,7 +332,7 @@ public final class Bridged { } @Override - public void onDelivered(String target, dev.ltms.bridged.msg.TurnToken token) { + public void onDelivered(String target, dev.ltms.fleet.msg.TurnToken token) { completion.onDelivered(target, token); sessions.onDelivered(target, token); } @@ -389,7 +389,7 @@ public final class Bridged { // CB-502: the registry is built before the service and the push loop so send/reply outcomes // are counted at their single funnel rather than at each of the two caller-facing surfaces. // CB-512: the push loop takes it too, so nudge outcomes (delivered|exhausted) are counted. - Metrics metrics = BridgedMetrics.create(sessions, replyInbox); + Metrics metrics = FleetMetrics.create(sessions, replyInbox); var pushLoop = new ReplyPushLoop(primaryRegistry, agents, replyInbox, pushScheduler, maxReminders, backoffMs, metrics); // CB-551: idle-lead heartbeat. Opt-in; absent `leadHeartbeat:` this is never constructed, so @@ -480,18 +480,18 @@ public final class Bridged { log.info("auth: loopback-trust (any loopback non-worker caller is the primary)"); } - BridgeMcp mcp = new BridgeMcp(messages, workers, sessions, identity, presence, - primaryRegistry, callers, metrics, new BridgeMcp.CapacitySource(profile -> liveCountRef.get().apply(profile), + FleetMcp mcp = new FleetMcp(messages, workers, sessions, identity, presence, + primaryRegistry, callers, metrics, new FleetMcp.CapacitySource(profile -> liveCountRef.get().apply(profile), profile -> { var configured = config.get().profiles().get(profile); return configured == null ? null : configured.maxLoad(); }, () -> config.get().profiles().keySet(), System::nanoTime), - new BridgeMcp.HealthCoverageSource(() -> { + new FleetMcp.HealthCoverageSource(() -> { var health = config.get().health(); return FleetHealthMonitor.coverage(health != null && health.isEnabled(), health != null && health.notifications() != null && health.notifications().configured()); }), - new BridgeMcp.QuarantineSource(profile -> { + new FleetMcp.QuarantineSource(profile -> { var configured = config.get().profiles().get(profile); return configured == null ? null : configured.effectiveCredentialId(); }, quarantine)); @@ -530,7 +530,7 @@ public final class Bridged { herdr.close(); })); - Javalin app = new BridgedApp(herdr, workers, sessions, messages, presence, mcp.servlet(), + Javalin app = new FleetApp(herdr, workers, sessions, messages, presence, mcp.servlet(), callers, metrics).build(); app.start(cfg.bind().host(), cfg.bind().port()); log.info("bridged listening on {}:{}, herdr socket {}", @@ -546,7 +546,7 @@ public final class Bridged { * hazard is a property of spawning. A lead is never spawned: the operator started it and named it * (or labelled its tab) only once it was up, so there is no boot window to guard. * - *

A lead is also never enrolled in {@link MemberPresence} — {@code BridgeMcp} marks presence + *

A lead is also never enrolled in {@link MemberPresence} — {@code FleetMcp} marks presence * for every spawned member (worker and architect), deliberately, since that map doubles as the * member roster's availability signal and a lead counted there would show up as an available * member. So without the second disjunct a lead is permanently un-deliverable: every @@ -563,19 +563,19 @@ public final class Bridged { /** * CB-594: which env vars the loaded config actually needs, and why — every non-{@code * subscription} profile's {@code tokenEnv} (a subscription profile never reads one, see - * {@link BridgedConfig.Profile#isSubscription()}), plus every profile's {@code gitTokenEnv} + * {@link FleetConfig.Profile#isSubscription()}), plus every profile's {@code gitTokenEnv} * where set (opt-in). Derived from the config, not hard-coded, so a new profile is covered for * free. A var required by more than one profile is one entry naming every profile that needs * it. Deliberately excludes {@code auth.tokenEnv}: that one is already enforced loudly, by a * startup throw in {@code main()} — about 370 lines below this method's call site - * ({@link #reportRequiredSecrets(BridgedConfig)}), not a few lines above it. That throw only + * ({@link #reportRequiredSecrets(FleetConfig)}), not a few lines above it. That throw only * fires when {@code auth.mode: token} is configured; under the default loopback-trust mode it * never runs, and {@code auth.tokenEnv} is simply not required. * *

Package-private and pure (no I/O, no logging) so the derivation is unit-testable without - * capturing log output; {@link #reportRequiredSecrets(BridgedConfig)} is the logging caller. + * capturing log output; {@link #reportRequiredSecrets(FleetConfig)} is the logging caller. */ - static Map> requiredSecretEnvVars(BridgedConfig cfg) { + static Map> requiredSecretEnvVars(FleetConfig cfg) { Map> requiredBy = new LinkedHashMap<>(); cfg.profiles().forEach((name, profile) -> { if (!profile.isSubscription()) { @@ -599,7 +599,7 @@ public final class Bridged { *

A missing entry only warns — it must never refuse to start. A daemon that boots and says * what is wrong is strictly more useful than one that will not boot at all. */ - private static void reportRequiredSecrets(BridgedConfig cfg) { + private static void reportRequiredSecrets(FleetConfig cfg) { Map> requiredBy = requiredSecretEnvVars(cfg); if (requiredBy.isEmpty()) { log.info("startup secrets: no profile references a token env var — nothing to check"); @@ -622,7 +622,7 @@ public final class Bridged { /** * CB-596: {@code known:} empty (block absent entirely, or present but empty) means {@link - * BridgedConfig.MemberCredentials#blockedSet()} is empty too — every member pane inherits the + * FleetConfig.MemberCredentials#blockedSet()} is empty too — every member pane inherits the * operator's whole secret store, unblocked, exactly the defect this ticket fixes. Unlike a * missing token ({@link #reportRequiredSecrets}), there is no name to point at: the point is * that the block itself is missing. Warn once at startup and say what to add; never refuse to @@ -632,8 +632,8 @@ public final class Bridged { *

Package-private so the test can capture the log directly, the same way {@link * #requiredSecretEnvVars} is exposed for {@link #reportRequiredSecrets}'s own test. */ - static void reportMemberCredentialsGap(BridgedConfig cfg) { - BridgedConfig.MemberCredentials creds = cfg.memberCredentials(); + static void reportMemberCredentialsGap(FleetConfig cfg) { + FleetConfig.MemberCredentials creds = cfg.memberCredentials(); if (creds != null && !creds.known().isEmpty()) { log.info("memberCredentials: {} known name(s), {} allowed — blocking {} on every spawn", creds.known().size(), creds.allow().size(), creds.blockedSet().size()); @@ -678,6 +678,6 @@ public final class Bridged { } } - private Bridged() { + private Fleetd() { } } diff --git a/bridged/src/main/java/dev/ltms/bridged/auth/AuditLog.java b/bridged/src/main/java/dev/ltms/fleet/auth/AuditLog.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/auth/AuditLog.java rename to bridged/src/main/java/dev/ltms/fleet/auth/AuditLog.java index 1554dbd..1013734 100644 --- a/bridged/src/main/java/dev/ltms/bridged/auth/AuditLog.java +++ b/bridged/src/main/java/dev/ltms/fleet/auth/AuditLog.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bridged/src/main/java/dev/ltms/bridged/auth/Authz.java b/bridged/src/main/java/dev/ltms/fleet/auth/Authz.java similarity index 96% rename from bridged/src/main/java/dev/ltms/bridged/auth/Authz.java rename to bridged/src/main/java/dev/ltms/fleet/auth/Authz.java index a89d6aa..1cb536c 100644 --- a/bridged/src/main/java/dev/ltms/bridged/auth/Authz.java +++ b/bridged/src/main/java/dev/ltms/fleet/auth/Authz.java @@ -1,9 +1,9 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; /** * The authorization table (CB-505), stated once and enforced on both entry paths. * - *

Most of these rules are already true de facto — {@code BridgeMcp} derives a worker's identity + *

Most of these rules are already true de facto — {@code FleetMcp} derives a worker's identity * from the connection rather than reading it from an argument, so a worker has never been able to * reply as another worker over MCP. What was missing is that the REST surface trusted the * session id in the URL path, and neither surface checked role at all. This class makes the diff --git a/bridged/src/main/java/dev/ltms/bridged/auth/CallerResolver.java b/bridged/src/main/java/dev/ltms/fleet/auth/CallerResolver.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/auth/CallerResolver.java rename to bridged/src/main/java/dev/ltms/fleet/auth/CallerResolver.java index d3806bf..62f0244 100644 --- a/bridged/src/main/java/dev/ltms/bridged/auth/CallerResolver.java +++ b/bridged/src/main/java/dev/ltms/fleet/auth/CallerResolver.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; -import dev.ltms.bridged.mcp.ConnectionIdentity; -import dev.ltms.bridged.peer.MemberRole; +import dev.ltms.fleet.mcp.ConnectionIdentity; +import dev.ltms.fleet.peer.MemberRole; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; @@ -12,7 +12,7 @@ import java.util.function.Supplier; /** * Resolves every caller to a {@link Principal}, for both entry paths into the core (CB-501). * - *

There are two of them and they are not layered the way the docs suggest: {@code BridgeMcp} + *

There are two of them and they are not layered the way the docs suggest: {@code FleetMcp} * calls the service layer directly and is mounted as a raw servlet (so it never passes through a * Javalin filter), while the REST routes historically resolved no identity at all. Both now * delegate here, so the authorization rules are stated once instead of drifting apart. @@ -59,7 +59,7 @@ public final class CallerResolver { *

Like {@link #leadTerminals}, a supplier rather than a fixed map, so a binding injected * after startup — when the later spawn lifecycle establishes a live architect session, or an * operator pins one — takes effect without a restart. Consulted per resolve; today's wiring - * in {@code Bridged} reads a constant from config, which is the degenerate live case. + * in {@code Fleetd} reads a constant from config, which is the degenerate live case. */ private final Supplier> architectTerminals; private final Function memberSlotRoles; @@ -235,7 +235,7 @@ public final class CallerResolver { // loopback-trust: same-host callers that are not workers are the primary. A non-loopback // caller is anonymous even here — and startup refuses that combination anyway - // (BridgedConfig.validateAuthExposure), so this is defence in depth, not the control. + // (FleetConfig.validateAuthExposure), so this is defence in depth, not the control. return isLoopback(remoteAddr) ? Principal.primary(c.pid()) : Principal.anonymous(); } diff --git a/bridged/src/main/java/dev/ltms/bridged/auth/MemberLifecycle.java b/bridged/src/main/java/dev/ltms/fleet/auth/MemberLifecycle.java similarity index 86% rename from bridged/src/main/java/dev/ltms/bridged/auth/MemberLifecycle.java rename to bridged/src/main/java/dev/ltms/fleet/auth/MemberLifecycle.java index d4a9636..cdce524 100644 --- a/bridged/src/main/java/dev/ltms/bridged/auth/MemberLifecycle.java +++ b/bridged/src/main/java/dev/ltms/fleet/auth/MemberLifecycle.java @@ -1,6 +1,6 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; -import dev.ltms.bridged.peer.MemberRole; +import dev.ltms.fleet.peer.MemberRole; /** Optional session lifecycle hook for live member-slot bindings. */ public interface MemberLifecycle { diff --git a/bridged/src/main/java/dev/ltms/bridged/auth/MemberRegistry.java b/bridged/src/main/java/dev/ltms/fleet/auth/MemberRegistry.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/auth/MemberRegistry.java rename to bridged/src/main/java/dev/ltms/fleet/auth/MemberRegistry.java index 7221463..7bfd463 100644 --- a/bridged/src/main/java/dev/ltms/bridged/auth/MemberRegistry.java +++ b/bridged/src/main/java/dev/ltms/fleet/auth/MemberRegistry.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.peer.MemberRole; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.peer.MemberRole; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,7 +59,7 @@ public final class MemberRegistry implements MemberLifecycle { private final Map terminalToSlot = new HashMap<>(); /** Flatten every role pool in {@code fleet} into one registry. Leaders are not members. */ - public MemberRegistry(BridgedConfig.Fleet fleet) { + public MemberRegistry(FleetConfig.Fleet fleet) { Map flat = new LinkedHashMap<>(); if (fleet != null) { for (MemberRole role : MemberRole.values()) { diff --git a/bridged/src/main/java/dev/ltms/bridged/auth/Principal.java b/bridged/src/main/java/dev/ltms/fleet/auth/Principal.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/auth/Principal.java rename to bridged/src/main/java/dev/ltms/fleet/auth/Principal.java index 0a880da..3a2526f 100644 --- a/bridged/src/main/java/dev/ltms/bridged/auth/Principal.java +++ b/bridged/src/main/java/dev/ltms/fleet/auth/Principal.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; /** * A resolved caller: its {@link Role}, and — for a worker — the herdr {@code terminal_id} that diff --git a/bridged/src/main/java/dev/ltms/bridged/auth/Role.java b/bridged/src/main/java/dev/ltms/fleet/auth/Role.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/auth/Role.java rename to bridged/src/main/java/dev/ltms/fleet/auth/Role.java index b43f3ac..bdd47c7 100644 --- a/bridged/src/main/java/dev/ltms/bridged/auth/Role.java +++ b/bridged/src/main/java/dev/ltms/fleet/auth/Role.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; /** * What a caller is allowed to be on the bus (CB-501). diff --git a/bridged/src/main/java/dev/ltms/bridged/config/ConfigRef.java b/bridged/src/main/java/dev/ltms/fleet/config/ConfigRef.java similarity index 92% rename from bridged/src/main/java/dev/ltms/bridged/config/ConfigRef.java rename to bridged/src/main/java/dev/ltms/fleet/config/ConfigRef.java index f802e42..651c6a8 100644 --- a/bridged/src/main/java/dev/ltms/bridged/config/ConfigRef.java +++ b/bridged/src/main/java/dev/ltms/fleet/config/ConfigRef.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.config; +package dev.ltms.fleet.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,7 +16,7 @@ import java.util.function.Supplier; /** * The daemon's live configuration, re-readable without a restart (CB-559). * - *

Consumers hold this, not a {@link BridgedConfig}, and read through {@link #get()} at the point + *

Consumers hold this, not a {@link FleetConfig}, and read through {@link #get()} at the point * of use. A component that captures {@code ref.get()} into a field at construction has opted out of * reload — which is sometimes right (see deferred below), but it must then be a deliberate * choice rather than an accident of where the field was initialised. @@ -31,7 +31,7 @@ import java.util.function.Supplier; * {@code placement:}, and an existing profile's {@code weight} / {@code maxLoad}. Those * three are read through a supplier on {@code CompositePeerLauncher}, which is what makes * them hot — not the fact that they are config. This does NOT include - * {@code fleet.leaders}: {@code Bridged.main} reads {@code cfg.fleet().leaders()} + * {@code fleet.leaders}: {@code Fleetd.main} reads {@code cfg.fleet().leaders()} * once at startup to build the {@code LeadTabScanner} and the {@code LeadLauncher}, and * neither is reconstructed on reload — so a lead added, removed, or re-{@code tab}'d under * {@code fleet.leaders} needs a restart, the same as any deferred key below. @@ -42,7 +42,7 @@ import java.util.function.Supplier; * {@code guard:}, {@code worktreeRoot:}, adding or removing a profile (a new backend needs its own launcher, * which is constructed once), and an existing profile's launch settings — * {@code model}, {@code baseUrl}, {@code argv}, {@code env}, {@code mcpUrl}, - * {@code exhaustedPattern} (CB-578 stage A — compiled once into {@code Bridged.main}'s + * {@code exhaustedPattern} (CB-578 stage A — compiled once into {@code Fleetd.main}'s * pattern map at startup), and the rest. {@code credentialId} (CB-578 stage B) is NOT on * this list — it is read live off the config supplier at every quarantine check and * exhaustion event, exactly like {@code weight} / {@code maxLoad}, so it is hot instead. @@ -65,7 +65,7 @@ import java.util.function.Supplier; * running. A config file being edited is normally read once mid-save; degrading a working daemon * because it caught a half-written file would be a bad trade. */ -public final class ConfigRef implements Supplier { +public final class ConfigRef implements Supplier { private static final Logger log = LoggerFactory.getLogger(ConfigRef.class); @@ -74,21 +74,21 @@ public final class ConfigRef implements Supplier { Set.of("bind", "herdrSocket", "broker", "auth"); private final Path path; - private final AtomicReference current; + private final AtomicReference current; - public ConfigRef(Path path, BridgedConfig initial) { + public ConfigRef(Path path, FleetConfig initial) { this.path = path; this.current = new AtomicReference<>(Objects.requireNonNull(initial, "initial config")); } /** A fixed reference that never reloads — for tests and for wiring built from a config in code. */ - public static ConfigRef fixed(BridgedConfig cfg) { + public static ConfigRef fixed(FleetConfig cfg) { return new ConfigRef(null, cfg); } /** The live configuration. Read this per use; do not cache it in a field. */ @Override - public BridgedConfig get() { + public FleetConfig get() { return current.get(); } @@ -149,10 +149,10 @@ public final class ConfigRef implements Supplier { if (path == null) { return Outcome.failed("this config was built in code and has no file to reload from"); } - BridgedConfig old = current.get(); - BridgedConfig fresh; + FleetConfig old = current.get(); + FleetConfig fresh; try { - fresh = BridgedConfig.load(path); + fresh = FleetConfig.load(path); // The same gate startup runs. A config that would have refused to boot must not be able // to slip in through a reload — that is how a daemon ends up in a state it could never // have started in, which is the hardest kind to debug. @@ -182,7 +182,7 @@ public final class ConfigRef implements Supplier { } /** Cold keys whose value differs between the running config and the candidate. */ - private static List changedColdKeys(BridgedConfig old, BridgedConfig fresh) { + private static List changedColdKeys(FleetConfig old, FleetConfig fresh) { List changed = new ArrayList<>(); if (!Objects.equals(old.bind(), fresh.bind())) { changed.add("bind"); @@ -202,7 +202,7 @@ public final class ConfigRef implements Supplier { } /** Changed keys that were accepted but whose effect waits for a restart. */ - private static List changedDeferredKeys(BridgedConfig old, BridgedConfig fresh) { + private static List changedDeferredKeys(FleetConfig old, FleetConfig fresh) { List changed = new ArrayList<>(); if (!Objects.equals(old.lifecycle(), fresh.lifecycle())) { changed.add("lifecycle"); @@ -226,9 +226,9 @@ public final class ConfigRef implements Supplier { if (!Objects.equals(old.quarantineCooldownSeconds(), fresh.quarantineCooldownSeconds())) { changed.add("quarantineCooldownSeconds"); } - Map before = + Map before = old.profiles() == null ? Map.of() : old.profiles(); - Map after = + Map after = fresh.profiles() == null ? Map.of() : fresh.profiles(); // Adding or removing a profile is deferred: a new backend needs its own launcher, and // launchers are built once at startup. @@ -247,7 +247,7 @@ public final class ConfigRef implements Supplier { // a reload can produce, because the operator has no reason to doubt it. List relaunch = new ArrayList<>(); before.forEach((name, was) -> { - BridgedConfig.Profile now = after.get(name); + FleetConfig.Profile now = after.get(name); if (now != null && !sameLaunchSettings(was, now)) { relaunch.add(name); } @@ -266,7 +266,7 @@ public final class ConfigRef implements Supplier { * {@code CompositePeerLauncher}/the CB-578 stage B exhaustion sink) and really do take effect on * the next spawn. */ - private static boolean sameLaunchSettings(BridgedConfig.Profile a, BridgedConfig.Profile b) { + private static boolean sameLaunchSettings(FleetConfig.Profile a, FleetConfig.Profile b) { return Objects.equals(a.baseUrl(), b.baseUrl()) && Objects.equals(a.model(), b.model()) && Objects.equals(a.configDir(), b.configDir()) @@ -283,7 +283,7 @@ public final class ConfigRef implements Supplier { && Objects.equals(a.kind(), b.kind()) && Objects.equals(a.env(), b.env()) && Objects.equals(a.subscription(), b.subscription()) - // CB-578 stage B: exhaustedPattern is compiled once into Bridged.main's pattern map + // CB-578 stage B: exhaustedPattern is compiled once into Fleetd.main's pattern map // at startup (see ExhaustedPatternLookup wiring) — a reload never re-reads it, so a // changed pattern must be reported as deferred, exactly like model/baseUrl/argv. && Objects.equals(a.exhaustedPattern(), b.exhaustedPattern()); diff --git a/bridged/src/main/java/dev/ltms/bridged/config/ConfigWatcher.java b/bridged/src/main/java/dev/ltms/fleet/config/ConfigWatcher.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/config/ConfigWatcher.java rename to bridged/src/main/java/dev/ltms/fleet/config/ConfigWatcher.java index 7cde2d2..f521c0a 100644 --- a/bridged/src/main/java/dev/ltms/bridged/config/ConfigWatcher.java +++ b/bridged/src/main/java/dev/ltms/fleet/config/ConfigWatcher.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.config; +package dev.ltms.fleet.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bridged/src/main/java/dev/ltms/bridged/config/BridgedConfig.java b/bridged/src/main/java/dev/ltms/fleet/config/FleetConfig.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/config/BridgedConfig.java rename to bridged/src/main/java/dev/ltms/fleet/config/FleetConfig.java index 2931566..b0b939d 100644 --- a/bridged/src/main/java/dev/ltms/bridged/config/BridgedConfig.java +++ b/bridged/src/main/java/dev/ltms/fleet/config/FleetConfig.java @@ -1,13 +1,13 @@ -package dev.ltms.bridged.config; +package dev.ltms.fleet.config; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import dev.ltms.bridged.msg.AmqpReplyInbox; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.placement.PlacementPolicies; +import dev.ltms.fleet.msg.AmqpReplyInbox; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.placement.PlacementPolicies; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,7 +71,7 @@ import java.util.Set; * omitted) blocks nothing — see {@link MemberCredentials}. */ @JsonIgnoreProperties(ignoreUnknown = true) -public record BridgedConfig( +public record FleetConfig( Bind bind, String herdrSocket, Map profiles, @@ -92,7 +92,7 @@ public record BridgedConfig( MemberCredentials memberCredentials) { /** Back-compat form before the CB-596 {@code memberCredentials:} block was added. */ - public BridgedConfig(Bind bind, String herdrSocket, Map profiles, Guard guard, + public FleetConfig(Bind bind, String herdrSocket, Map profiles, Guard guard, String worktreeRoot, Lifecycle lifecycle, Integer spawnReadyTimeoutMs, Integer spawnReadyPollMs, Broker broker, Primary primary, Fleet fleet, LeadHeartbeat leadHeartbeat, Health health, String placement, Auth auth, @@ -106,7 +106,7 @@ public record BridgedConfig( public static final int DEFAULT_QUARANTINE_COOLDOWN_SECONDS = 1800; /** Back-compat 14-arg form — no {@code configReload:} block, so file watching stays off. */ - public BridgedConfig(Bind bind, String herdrSocket, Map profiles, Guard guard, + public FleetConfig(Bind bind, String herdrSocket, Map profiles, Guard guard, String worktreeRoot, Lifecycle lifecycle, Integer spawnReadyTimeoutMs, Integer spawnReadyPollMs, Broker broker, Primary primary, Fleet fleet, LeadHeartbeat leadHeartbeat, String placement, Auth auth) { @@ -115,7 +115,7 @@ public record BridgedConfig( } /** Back-compat form before the optional {@code health:} block was added. */ - public BridgedConfig(Bind bind, String herdrSocket, Map profiles, Guard guard, + public FleetConfig(Bind bind, String herdrSocket, Map profiles, Guard guard, String worktreeRoot, Lifecycle lifecycle, Integer spawnReadyTimeoutMs, Integer spawnReadyPollMs, Broker broker, Primary primary, Fleet fleet, LeadHeartbeat leadHeartbeat, String placement, Auth auth, ConfigReload configReload) { @@ -124,7 +124,7 @@ public record BridgedConfig( } /** Back-compat form before the CB-578 stage B {@code quarantineCooldownSeconds} field was added. */ - public BridgedConfig(Bind bind, String herdrSocket, Map profiles, Guard guard, + public FleetConfig(Bind bind, String herdrSocket, Map profiles, Guard guard, String worktreeRoot, Lifecycle lifecycle, Integer spawnReadyTimeoutMs, Integer spawnReadyPollMs, Broker broker, Primary primary, Fleet fleet, LeadHeartbeat leadHeartbeat, Health health, String placement, Auth auth, @@ -147,7 +147,7 @@ public record BridgedConfig( * {@code WeightedRoundRobinPolicy}), so losing it makes equal-weight placement * non-reproducible across restarts. Unmodifiable-wrap instead of copy-and-scramble. */ - public BridgedConfig { + public FleetConfig { if (profiles != null && !profiles.isEmpty()) { Map normalized = new LinkedHashMap<>(); profiles.forEach((name, p) -> normalized.put(name, @@ -242,7 +242,7 @@ public record BridgedConfig( * instead, naming the profile and the key. Live means any session the * registry still owns (acquired and not yet released), in any state. * @param kind which peer launcher spawns this profile: {@code "claude-code"} (default — - * the {@link dev.ltms.bridged.member.ClaudeCodeLauncher}) or {@code "opencode"}. + * the {@link dev.ltms.fleet.member.ClaudeCodeLauncher}) or {@code "opencode"}. * The {@code CompositePeerLauncher} routes {@code spawn}/reap by this value, so * each adapter drives only its own kind. Normalised to lower-case; blank ⇒ the * default. It selects the adapter, not the transport — placement, tabs, cwd, and @@ -291,7 +291,7 @@ public record BridgedConfig( String exhaustedPattern, String credentialId) { - /** Peer kind spawned by {@link dev.ltms.bridged.member.ClaudeCodeLauncher} (the default). */ + /** Peer kind spawned by {@link dev.ltms.fleet.member.ClaudeCodeLauncher} (the default). */ public static final String KIND_CLAUDE_CODE = "claude-code"; /** Peer kind spawned by the opencode adapter (CB-402). */ public static final String KIND_OPENCODE = "opencode"; @@ -472,7 +472,7 @@ public record BridgedConfig( * {@code ANTHROPIC_AUTH_TOKEN} is injected from {@code tokenEnv}. An {@code env:} entry for * either is a bypass vector — it is what the subscription path would otherwise let survive * unguarded — so it is rejected at config load (see - * {@link BridgedConfig#validateSubscriptionProfiles()}). + * {@link FleetConfig#validateSubscriptionProfiles()}). */ public boolean envCarriesAnthropicBinding() { return env != null @@ -893,7 +893,7 @@ public record BridgedConfig( * *

Member identity never depends on this block: a loopback peer PID that maps to a herdr * pane is unforgeable and is always honoured (see - * {@link dev.ltms.bridged.mcp.ConnectionIdentity}). This only decides what happens for + * {@link dev.ltms.fleet.mcp.ConnectionIdentity}). This only decides what happens for * everyone else. * * @param mode {@code "loopback-trust"} (default) — any loopback caller that is not a known @@ -1028,7 +1028,7 @@ public record BridgedConfig( return defaultProfileFor(MemberRole.DEV); } - private static final Logger log = LoggerFactory.getLogger(BridgedConfig.class); + private static final Logger log = LoggerFactory.getLogger(FleetConfig.class); private static final ObjectMapper YAML = new ObjectMapper(new YAMLFactory()); @@ -1047,7 +1047,7 @@ public record BridgedConfig( "memberCredentials"); /** Load and validate config from {@code path}. */ - public static BridgedConfig load(Path path) { + public static FleetConfig load(Path path) { try { String yaml = Files.readString(path); rejectRenamedTopLevelKeys(yaml); @@ -1059,7 +1059,7 @@ public record BridgedConfig( rejectUnknownAuthMode(yaml); rejectUnknownPlacement(yaml); rejectUnknownMemberCredentialsPolicy(yaml); - BridgedConfig cfg = YAML.readValue(yaml, BridgedConfig.class); + FleetConfig cfg = YAML.readValue(yaml, FleetConfig.class); // CB-606: validated here, eagerly, using PlacementPolicies.fromName as the single source // of truth — not lazily at first spawn (see CompositePeerLauncher's placementPolicy // Supplier), where a bad name would still start a daemon that looks healthy. @@ -1366,7 +1366,7 @@ public record BridgedConfig( * *

{@link Profile}'s compact constructor only lower-cases {@code kind} and compares it against * {@code KIND_OPENCODE} — anything else, including a typo like {@code opencod}, silently falls - * into the claude-code bucket ({@link dev.ltms.bridged.member.CompositePeerLauncher} routes by + * into the claude-code bucket ({@link dev.ltms.fleet.member.CompositePeerLauncher} routes by * exact adapter claim, not by membership in a known set). With {@code argv:} also unset, the argv * default special-cases only the exact string {@code "claude-code"}, so the launch command falls * back to {@code List.of(kind)} — the daemon then tries to run a program literally named after the @@ -1570,7 +1570,7 @@ public record BridgedConfig( } /** Fill in nested defaults so callers never see nulls for structural fields. */ - public BridgedConfig withDefaults() { + public FleetConfig withDefaults() { Bind b = bind != null ? bind : new Bind(null, 0); Guard g = guard != null ? guard : new Guard(List.of()); Lifecycle l = lifecycle != null ? lifecycle : new Lifecycle(null, null, null, false); @@ -1604,7 +1604,7 @@ public record BridgedConfig( // bridged.yaml to protect anything. See bridged.example.yaml's memberCredentials: comment. MemberCredentials mc = memberCredentials != null ? memberCredentials : new MemberCredentials(null, List.of(), List.of()); - return new BridgedConfig(b, herdrSocket, profiles, g, worktreeRoot, l, timeout, pollMs, + return new FleetConfig(b, herdrSocket, profiles, g, worktreeRoot, l, timeout, pollMs, broker, primary, f, leadHeartbeat, health, placementOrDefault, a, configReload, quarantineCooldown, mc); } @@ -1639,8 +1639,8 @@ public record BridgedConfig( *

The scan reads a tab label and concludes "a lead lives here". bridged also writes * tab labels — every member gets one rendered into its tab. Choose a lead {@code tabPrefix} that * a member template matches and the daemon starts labelling its own members as leads, promoting - * the entire fleet to {@link dev.ltms.bridged.auth.Role#PRIMARY} with no message and no diff. - * The member-space exclusion in {@link dev.ltms.bridged.herdr.LeadTabScanner} already blocks the + * the entire fleet to {@link dev.ltms.fleet.auth.Role#PRIMARY} with no message and no diff. + * The member-space exclusion in {@link dev.ltms.fleet.herdr.LeadTabScanner} already blocks the * realistic path, but defence that depends on one workspace label holding is not defence enough * for a privilege boundary. * diff --git a/bridged/src/main/java/dev/ltms/bridged/guard/GuardException.java b/bridged/src/main/java/dev/ltms/fleet/guard/GuardException.java similarity index 87% rename from bridged/src/main/java/dev/ltms/bridged/guard/GuardException.java rename to bridged/src/main/java/dev/ltms/fleet/guard/GuardException.java index b3cbd57..1532524 100644 --- a/bridged/src/main/java/dev/ltms/bridged/guard/GuardException.java +++ b/bridged/src/main/java/dev/ltms/fleet/guard/GuardException.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.guard; +package dev.ltms.fleet.guard; /** Thrown when the subscription boundary would be violated. Never swallow this. */ public class GuardException extends RuntimeException { diff --git a/bridged/src/main/java/dev/ltms/bridged/guard/SubscriptionGuard.java b/bridged/src/main/java/dev/ltms/fleet/guard/SubscriptionGuard.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/guard/SubscriptionGuard.java rename to bridged/src/main/java/dev/ltms/fleet/guard/SubscriptionGuard.java index 64fd4a7..f29386e 100644 --- a/bridged/src/main/java/dev/ltms/bridged/guard/SubscriptionGuard.java +++ b/bridged/src/main/java/dev/ltms/fleet/guard/SubscriptionGuard.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.guard; +package dev.ltms.fleet.guard; import java.net.URI; import java.net.URISyntaxException; diff --git a/bridged/src/main/java/dev/ltms/bridged/health/FleetHealth.java b/bridged/src/main/java/dev/ltms/fleet/health/FleetHealth.java similarity index 94% rename from bridged/src/main/java/dev/ltms/bridged/health/FleetHealth.java rename to bridged/src/main/java/dev/ltms/fleet/health/FleetHealth.java index 5c8ca23..fb50acc 100644 --- a/bridged/src/main/java/dev/ltms/bridged/health/FleetHealth.java +++ b/bridged/src/main/java/dev/ltms/fleet/health/FleetHealth.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.session.MemberSession; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.session.MemberSession; /** * Pure classifier. Collection and repair are deliberately outside this package. diff --git a/bridged/src/main/java/dev/ltms/bridged/health/FleetHealthMonitor.java b/bridged/src/main/java/dev/ltms/fleet/health/FleetHealthMonitor.java similarity index 95% rename from bridged/src/main/java/dev/ltms/bridged/health/FleetHealthMonitor.java rename to bridged/src/main/java/dev/ltms/fleet/health/FleetHealthMonitor.java index f9ecd81..7131c71 100644 --- a/bridged/src/main/java/dev/ltms/bridged/health/FleetHealthMonitor.java +++ b/bridged/src/main/java/dev/ltms/fleet/health/FleetHealthMonitor.java @@ -1,10 +1,10 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.session.MemberSession; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.session.MemberSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +44,7 @@ public final class FleetHealthMonitor { * invoked once when a member transitions into a terminal health state. Required — * there is deliberately no defaulting overload; a caller that does not want the * fail-tickets-on-terminal-health behavior must pass an explicit inert value (see - * {@code TestTurnTokens.inert} / {@code BridgeMcp.CapacitySource.none()} for the pattern). + * {@code TestTurnTokens.inert} / {@code FleetMcp.CapacitySource.none()} for the pattern). */ public FleetHealthMonitor(AgentControl agents, Supplier> roster, MessageService messages, ScheduledExecutorService scheduler, LongSupplier clock, long intervalSeconds, diff --git a/bridged/src/main/java/dev/ltms/bridged/health/HealthDecision.java b/bridged/src/main/java/dev/ltms/fleet/health/HealthDecision.java similarity index 82% rename from bridged/src/main/java/dev/ltms/bridged/health/HealthDecision.java rename to bridged/src/main/java/dev/ltms/fleet/health/HealthDecision.java index fc10ed0..f2a6541 100644 --- a/bridged/src/main/java/dev/ltms/bridged/health/HealthDecision.java +++ b/bridged/src/main/java/dev/ltms/fleet/health/HealthDecision.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; /** Classification plus the private fact that the next pure decision needs. */ public record HealthDecision(HealthState state, HealthPrior prior) { } diff --git a/bridged/src/main/java/dev/ltms/bridged/health/HealthPrior.java b/bridged/src/main/java/dev/ltms/fleet/health/HealthPrior.java similarity index 86% rename from bridged/src/main/java/dev/ltms/bridged/health/HealthPrior.java rename to bridged/src/main/java/dev/ltms/fleet/health/HealthPrior.java index 6c0816e..b378979 100644 --- a/bridged/src/main/java/dev/ltms/bridged/health/HealthPrior.java +++ b/bridged/src/main/java/dev/ltms/fleet/health/HealthPrior.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; /** Private cross-tick observation. It is deliberately not a reported health value. */ public record HealthPrior(boolean busyButDone) { diff --git a/bridged/src/main/java/dev/ltms/bridged/health/HealthSnapshot.java b/bridged/src/main/java/dev/ltms/fleet/health/HealthSnapshot.java similarity index 80% rename from bridged/src/main/java/dev/ltms/bridged/health/HealthSnapshot.java rename to bridged/src/main/java/dev/ltms/fleet/health/HealthSnapshot.java index 0089c28..b1a14ad 100644 --- a/bridged/src/main/java/dev/ltms/bridged/health/HealthSnapshot.java +++ b/bridged/src/main/java/dev/ltms/fleet/health/HealthSnapshot.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.session.MemberSession; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.session.MemberSession; /** Read-only facts from one fleet collection tick. */ public record HealthSnapshot(MemberSession.State sessionState, AgentStatus liveStatus, diff --git a/bridged/src/main/java/dev/ltms/bridged/health/HealthState.java b/bridged/src/main/java/dev/ltms/fleet/health/HealthState.java similarity index 89% rename from bridged/src/main/java/dev/ltms/bridged/health/HealthState.java rename to bridged/src/main/java/dev/ltms/fleet/health/HealthState.java index 5a9c0bd..be7287a 100644 --- a/bridged/src/main/java/dev/ltms/bridged/health/HealthState.java +++ b/bridged/src/main/java/dev/ltms/fleet/health/HealthState.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; /** Health classifications reported for a member. */ public enum HealthState { diff --git a/bridged/src/main/java/dev/ltms/bridged/health/MuteCounter.java b/bridged/src/main/java/dev/ltms/fleet/health/MuteCounter.java similarity index 92% rename from bridged/src/main/java/dev/ltms/bridged/health/MuteCounter.java rename to bridged/src/main/java/dev/ltms/fleet/health/MuteCounter.java index c3db08e..45e8157 100644 --- a/bridged/src/main/java/dev/ltms/bridged/health/MuteCounter.java +++ b/bridged/src/main/java/dev/ltms/fleet/health/MuteCounter.java @@ -1,6 +1,6 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; -import dev.ltms.bridged.msg.Rendezvous; +import dev.ltms.fleet.msg.Rendezvous; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; diff --git a/bridged/src/main/java/dev/ltms/bridged/health/PaneBudget.java b/bridged/src/main/java/dev/ltms/fleet/health/PaneBudget.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/health/PaneBudget.java rename to bridged/src/main/java/dev/ltms/fleet/health/PaneBudget.java index 315c76a..b503bb2 100644 --- a/bridged/src/main/java/dev/ltms/bridged/health/PaneBudget.java +++ b/bridged/src/main/java/dev/ltms/fleet/health/PaneBudget.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; import java.util.ArrayList; import java.util.HashMap; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/Agent.java b/bridged/src/main/java/dev/ltms/fleet/herdr/Agent.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/herdr/Agent.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/Agent.java index 69753e3..161d310 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/Agent.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/Agent.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/AgentControl.java b/bridged/src/main/java/dev/ltms/fleet/herdr/AgentControl.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/herdr/AgentControl.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/AgentControl.java index e8ab4d5..75541a7 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/AgentControl.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/AgentControl.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/AgentStatus.java b/bridged/src/main/java/dev/ltms/fleet/herdr/AgentStatus.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/herdr/AgentStatus.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/AgentStatus.java index e04dbc5..407e7db 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/AgentStatus.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/AgentStatus.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; /** * A herdr agent's lifecycle state, as reported by {@code agent_status}. Drives the diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/HerdrClient.java b/bridged/src/main/java/dev/ltms/fleet/herdr/HerdrClient.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/herdr/HerdrClient.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/HerdrClient.java index fb215da..2b333b4 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/HerdrClient.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/HerdrClient.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/HerdrCodec.java b/bridged/src/main/java/dev/ltms/fleet/herdr/HerdrCodec.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/herdr/HerdrCodec.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/HerdrCodec.java index f44c816..e946477 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/HerdrCodec.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/HerdrCodec.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/HerdrException.java b/bridged/src/main/java/dev/ltms/fleet/herdr/HerdrException.java similarity index 96% rename from bridged/src/main/java/dev/ltms/bridged/herdr/HerdrException.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/HerdrException.java index 25540a1..6bfe55d 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/HerdrException.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/HerdrException.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; /** * Raised when a herdr call fails: transport error, or an {@code error} envelope diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/LeadTabScanner.java b/bridged/src/main/java/dev/ltms/fleet/herdr/LeadTabScanner.java similarity index 96% rename from bridged/src/main/java/dev/ltms/bridged/herdr/LeadTabScanner.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/LeadTabScanner.java index 6297d75..45ad227 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/LeadTabScanner.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/LeadTabScanner.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import org.slf4j.Logger; @@ -14,7 +14,7 @@ import java.util.function.Supplier; /** * Discovers which panes host a lead by scanning herdr for tabs the operator labelled by convention - * (CB-531), and hands {@link dev.ltms.bridged.auth.CallerResolver} the resulting + * (CB-531), and hands {@link dev.ltms.fleet.auth.CallerResolver} the resulting * {@code terminal_id → lead name} map. * *

Why scan at all. A lead is never spawned — a human opens a tab and starts an @@ -49,7 +49,7 @@ import java.util.function.Supplier; *

CB-558 — bridged now writes lead labels too. This class used to be able to say * that bridged never renames a lead tab, so the label was always the human's own writing and there * was no round-trip from the daemon's rename back into its next decision. - * {@code dev.ltms.bridged.lead.LeadLauncher} ends that: an auto-launched lead is labelled by the + * {@code dev.ltms.fleet.lead.LeadLauncher} ends that: an auto-launched lead is labelled by the * daemon and found again by this scan. The trust direction above is unaffected — bridged writing a * name for a lead it just started is not a pane promoting itself — but staleness becomes * real: a label left behind by a session that has since died would read as a live lead forever. @@ -58,7 +58,7 @@ import java.util.function.Supplier; * ever make a decision that removes something based on this map, add the same check. * The remaining hazard is an operator one — a worker {@code tabLabel} template that * happens to start with the same prefix would promote the whole fleet — and that is refused at - * startup by {@code BridgedConfig.validateLeadTabPrefixes} rather than documented here. + * startup by {@code FleetConfig.validateLeadTabPrefixes} rather than documented here. * *

Caching. {@link #get()} is on the request path (every resolve), so the scan * is TTL-cached and a stale-but-valid map is preferred to a herdr round-trip. A failed scan keeps diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/PaneLocator.java b/bridged/src/main/java/dev/ltms/fleet/herdr/PaneLocator.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/herdr/PaneLocator.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/PaneLocator.java index 4e30b73..8eaa8bd 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/PaneLocator.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/PaneLocator.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/Tab.java b/bridged/src/main/java/dev/ltms/fleet/herdr/Tab.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/herdr/Tab.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/Tab.java index 01e35cb..bee9605 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/Tab.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/Tab.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/UnixSocketHerdrClient.java b/bridged/src/main/java/dev/ltms/fleet/herdr/UnixSocketHerdrClient.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/herdr/UnixSocketHerdrClient.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/UnixSocketHerdrClient.java index b2045d0..34f70e5 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/UnixSocketHerdrClient.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/UnixSocketHerdrClient.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/Workspace.java b/bridged/src/main/java/dev/ltms/fleet/herdr/Workspace.java similarity index 96% rename from bridged/src/main/java/dev/ltms/bridged/herdr/Workspace.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/Workspace.java index 9dbfcab..7724c27 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/Workspace.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/Workspace.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; diff --git a/bridged/src/main/java/dev/ltms/bridged/herdr/WorkspaceControl.java b/bridged/src/main/java/dev/ltms/fleet/herdr/WorkspaceControl.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/herdr/WorkspaceControl.java rename to bridged/src/main/java/dev/ltms/fleet/herdr/WorkspaceControl.java index ce2c1fc..d693391 100644 --- a/bridged/src/main/java/dev/ltms/bridged/herdr/WorkspaceControl.java +++ b/bridged/src/main/java/dev/ltms/fleet/herdr/WorkspaceControl.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import org.slf4j.Logger; diff --git a/bridged/src/main/java/dev/ltms/bridged/inject/CompletionResolver.java b/bridged/src/main/java/dev/ltms/fleet/inject/CompletionResolver.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/inject/CompletionResolver.java rename to bridged/src/main/java/dev/ltms/fleet/inject/CompletionResolver.java index 3b16bad..9d140c6 100644 --- a/bridged/src/main/java/dev/ltms/bridged/inject/CompletionResolver.java +++ b/bridged/src/main/java/dev/ltms/fleet/inject/CompletionResolver.java @@ -1,8 +1,8 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.msg.TurnToken; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.msg.TurnToken; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -289,7 +289,7 @@ public final class CompletionResolver implements TurnListener { /** * Coverage summary for the CB-578 stage A exhausted-pattern classification, logged at startup - * the way {@link dev.ltms.bridged.health.FleetHealthMonitor#coverage} is — so an operator can + * the way {@link dev.ltms.fleet.health.FleetHealthMonitor#coverage} is — so an operator can * see whether the classification is on, and for which profiles, without reading every * profile's config by hand. * diff --git a/bridged/src/main/java/dev/ltms/bridged/inject/ExhaustedPatternLookup.java b/bridged/src/main/java/dev/ltms/fleet/inject/ExhaustedPatternLookup.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/inject/ExhaustedPatternLookup.java rename to bridged/src/main/java/dev/ltms/fleet/inject/ExhaustedPatternLookup.java index 79a4209..eedb4e6 100644 --- a/bridged/src/main/java/dev/ltms/bridged/inject/ExhaustedPatternLookup.java +++ b/bridged/src/main/java/dev/ltms/fleet/inject/ExhaustedPatternLookup.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; import java.util.regex.Pattern; diff --git a/bridged/src/main/java/dev/ltms/bridged/inject/ExhaustionSink.java b/bridged/src/main/java/dev/ltms/fleet/inject/ExhaustionSink.java similarity index 89% rename from bridged/src/main/java/dev/ltms/bridged/inject/ExhaustionSink.java rename to bridged/src/main/java/dev/ltms/fleet/inject/ExhaustionSink.java index d7b35a0..e1a9220 100644 --- a/bridged/src/main/java/dev/ltms/bridged/inject/ExhaustionSink.java +++ b/bridged/src/main/java/dev/ltms/fleet/inject/ExhaustionSink.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; /** * Notified when {@link CompletionResolver} actually delivers a {@code BACKEND_EXHAUSTED} @@ -8,7 +8,7 @@ package dev.ltms.bridged.inject; * *

{@link CompletionResolver} knows only {@code target} (a herdr terminal id); it has no notion of * profiles or credentials, so mapping {@code target} to whatever should be quarantined is entirely - * the sink's job — see {@code Bridged.main}'s wiring, which resolves target → session → profile → + * the sink's job — see {@code Fleetd.main}'s wiring, which resolves target → session → profile → * {@code effectiveCredentialId()} and calls {@code BackendQuarantine.quarantine} on it. */ @FunctionalInterface diff --git a/bridged/src/main/java/dev/ltms/bridged/inject/Injector.java b/bridged/src/main/java/dev/ltms/fleet/inject/Injector.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/inject/Injector.java rename to bridged/src/main/java/dev/ltms/fleet/inject/Injector.java index eeb62f3..9bafae7 100644 --- a/bridged/src/main/java/dev/ltms/bridged/inject/Injector.java +++ b/bridged/src/main/java/dev/ltms/fleet/inject/Injector.java @@ -1,8 +1,8 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.msg.TurnToken; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.msg.TurnToken; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,7 +81,7 @@ public final class Injector { /** * The single source for the injector poll cadence — how often the {@link StatusPoller} drives - * {@link #onStatus} at. {@code Bridged} passes this to every {@link StatusPoller} it constructs, + * {@link #onStatus} at. {@code Fleetd} passes this to every {@link StatusPoller} it constructs, * and this class reads it to state the readiness grace in seconds on the CB-562 expiry log * instead of hardcoding "60s". One constant, so a cadence change cannot silently desync a log * that claims a grace duration. diff --git a/bridged/src/main/java/dev/ltms/bridged/inject/MemberPresence.java b/bridged/src/main/java/dev/ltms/fleet/inject/MemberPresence.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/inject/MemberPresence.java rename to bridged/src/main/java/dev/ltms/fleet/inject/MemberPresence.java index 7986f68..6f43433 100644 --- a/bridged/src/main/java/dev/ltms/bridged/inject/MemberPresence.java +++ b/bridged/src/main/java/dev/ltms/fleet/inject/MemberPresence.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; import java.util.concurrent.ConcurrentHashMap; import java.util.Set; diff --git a/bridged/src/main/java/dev/ltms/bridged/inject/StatusPoller.java b/bridged/src/main/java/dev/ltms/fleet/inject/StatusPoller.java similarity index 95% rename from bridged/src/main/java/dev/ltms/bridged/inject/StatusPoller.java rename to bridged/src/main/java/dev/ltms/fleet/inject/StatusPoller.java index d3592a6..706651f 100644 --- a/bridged/src/main/java/dev/ltms/bridged/inject/StatusPoller.java +++ b/bridged/src/main/java/dev/ltms/fleet/inject/StatusPoller.java @@ -1,8 +1,8 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.herdr.HerdrException; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.herdr.HerdrException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bridged/src/main/java/dev/ltms/bridged/inject/StatusRefiner.java b/bridged/src/main/java/dev/ltms/fleet/inject/StatusRefiner.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/inject/StatusRefiner.java rename to bridged/src/main/java/dev/ltms/fleet/inject/StatusRefiner.java index bc7551f..bc55d02 100644 --- a/bridged/src/main/java/dev/ltms/bridged/inject/StatusRefiner.java +++ b/bridged/src/main/java/dev/ltms/fleet/inject/StatusRefiner.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bridged/src/main/java/dev/ltms/bridged/inject/TurnListener.java b/bridged/src/main/java/dev/ltms/fleet/inject/TurnListener.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/inject/TurnListener.java rename to bridged/src/main/java/dev/ltms/fleet/inject/TurnListener.java index 0ba258d..1ab1b35 100644 --- a/bridged/src/main/java/dev/ltms/bridged/inject/TurnListener.java +++ b/bridged/src/main/java/dev/ltms/fleet/inject/TurnListener.java @@ -1,6 +1,6 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; -import dev.ltms.bridged.msg.TurnToken; +import dev.ltms.fleet.msg.TurnToken; /** * Notified when a worker's delegated turn is observed to complete — a confirmed diff --git a/bridged/src/main/java/dev/ltms/bridged/lead/LeadLauncher.java b/bridged/src/main/java/dev/ltms/fleet/lead/LeadLauncher.java similarity index 90% rename from bridged/src/main/java/dev/ltms/bridged/lead/LeadLauncher.java rename to bridged/src/main/java/dev/ltms/fleet/lead/LeadLauncher.java index 6d97ac1..de36d1e 100644 --- a/bridged/src/main/java/dev/ltms/bridged/lead/LeadLauncher.java +++ b/bridged/src/main/java/dev/ltms/fleet/lead/LeadLauncher.java @@ -1,12 +1,12 @@ -package dev.ltms.bridged.lead; +package dev.ltms.fleet.lead; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.HerdrException; -import dev.ltms.bridged.herdr.Tab; -import dev.ltms.bridged.herdr.Workspace; -import dev.ltms.bridged.herdr.WorkspaceControl; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.HerdrException; +import dev.ltms.fleet.herdr.Tab; +import dev.ltms.fleet.herdr.Workspace; +import dev.ltms.fleet.herdr.WorkspaceControl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,14 +54,14 @@ public final class LeadLauncher { private final AgentControl agents; private final WorkspaceControl spaces; - private final BridgedConfig cfg; + private final FleetConfig cfg; /** * @param agents herdr agent control (start, list) * @param spaces workspace / tab control (ensure, create, label, list) * @param cfg the loaded config — {@code fleet.leaders}, {@code profiles} and each lead's tab */ - public LeadLauncher(AgentControl agents, WorkspaceControl spaces, BridgedConfig cfg) { + public LeadLauncher(AgentControl agents, WorkspaceControl spaces, FleetConfig cfg) { this.agents = agents; this.spaces = spaces; this.cfg = cfg; @@ -75,7 +75,7 @@ public final class LeadLauncher { * the remaining leads are still attempted. */ public int ensureLeads() { - Map leaders = cfg.fleet().leaders(); + Map leaders = cfg.fleet().leaders(); if (leaders.isEmpty()) { return 0; } @@ -91,9 +91,9 @@ public final class LeadLauncher { } int started = 0; - for (Map.Entry e : leaders.entrySet()) { + for (Map.Entry e : leaders.entrySet()) { String name = e.getKey(); - BridgedConfig.Leader lead = e.getValue(); + FleetConfig.Leader lead = e.getValue(); int running = live.getOrDefault(name, 0); int wanted = lead.instances(); @@ -110,7 +110,7 @@ public final class LeadLauncher { continue; } - BridgedConfig.Profile profile = cfg.profiles().get(lead.profile()); + FleetConfig.Profile profile = cfg.profiles().get(lead.profile()); if (profile == null) { log.warn("lead '{}' names profile '{}', which is not configured — not launching", name, lead.profile()); @@ -138,9 +138,9 @@ public final class LeadLauncher { * already carries {@link Agent#tabId()} directly, so a hand-opened lead is found the same way an * auto-launched one is — by labelling its tab to match. */ - private Map liveLeads(Map leaders) { + private Map liveLeads(Map leaders) { Set memberSpaces = cfg.profiles().values().stream() - .map(BridgedConfig.Profile::workspace) + .map(FleetConfig.Profile::workspace) .filter(w -> w != null && !w.isBlank()) .collect(Collectors.toSet()); @@ -174,12 +174,12 @@ public final class LeadLauncher { *

Matched exactly (case-insensitively) against each lead's configured {@code tab}, so an * operator's {@code "lead: something-else"} tab is not mistaken for a configured lead. */ - private String leadNameOf(String label, Map leaders) { + private String leadNameOf(String label, Map leaders) { if (label == null) { return null; } String l = label.strip(); - for (Map.Entry e : leaders.entrySet()) { + for (Map.Entry e : leaders.entrySet()) { String tab = e.getValue().tabLabel(); if (tab != null && l.equalsIgnoreCase(tab.strip())) { return e.getKey(); @@ -189,7 +189,7 @@ public final class LeadLauncher { } /** Start one lead. Returns false (having logged) rather than throwing on any failure. */ - private boolean launch(String name, BridgedConfig.Leader lead, BridgedConfig.Profile profile) { + private boolean launch(String name, FleetConfig.Leader lead, FleetConfig.Profile profile) { String label = lead.tabLabel(); String cwd = (lead.cwd() == null || lead.cwd().isBlank()) ? System.getProperty("user.dir") : lead.cwd(); @@ -236,7 +236,7 @@ public final class LeadLauncher { * The herdr agent kind for this profile — the same value the matching member adapter passes, so * herdr resolves the same executable for a lead as it does for a member on that backend. */ - private static String herdrKind(BridgedConfig.Profile profile) { + private static String herdrKind(FleetConfig.Profile profile) { return profile.isOpenCode() ? "opencode" : "claude"; } @@ -248,7 +248,7 @@ public final class LeadLauncher { * any other primary. This is the single most important difference from the member launchers; * do not "unify" it back. */ - private List leadArgv(BridgedConfig.Profile profile) { + private List leadArgv(FleetConfig.Profile profile) { List argv = new ArrayList<>(profile.argv()); if (profile.hasMcp()) { argv.add("--mcp-config"); @@ -274,7 +274,7 @@ public final class LeadLauncher { * definition, so there is no configuration under which pointing it elsewhere is correct, and a * profile that carries them (a member profile reused as a lead's backend) must not leak them in. */ - private Map leadEnv(BridgedConfig.Profile profile) { + private Map leadEnv(FleetConfig.Profile profile) { Map out = new LinkedHashMap<>(); if (profile.env() != null) { out.putAll(profile.env()); diff --git a/bridged/src/main/java/dev/ltms/bridged/logging/McpCancelledNotificationFilter.java b/bridged/src/main/java/dev/ltms/fleet/logging/McpCancelledNotificationFilter.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/logging/McpCancelledNotificationFilter.java rename to bridged/src/main/java/dev/ltms/fleet/logging/McpCancelledNotificationFilter.java index d6f0463..98abee9 100644 --- a/bridged/src/main/java/dev/ltms/bridged/logging/McpCancelledNotificationFilter.java +++ b/bridged/src/main/java/dev/ltms/fleet/logging/McpCancelledNotificationFilter.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.logging; +package dev.ltms.fleet.logging; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; diff --git a/bridged/src/main/java/dev/ltms/bridged/mcp/ConnectionIdentity.java b/bridged/src/main/java/dev/ltms/fleet/mcp/ConnectionIdentity.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/mcp/ConnectionIdentity.java rename to bridged/src/main/java/dev/ltms/fleet/mcp/ConnectionIdentity.java index 00bf746..53b58e0 100644 --- a/bridged/src/main/java/dev/ltms/bridged/mcp/ConnectionIdentity.java +++ b/bridged/src/main/java/dev/ltms/fleet/mcp/ConnectionIdentity.java @@ -1,6 +1,6 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; -import dev.ltms.bridged.herdr.PaneLocator; +import dev.ltms.fleet.herdr.PaneLocator; /** * Resolves who is calling an MCP tool from the connection alone — the anti-spoofing diff --git a/bridged/src/main/java/dev/ltms/bridged/mcp/BridgeMcp.java b/bridged/src/main/java/dev/ltms/fleet/mcp/FleetMcp.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/mcp/BridgeMcp.java rename to bridged/src/main/java/dev/ltms/fleet/mcp/FleetMcp.java index 1a994ba..fe67ef2 100644 --- a/bridged/src/main/java/dev/ltms/bridged/mcp/BridgeMcp.java +++ b/bridged/src/main/java/dev/ltms/fleet/mcp/FleetMcp.java @@ -1,26 +1,26 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; -import dev.ltms.bridged.auth.AuditLog; -import dev.ltms.bridged.auth.Authz; -import dev.ltms.bridged.auth.CallerResolver; -import dev.ltms.bridged.auth.Principal; -import dev.ltms.bridged.auth.Role; -import dev.ltms.bridged.guard.GuardException; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.metrics.BridgedMetrics; -import dev.ltms.bridged.metrics.Metrics; -import dev.ltms.bridged.inject.MemberPresence; -import dev.ltms.bridged.herdr.HerdrException; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.peer.PeerUnreachableException; -import dev.ltms.bridged.placement.BackendQuarantine; -import dev.ltms.bridged.placement.PlacementException; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.session.MemberSession; -import dev.ltms.bridged.session.WorktreeRequest; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.PeerLauncher; +import dev.ltms.fleet.auth.AuditLog; +import dev.ltms.fleet.auth.Authz; +import dev.ltms.fleet.auth.CallerResolver; +import dev.ltms.fleet.auth.Principal; +import dev.ltms.fleet.auth.Role; +import dev.ltms.fleet.guard.GuardException; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.metrics.FleetMetrics; +import dev.ltms.fleet.metrics.Metrics; +import dev.ltms.fleet.inject.MemberPresence; +import dev.ltms.fleet.herdr.HerdrException; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.peer.PeerUnreachableException; +import dev.ltms.fleet.placement.BackendQuarantine; +import dev.ltms.fleet.placement.PlacementException; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.session.MemberSession; +import dev.ltms.fleet.session.WorktreeRequest; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.PeerLauncher; import io.modelcontextprotocol.common.McpTransportContext; import io.modelcontextprotocol.json.McpJsonMapper; import io.modelcontextprotocol.json.jackson3.JacksonMcpJsonMapperSupplier; @@ -61,9 +61,9 @@ import org.slf4j.LoggerFactory; * {@link McpSchema.CallToolResult}, so it is unit-testable without standing up the HTTP transport; * the SDK owns the wire protocol. Mount {@link #servlet()} at {@code /mcp} on the daemon's Jetty. */ -public final class BridgeMcp { +public final class FleetMcp { - private static final Logger log = LoggerFactory.getLogger(BridgeMcp.class); + private static final Logger log = LoggerFactory.getLogger(FleetMcp.class); private static final long DEFAULT_TIMEOUT_MS = 25_000; private static final long MAX_TIMEOUT_MS = 120_000; @@ -127,7 +127,7 @@ public final class BridgeMcp { * @param quarantine CB-578 stage B facts for {@code fleet_profiles}; required — pass * {@link QuarantineSource#none()} for a caller that does not want the feature */ - public BridgeMcp(MessageService messages, PeerLauncher workers, SessionManager sessions, + public FleetMcp(MessageService messages, PeerLauncher workers, SessionManager sessions, ConnectionIdentity identity, MemberPresence presence, PrimaryRegistry primaryRegistry, CallerResolver callers, Metrics metrics, CapacitySource capacity, HealthCoverageSource healthCoverage, QuarantineSource quarantine) { @@ -377,7 +377,7 @@ public final class BridgeMcp { * without fabricating an SDK {@code McpSyncServerExchange}. * *

This surface exists because the enforcement was previously unreachable from a test: no - * test constructs a {@code BridgeMcp}, so the whole MCP-side gate ran zero times in the suite + * test constructs a {@code FleetMcp}, so the whole MCP-side gate ran zero times in the suite * while the REST-side equivalent had ten tests. A security control nothing exercises is a * claim, not a control. * @@ -398,7 +398,7 @@ public final class BridgeMcp { String reason = Authz.isUnauthenticated(caller) ? "unauthenticated" : "forbidden"; AuditLog.denied(caller, action, target, reason); if (metrics != null) { - metrics.inc(BridgedMetrics.AUTH_FAILURES, "reason", reason); + metrics.inc(FleetMetrics.AUTH_FAILURES, "reason", reason); } return error(reason + ": " + caller.describe() + " may not " + action); } @@ -745,7 +745,7 @@ public final class BridgeMcp { * CB-301-ext: {@code worktreeRequest} non-null provisions an isolated git worktree. * CB-584: {@code sessionName}/{@code resumeSessionId} request agent session identity — a resumed * conversation requires an explicit {@code profile} whose adapter declares - * {@link dev.ltms.bridged.peer.Capability#SESSION_RESUME}, or the spawn is refused rather than + * {@link dev.ltms.fleet.peer.Capability#SESSION_RESUME}, or the spawn is refused rather than * silently starting a cold session. * *

{@code role} and {@code profile} are independent: the role picks the contract, the profile diff --git a/bridged/src/main/java/dev/ltms/bridged/mcp/LsofPeerPidLookup.java b/bridged/src/main/java/dev/ltms/fleet/mcp/LsofPeerPidLookup.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/mcp/LsofPeerPidLookup.java rename to bridged/src/main/java/dev/ltms/fleet/mcp/LsofPeerPidLookup.java index fa47546..79da40d 100644 --- a/bridged/src/main/java/dev/ltms/bridged/mcp/LsofPeerPidLookup.java +++ b/bridged/src/main/java/dev/ltms/fleet/mcp/LsofPeerPidLookup.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bridged/src/main/java/dev/ltms/bridged/mcp/LsofProcessCwdLookup.java b/bridged/src/main/java/dev/ltms/fleet/mcp/LsofProcessCwdLookup.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/mcp/LsofProcessCwdLookup.java rename to bridged/src/main/java/dev/ltms/fleet/mcp/LsofProcessCwdLookup.java index f53e801..8acf098 100644 --- a/bridged/src/main/java/dev/ltms/bridged/mcp/LsofProcessCwdLookup.java +++ b/bridged/src/main/java/dev/ltms/fleet/mcp/LsofProcessCwdLookup.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bridged/src/main/java/dev/ltms/bridged/mcp/PeerPidLookup.java b/bridged/src/main/java/dev/ltms/fleet/mcp/PeerPidLookup.java similarity index 93% rename from bridged/src/main/java/dev/ltms/bridged/mcp/PeerPidLookup.java rename to bridged/src/main/java/dev/ltms/fleet/mcp/PeerPidLookup.java index 105713a..106625b 100644 --- a/bridged/src/main/java/dev/ltms/bridged/mcp/PeerPidLookup.java +++ b/bridged/src/main/java/dev/ltms/fleet/mcp/PeerPidLookup.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; /** * Resolves the OS PID that owns a loopback TCP source port — the OS half of connection-based MCP diff --git a/bridged/src/main/java/dev/ltms/bridged/mcp/PrimaryRegistry.java b/bridged/src/main/java/dev/ltms/fleet/mcp/PrimaryRegistry.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/mcp/PrimaryRegistry.java rename to bridged/src/main/java/dev/ltms/fleet/mcp/PrimaryRegistry.java index 9e441ea..3682bee 100644 --- a/bridged/src/main/java/dev/ltms/bridged/mcp/PrimaryRegistry.java +++ b/bridged/src/main/java/dev/ltms/fleet/mcp/PrimaryRegistry.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bridged/src/main/java/dev/ltms/bridged/mcp/ProcessCwdLookup.java b/bridged/src/main/java/dev/ltms/fleet/mcp/ProcessCwdLookup.java similarity index 92% rename from bridged/src/main/java/dev/ltms/bridged/mcp/ProcessCwdLookup.java rename to bridged/src/main/java/dev/ltms/fleet/mcp/ProcessCwdLookup.java index 708738b..53b0c5c 100644 --- a/bridged/src/main/java/dev/ltms/bridged/mcp/ProcessCwdLookup.java +++ b/bridged/src/main/java/dev/ltms/fleet/mcp/ProcessCwdLookup.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; /** * Resolves a process's current working directory from its PID — the OS half of CB-112's diff --git a/bridged/src/main/java/dev/ltms/bridged/member/ClaudeCodeLauncher.java b/bridged/src/main/java/dev/ltms/fleet/member/ClaudeCodeLauncher.java similarity index 90% rename from bridged/src/main/java/dev/ltms/bridged/member/ClaudeCodeLauncher.java rename to bridged/src/main/java/dev/ltms/fleet/member/ClaudeCodeLauncher.java index f1e196e..3a39d11 100644 --- a/bridged/src/main/java/dev/ltms/bridged/member/ClaudeCodeLauncher.java +++ b/bridged/src/main/java/dev/ltms/fleet/member/ClaudeCodeLauncher.java @@ -1,11 +1,11 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.peer.Capability; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.peer.Capability; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,7 +53,7 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * existing deployments and tests keep the legacy non-blocking spawn semantics. */ public ClaudeCodeLauncher(AgentControl agents, WorkspaceControl spaces, SubscriptionGuard guard, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env) { this(agents, spaces, guard, profiles, defaultProfile, env, 0, System::currentTimeMillis, () -> sleepUninterruptibly(300)); @@ -64,7 +64,7 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * until the pane reports an injectable state or {@code spawnReadyTimeoutMs} elapses. */ public ClaudeCodeLauncher(AgentControl agents, WorkspaceControl spaces, SubscriptionGuard guard, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, long spawnReadyPollMs) { this(agents, spaces, guard, profiles, defaultProfile, env, @@ -77,10 +77,10 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * role; a profile may still override it with its own {@code tabLabel}. */ public ClaudeCodeLauncher(AgentControl agents, WorkspaceControl spaces, SubscriptionGuard guard, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, long spawnReadyPollMs, - Supplier fleet) { + Supplier fleet) { this(agents, spaces, guard, profiles, defaultProfile, env, spawnReadyTimeoutMs, System::currentTimeMillis, () -> sleepUninterruptibly(spawnReadyPollMs), @@ -91,11 +91,11 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * Production constructor, plus the CB-596 {@code memberCredentials} policy supplier. */ public ClaudeCodeLauncher(AgentControl agents, WorkspaceControl spaces, SubscriptionGuard guard, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, long spawnReadyPollMs, - Supplier fleet, - Supplier memberCredentials) { + Supplier fleet, + Supplier memberCredentials) { this(agents, spaces, guard, profiles, defaultProfile, env, spawnReadyTimeoutMs, System::currentTimeMillis, () -> sleepUninterruptibly(spawnReadyPollMs), @@ -120,7 +120,7 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * (poll ms) is accepted for API symmetry but otherwise unused here */ public ClaudeCodeLauncher(AgentControl agents, WorkspaceControl spaces, SubscriptionGuard guard, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper) { @@ -134,11 +134,11 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * @param fleet live fleet config, read once for each spawn */ public ClaudeCodeLauncher(AgentControl agents, WorkspaceControl spaces, SubscriptionGuard guard, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, - Supplier fleet) { + Supplier fleet) { super(NAME_PREFIX, agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, nowMillis, sleeper, fleet); this.guard = guard; @@ -148,12 +148,12 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * Full testability constructor, plus the CB-596 {@code memberCredentials} policy supplier. */ public ClaudeCodeLauncher(AgentControl agents, WorkspaceControl spaces, SubscriptionGuard guard, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, - Supplier fleet, - Supplier memberCredentials) { + Supplier fleet, + Supplier memberCredentials) { super(NAME_PREFIX, agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, nowMillis, sleeper, fleet, memberCredentials); this.guard = guard; @@ -165,12 +165,12 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * default (the real {@code System.getenv()} key set) via the constructor above. */ public ClaudeCodeLauncher(AgentControl agents, WorkspaceControl spaces, SubscriptionGuard guard, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, - Supplier fleet, - Supplier memberCredentials, + Supplier fleet, + Supplier memberCredentials, Supplier> hostEnvNames) { super(NAME_PREFIX, agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, nowMillis, sleeper, fleet, memberCredentials, hostEnvNames); @@ -187,7 +187,7 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * applied here — see {@link #applySessionIdentity}. */ @Override - protected Launch buildLaunch(BridgedConfig.Profile cfg, LaunchSpec spec) { + protected Launch buildLaunch(FleetConfig.Profile cfg, LaunchSpec spec) { // CB-539: a profile may deliberately opt into the subscription (subscription: true) when no // off-subscription endpoint exists for it — e.g. `sonnet` on `ccs`. That profile gets no // ANTHROPIC_BASE_URL/AUTH_TOKEN (there is nothing to point them at) and the guard's base_url @@ -232,9 +232,9 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { // handle is known BEFORE the agent has written anything; a resume spawn adopts its prior // id via -r and passes no --session-id (the two conflict). Both are injected before the // model flag so --model keeps outranking the operator's own argv. - // mutableArgv: argvWithBridge may hand back the profile's own (immutable) List.of when it + // mutableArgv: argvWithFleet may hand back the profile's own (immutable) List.of when it // has neither MCP nor a charter — session flags must be added into a list we own. - List argv = mutableArgv(argvWithBridge(cfg, spec)); + List argv = mutableArgv(argvWithFleet(cfg, spec)); String agentSessionId = applySessionIdentity(argv, spec.sessionName(), spec.resumeSessionId()); return new Launch(workerEnv, argvWithModel(argv, cfg), agentSessionId); } @@ -289,7 +289,7 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * is present it keeps its proven inline {@code --append-system-prompt} delivery, which is also * the only form that reaches a member with no repo checkout. */ - private List argvWithBridge(BridgedConfig.Profile cfg, LaunchSpec spec) { + private List argvWithFleet(FleetConfig.Profile cfg, LaunchSpec spec) { String roleCharter = nonBlank(spec.roleCharter()); String replyCharter = nonBlank(spec.replyCharter()); Path agentFile = agentDefinitionFile(spec.cwd(), spec.role(), ".claude", "agents"); @@ -358,7 +358,7 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * {@code gx10} does) are untouched — this adds nothing when there is nothing to add. This is * the {@code kind: claude} counterpart of the opencode adapter's {@code -m provider/model}. */ - private static List argvWithModel(List argv, BridgedConfig.Profile cfg) { + private static List argvWithModel(List argv, FleetConfig.Profile cfg) { if (cfg.model() == null || cfg.model().isBlank()) { return argv; } @@ -411,7 +411,7 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { /** Whether any configured profile opts into a git-forge token (required for {@link Capability#SELF_PR}). */ private boolean hasGitTokenProfile() { - return profileConfigs().stream().anyMatch(BridgedConfig.Profile::hasGitToken); + return profileConfigs().stream().anyMatch(FleetConfig.Profile::hasGitToken); } // --- CB-117 reap predicate (Claude prefix), kept for direct unit testing ------------------- diff --git a/bridged/src/main/java/dev/ltms/bridged/member/CompositePeerLauncher.java b/bridged/src/main/java/dev/ltms/fleet/member/CompositePeerLauncher.java similarity index 92% rename from bridged/src/main/java/dev/ltms/bridged/member/CompositePeerLauncher.java rename to bridged/src/main/java/dev/ltms/fleet/member/CompositePeerLauncher.java index fcf09f5..1469b30 100644 --- a/bridged/src/main/java/dev/ltms/bridged/member/CompositePeerLauncher.java +++ b/bridged/src/main/java/dev/ltms/fleet/member/CompositePeerLauncher.java @@ -1,19 +1,19 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.PeerHandle; -import dev.ltms.bridged.peer.PeerLauncher; -import dev.ltms.bridged.peer.PeerUnreachableException; -import dev.ltms.bridged.peer.SpawnRequest; -import dev.ltms.bridged.placement.BackendQuarantine; -import dev.ltms.bridged.placement.PlacementCandidate; -import dev.ltms.bridged.placement.PlacementContext; -import dev.ltms.bridged.placement.PlacementException; -import dev.ltms.bridged.placement.PlacementPolicies; -import dev.ltms.bridged.placement.PlacementPolicy; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.PeerHandle; +import dev.ltms.fleet.peer.PeerLauncher; +import dev.ltms.fleet.peer.PeerUnreachableException; +import dev.ltms.fleet.peer.SpawnRequest; +import dev.ltms.fleet.placement.BackendQuarantine; +import dev.ltms.fleet.placement.PlacementCandidate; +import dev.ltms.fleet.placement.PlacementContext; +import dev.ltms.fleet.placement.PlacementException; +import dev.ltms.fleet.placement.PlacementPolicies; +import dev.ltms.fleet.placement.PlacementPolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,7 +78,7 @@ public final class CompositePeerLauncher implements PeerLauncher { * this way is the set of adapters ({@link #byProfile}), because a new backend needs a launcher * and launchers are built once; {@code ConfigRef} classifies that as deferred and says so. */ - private final Supplier> profileConfigs; + private final Supplier> profileConfigs; private final Supplier placementPolicy; /** CB-578 stage B: credential cooldown, checked before an explicit spawn and filtered into placement. */ @@ -89,7 +89,7 @@ public final class CompositePeerLauncher implements PeerLauncher { * {@code null}, and an empty pool for a role, both fall back to every configured profile — the * pre-CB-557 behaviour. */ - private final Supplier fleet; + private final Supplier fleet; /** * Backward-compatible constructor: fixed placement, no live-counting. Use this for tests and @@ -119,7 +119,7 @@ public final class CompositePeerLauncher implements PeerLauncher { */ public CompositePeerLauncher(List delegates, String defaultProfile, - Map profileConfigs, + Map profileConfigs, PlacementPolicy placementPolicy, Function liveCount) { this(delegates, defaultProfile, profileConfigs, placementPolicy, liveCount, null, BackendQuarantine.none()); @@ -136,27 +136,27 @@ public final class CompositePeerLauncher implements PeerLauncher { */ public CompositePeerLauncher(List delegates, String defaultProfile, - Map profileConfigs, + Map profileConfigs, PlacementPolicy placementPolicy, Function liveCount, - BridgedConfig.Fleet fleet) { + FleetConfig.Fleet fleet) { this(delegates, defaultProfile, profileConfigs, placementPolicy, liveCount, fleet, BackendQuarantine.none()); } /** * Production constructor with role pools and quarantine (CB-578 stage B). The full-featured * non-reloading form; {@link #CompositePeerLauncher(List, String, Supplier, Function, BackendQuarantine)} - * is what {@code Bridged.main} actually wires up. + * is what {@code Fleetd.main} actually wires up. * * @param quarantine required — pass {@link BackendQuarantine#none()} for a caller that does not * want the feature, never a defaulting overload (CB-578 stage B's own rule). */ public CompositePeerLauncher(List delegates, String defaultProfile, - Map profileConfigs, + Map profileConfigs, PlacementPolicy placementPolicy, Function liveCount, - BridgedConfig.Fleet fleet, + FleetConfig.Fleet fleet, BackendQuarantine quarantine) { // LinkedHashMap, not Map.copyOf: candidates() promises definition order and the weighted // policy breaks exact-weight ties on it, so a salted iteration order would make placement @@ -175,7 +175,7 @@ public final class CompositePeerLauncher implements PeerLauncher { */ public CompositePeerLauncher(List delegates, String defaultProfile, - Supplier config, + Supplier config, Function liveCount, BackendQuarantine quarantine) { this(delegates, defaultProfile, @@ -189,10 +189,10 @@ public final class CompositePeerLauncher implements PeerLauncher { /** The all-suppliers form every other constructor funnels into. */ private CompositePeerLauncher(List delegates, String defaultProfile, - Supplier> profileConfigs, + Supplier> profileConfigs, Supplier placementPolicy, Function liveCount, - Supplier fleet, + Supplier fleet, BackendQuarantine quarantine) { this.fleet = fleet; this.quarantine = Objects.requireNonNull(quarantine, "quarantine"); @@ -229,8 +229,8 @@ public final class CompositePeerLauncher implements PeerLauncher { *

Read fresh on every call so a reload is visible; a caller that needs two consistent reads * takes one local, as {@link #poolFor} does. */ - private Map profiles0() { - Map m = profileConfigs.get(); + private Map profiles0() { + Map m = profileConfigs.get(); return m == null ? Map.of() : m; } @@ -254,7 +254,7 @@ public final class CompositePeerLauncher implements PeerLauncher { String requestedProfile = req.profileName(); if (requestedProfile != null && !requestedProfile.isBlank()) { // An explicit profile bypasses the placement policy, but not the capacity cap: maxLoad - // is documented as an unconditional limit on this profile (BridgedConfig.Profile), and + // is documented as an unconditional limit on this profile (FleetConfig.Profile), and // the charter makes explicit-profile spawns the normal path — so skipping the check // here would leave the cap dead config in real operation. HerdrPeerLauncher d = route(requestedProfile); @@ -317,7 +317,7 @@ public final class CompositePeerLauncher implements PeerLauncher { /** * Refuse an explicit-profile spawn when the profile is at its {@code maxLoad} cap. * - *

maxLoad is a documented, unconditional capacity limit (see {@code BridgedConfig.Profile#maxLoad}), + *

maxLoad is a documented, unconditional capacity limit (see {@code FleetConfig.Profile#maxLoad}), * and the charter makes explicit-profile spawns the normal path — so enforcing it only in placement * ({@code PlacementPolicyUtil}, package-private, hence not linked) would leave the cap dead config * on every call that names a profile. Same rule as placement: {@code live >= cap} is at capacity. @@ -359,7 +359,7 @@ public final class CompositePeerLauncher implements PeerLauncher { /** {@code profile}'s credential group (CB-578 stage B), or the profile's own name if unconfigured. */ private String credentialIdFor(String profile) { - BridgedConfig.Profile cfg = profiles0().get(profile); + FleetConfig.Profile cfg = profiles0().get(profile); return cfg == null ? profile : cfg.effectiveCredentialId(); } @@ -377,7 +377,7 @@ public final class CompositePeerLauncher implements PeerLauncher { // until CB-585: an explicit `maxLoad: 0` now survives as 0 and is a real cap of zero, so the // check below refuses every spawn on that profile, and a negative value is refused at config // load rather than normalized away. - BridgedConfig.Profile cfg = profiles0().get(profile); + FleetConfig.Profile cfg = profiles0().get(profile); Integer cap = (cfg == null) ? null : cfg.maxLoad(); if (cap == null) { return; @@ -398,8 +398,8 @@ public final class CompositePeerLauncher implements PeerLauncher { * a pool entry with no profile, so a survivor is a profile this particular composite does not own. */ private List poolFor(MemberRole role) { - Map configured = profiles0(); - BridgedConfig.Fleet f = fleet.get(); + Map configured = profiles0(); + FleetConfig.Fleet f = fleet.get(); List pool = (f == null) ? List.of() : f.profilesFor(role); List known = pool.stream().filter(configured::containsKey).toList(); return known.isEmpty() ? List.copyOf(configured.keySet()) : known; @@ -415,7 +415,7 @@ public final class CompositePeerLauncher implements PeerLauncher { private List candidates(MemberRole role) { List out = new ArrayList<>(); for (String name : poolFor(role)) { - BridgedConfig.Profile w = profiles0().get(name); + FleetConfig.Profile w = profiles0().get(name); if (w != null) { out.add(new PlacementCandidate(name, null, w.weight(), w.maxLoad())); } diff --git a/bridged/src/main/java/dev/ltms/bridged/member/HerdrPeerLauncher.java b/bridged/src/main/java/dev/ltms/fleet/member/HerdrPeerLauncher.java similarity index 93% rename from bridged/src/main/java/dev/ltms/bridged/member/HerdrPeerLauncher.java rename to bridged/src/main/java/dev/ltms/fleet/member/HerdrPeerLauncher.java index fc9ef19..c532b54 100644 --- a/bridged/src/main/java/dev/ltms/bridged/member/HerdrPeerLauncher.java +++ b/bridged/src/main/java/dev/ltms/fleet/member/HerdrPeerLauncher.java @@ -1,19 +1,19 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.HerdrException; -import dev.ltms.bridged.herdr.Tab; -import dev.ltms.bridged.herdr.Workspace; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.CharterReceipt; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.PeerHandle; -import dev.ltms.bridged.peer.PeerLauncher; -import dev.ltms.bridged.peer.PeerUnreachableException; -import dev.ltms.bridged.peer.SpawnRequest; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.HerdrException; +import dev.ltms.fleet.herdr.Tab; +import dev.ltms.fleet.herdr.Workspace; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.CharterReceipt; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.PeerHandle; +import dev.ltms.fleet.peer.PeerLauncher; +import dev.ltms.fleet.peer.PeerUnreachableException; +import dev.ltms.fleet.peer.SpawnRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +49,7 @@ import java.util.regex.Pattern; *

  • {@code namePrefix} (constructor arg) — the label prefix ({@code claude}, {@code opencode}) * that drives both unique naming and the orphan-reap pattern, so each adapter reaps only its * own kind of pane and never another's.
  • - *
  • {@link #buildLaunch(BridgedConfig.Profile, LaunchSpec)} — the peer-specific env map + argv, including any + *
  • {@link #buildLaunch(FleetConfig.Profile, LaunchSpec)} — the peer-specific env map + argv, including any * subscription/guard check, MCP mount, and instruction injection. The base never sees how the * peer is configured; it only places and starts the returned {@link Launch}.
  • * @@ -76,7 +76,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { private final String namePrefix; // label prefix: naming + reap scheme private final AgentControl agents; private final WorkspaceControl spaces; - private final Map profiles; // profile name → spawn settings + private final Map profiles; // profile name → spawn settings private final String defaultProfile; // profile a no-arg spawn uses (nullable) /** Host env lookup (injectable for tests); adapters read it in {@link #buildLaunch}. */ @@ -91,14 +91,14 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { *

    CB-559: a supplier rather than a snapshot, so a config reload affects the next launch * without a restart. Existing tabs keep the label they were given. */ - private final Supplier fleet; + private final Supplier fleet; /** * CB-596: the live {@code memberCredentials:} policy, read once per spawn (same hot-reload shape * as {@link #fleet}). {@code null} — either the supplier itself, or what it returns — means no * policy is configured and {@link #applyMemberCredentialPolicy} shadows nothing. */ - private final Supplier memberCredentials; + private final Supplier memberCredentials; /** * Enumerates the daemon's own process environment variable NAMES ONLY, never values — the CB-596 @@ -169,7 +169,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * interval is baked into this hook, so the base needs no poll field */ protected HerdrPeerLauncher(String namePrefix, AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper) { @@ -185,11 +185,11 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * above, so every existing call site keeps the default without an edit. */ protected HerdrPeerLauncher(String namePrefix, AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, - Supplier fleet) { + Supplier fleet) { this(namePrefix, agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, nowMillis, sleeper, fleet, null); } @@ -203,12 +203,12 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * existing call site keeps the pre-CB-596 default without an edit. */ protected HerdrPeerLauncher(String namePrefix, AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, - Supplier fleet, - Supplier memberCredentials) { + Supplier fleet, + Supplier memberCredentials) { this(namePrefix, agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, nowMillis, sleeper, fleet, memberCredentials, null); } @@ -218,12 +218,12 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * seam only — every production call site leaves this {@code null} and gets the real host env. */ protected HerdrPeerLauncher(String namePrefix, AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, - Supplier fleet, - Supplier memberCredentials, + Supplier fleet, + Supplier memberCredentials, Supplier> hostEnvNames) { this.fleet = fleet; this.namePrefix = namePrefix; @@ -246,7 +246,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * Any subscription/guard check, MCP mount, and instruction injection happen here. The env map * and argv are adapter-private; the base only places and starts what is returned. */ - protected abstract Launch buildLaunch(BridgedConfig.Profile cfg, LaunchSpec spec); + protected abstract Launch buildLaunch(FleetConfig.Profile cfg, LaunchSpec spec); /** Direct transport access for peer-specific, non-turn control operations. */ protected final AgentControl agents() { @@ -327,7 +327,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { if (name == null || name.isBlank()) { return List.of(); } - BridgedConfig.Profile cfg = profiles.get(name); + FleetConfig.Profile cfg = profiles.get(name); return cfg == null ? List.of() : cfg.parityOverlay(); } @@ -351,18 +351,18 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { } /** The configured profiles, for adapter capability decisions (e.g. any git-token grant). */ - protected Collection profileConfigs() { + protected Collection profileConfigs() { return profiles.values(); } /** Resolve {@code profileName} (null/blank → default) to its config, or throw with the options. */ - protected BridgedConfig.Profile requireProfile(String profileName) { + protected FleetConfig.Profile requireProfile(String profileName) { String name = (profileName == null || profileName.isBlank()) ? defaultProfile : profileName; if (name == null || name.isBlank()) { throw new IllegalArgumentException("no default worker profile is configured — " + "pass a profile; configured: " + profiles.keySet()); } - BridgedConfig.Profile cfg = profiles.get(name); + FleetConfig.Profile cfg = profiles.get(name); if (cfg == null) { throw new IllegalArgumentException("unknown worker profile '" + name + "' — configured: " + profiles.keySet()); @@ -399,14 +399,14 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { /** * Spawn a peer with session identity (CB-547a). The session values, role, and charter are - * threaded from the {@link SpawnRequest} into {@link #buildLaunch(BridgedConfig.Profile, + * threaded from the {@link SpawnRequest} into {@link #buildLaunch(FleetConfig.Profile, * LaunchSpec)}, and the launch's resolved agent-session id is returned alongside the agent so * the caller can put it on the {@link PeerHandle}. */ protected Spawned spawnInternal(String profileName, String requestedCwd, String callerCwd, String sessionName, String resumeSessionId, MemberRole role) { - BridgedConfig.Profile cfg = requireProfile(profileName); - BridgedConfig.Fleet liveFleet = fleet == null ? null : fleet.get(); + FleetConfig.Profile cfg = requireProfile(profileName); + FleetConfig.Fleet liveFleet = fleet == null ? null : fleet.get(); String roleCharter = liveFleet == null ? null : liveFleet.charterFor(role); String replyCharter = cfg.hasMcp() ? REPLY_CHARTER : null; String charter = roleCharter == null ? replyCharter @@ -507,7 +507,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * guaranteed last resort so a pathological environment with an unset {@code user.dir} still * honours the "never assume {@code $HOME}" contract rather than letting herdr default the pane. */ - private static String resolveCwd(String requestedCwd, BridgedConfig.Profile cfg, String callerCwd) { + private static String resolveCwd(String requestedCwd, FleetConfig.Profile cfg, String callerCwd) { return firstNonBlank(requestedCwd, cfg.cwd(), callerCwd, System.getProperty("user.dir"), "."); } @@ -519,8 +519,8 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { } /** Dedicated worker space → own tab (carrying cwd+env) → start the peer into the seed pane. */ - private Agent spawnInTab(BridgedConfig.Profile cfg, Map workerEnv, - List argv, String cwd, MemberRole role, BridgedConfig.Fleet liveFleet) { + private Agent spawnInTab(FleetConfig.Profile cfg, Map workerEnv, + List argv, String cwd, MemberRole role, FleetConfig.Fleet liveFleet) { Workspace space = spaces.ensureWorkspace(cfg.workspace()); Tab.Created tab = spaces.createTab(space.workspaceId(), cwd, workerEnv); log.info("spawning {} profile={} space={} tab={} cwd={}", @@ -578,7 +578,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * composed charter, if any; its argv element is replaced by its digest so the log still shows * which args were passed without exposing the charter prose. */ - private Agent spawnAsPane(BridgedConfig.Profile cfg, Map workerEnv, + private Agent spawnAsPane(FleetConfig.Profile cfg, Map workerEnv, List argv, String cwd, String charter) { log.info("spawning {} (pane placement) profile={} cwd={} argv={}", namePrefix, cfg.profile(), cwd, redactCharter(argv, charter)); @@ -620,7 +620,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * backstop for the astronomically unlikely nonce+seq clash; the name is a label only — herdr * detects kind and status from terminal output, not from it. */ - private Started startUniquelyNamed(BridgedConfig.Profile cfg, List argv, String paneId) { + private Started startUniquelyNamed(FleetConfig.Profile cfg, List argv, String paneId) { // Protocol 19 resolves the executable from the agent kind (== namePrefix here), so // argv[0] — the configured executable — is dropped and only the extra args are passed. List args = argv.isEmpty() ? argv : argv.subList(1, argv.size()); @@ -778,7 +778,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { /** Whether any configured profile places peers in their own tab (so tabs may need cleanup). */ private boolean usesTabPlacement() { - return profiles.values().stream().anyMatch(BridgedConfig.Profile::tabPlacement); + return profiles.values().stream().anyMatch(FleetConfig.Profile::tabPlacement); } /** True when a herdr error means the target is already gone (safe to treat as done). */ @@ -844,7 +844,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * {@code GITEA_HOST}. Push over SSH is unaffected; the only incremental grant is PR-create. * Peer-neutral, so every herdr adapter reuses it unchanged. */ - protected void applyGitToken(Map workerEnv, BridgedConfig.Profile cfg) { + protected void applyGitToken(Map workerEnv, FleetConfig.Profile cfg) { if (!cfg.hasGitToken()) { return; } @@ -860,7 +860,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * herdr's own login-shell process environment (gitea issue #82, superseding CB-592's single * hardcoded {@code GITEA_ACCESS_TOKEN} name — see {@link #applyMemberCredentialPolicy}). herdr * spawns a pane from its own process environment and layers our map on top — - * {@link dev.ltms.bridged.herdr.WorkspaceControl#createTab} and {@code #splitPane} send only + * {@link dev.ltms.fleet.herdr.WorkspaceControl#createTab} and {@code #splitPane} send only * the keys we put in that map, so any key we never mention passes straight through from * herdr's own shell, admin credentials included. * @@ -922,7 +922,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { *

    Adapter-specific variables are layered on top of this by {@code buildLaunch} and therefore * win. That ordering is deliberate and load-bearing: it stops a profile's {@code env:} from * overriding {@code ANTHROPIC_BASE_URL} and slipping past {@link - * dev.ltms.bridged.guard.SubscriptionGuard}, which is checked against the profile's + * dev.ltms.fleet.guard.SubscriptionGuard}, which is checked against the profile's * {@code baseUrl} and nothing else. * *

    The CB-596 credential shadow and the CB-592 marker are put in last, after the @@ -931,7 +931,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * place both are applied: every {@code buildLaunch} in every adapter calls this first, so a new * profile, and a peer kind not yet written, gets them for free. */ - protected Map baseEnv(BridgedConfig.Profile cfg) { + protected Map baseEnv(FleetConfig.Profile cfg) { Map workerEnv = new LinkedHashMap<>(); String path = env.apply("PATH"); if (path != null && !path.isBlank()) { @@ -955,11 +955,11 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * *

    No {@code memberCredentials} configured — the supplier is {@code null}, or it resolves to * one whose {@code known} list is empty — shadows nothing. This is a real, config-driven gap - * (see {@link BridgedConfig.MemberCredentials}'s javadoc), not a safe default: deny-by-default + * (see {@link FleetConfig.MemberCredentials}'s javadoc), not a safe default: deny-by-default * only defends names the operator has actually enumerated in {@code known}. */ private void applyMemberCredentialPolicy(Map workerEnv) { - BridgedConfig.MemberCredentials creds = memberCredentials == null ? null : memberCredentials.get(); + FleetConfig.MemberCredentials creds = memberCredentials == null ? null : memberCredentials.get(); if (creds == null) { return; } @@ -984,7 +984,7 @@ public abstract class HerdrPeerLauncher implements PeerLauncher { * every such NAME, at WARN, at most once per launcher instance — never a value, a prefix of a * value, or a hash of a value, so the log itself cannot leak anything. */ - private void logCredentialGap(BridgedConfig.MemberCredentials creds) { + private void logCredentialGap(FleetConfig.MemberCredentials creds) { Set covered = new HashSet<>(creds.known()); covered.addAll(creds.allow()); List gap = hostEnvNames.get().stream() diff --git a/bridged/src/main/java/dev/ltms/bridged/member/OpenCodeLauncher.java b/bridged/src/main/java/dev/ltms/fleet/member/OpenCodeLauncher.java similarity index 91% rename from bridged/src/main/java/dev/ltms/bridged/member/OpenCodeLauncher.java rename to bridged/src/main/java/dev/ltms/fleet/member/OpenCodeLauncher.java index 5679334..9b760c7 100644 --- a/bridged/src/main/java/dev/ltms/bridged/member/OpenCodeLauncher.java +++ b/bridged/src/main/java/dev/ltms/fleet/member/OpenCodeLauncher.java @@ -1,15 +1,15 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.CharterReceipt; -import dev.ltms.bridged.peer.PeerHandle; -import dev.ltms.bridged.peer.SpawnRequest; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.CharterReceipt; +import dev.ltms.fleet.peer.PeerHandle; +import dev.ltms.fleet.peer.SpawnRequest; import java.io.IOException; import java.io.UncheckedIOException; @@ -33,7 +33,7 @@ import java.util.function.Supplier; *

    The divergences from {@link ClaudeCodeLauncher}, all confined to {@link #buildLaunch}: *

      *
    • No subscription boundary. opencode carries no {@code ANTHROPIC_BASE_URL} - * and there is no {@link dev.ltms.bridged.guard.SubscriptionGuard} — the guard is a + * and there is no {@link dev.ltms.fleet.guard.SubscriptionGuard} — the guard is a * Claude-private concern, not part of the SPI. opencode reads the operator's own provider * credentials from its global {@code auth.json}; the bridge injects none.
    • *
    • File-based MCP mount + instructions. opencode has no inline @@ -70,7 +70,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * matches the legacy non-blocking spawn semantics. Config dirs are created under the JVM temp dir. */ public OpenCodeLauncher(AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env) { this(agents, spaces, profiles, defaultProfile, env, 0, System::currentTimeMillis, () -> sleepUninterruptibly(300), @@ -82,7 +82,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * the pane reports an injectable state or {@code spawnReadyTimeoutMs} elapses. */ public OpenCodeLauncher(AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, long spawnReadyPollMs) { this(agents, spaces, profiles, defaultProfile, env, @@ -95,10 +95,10 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * role; a profile may still override it with its own {@code tabLabel}. */ public OpenCodeLauncher(AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, long spawnReadyPollMs, - Supplier fleet) { + Supplier fleet) { this(agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, System::currentTimeMillis, () -> sleepUninterruptibly(spawnReadyPollMs), defaultConfigRoot(), defaultDiscoveryRoot(), fleet); @@ -108,11 +108,11 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * Production constructor, plus the CB-596 {@code memberCredentials} policy supplier. */ public OpenCodeLauncher(AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, long spawnReadyPollMs, - Supplier fleet, - Supplier memberCredentials) { + Supplier fleet, + Supplier memberCredentials) { this(agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, System::currentTimeMillis, () -> sleepUninterruptibly(spawnReadyPollMs), defaultConfigRoot(), defaultDiscoveryRoot(), fleet, memberCredentials); @@ -138,7 +138,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * {@link OpenCodeSessionDiscovery}) */ public OpenCodeLauncher(AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, @@ -153,12 +153,12 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * @param fleet live fleet config, read once for each spawn */ public OpenCodeLauncher(AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, Path configRoot, Path discoveryRoot, - Supplier fleet) { + Supplier fleet) { super(NAME_PREFIX, agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, nowMillis, sleeper, fleet); this.configRoot = configRoot; @@ -169,13 +169,13 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * Full testability constructor, plus the CB-596 {@code memberCredentials} policy supplier. */ public OpenCodeLauncher(AgentControl agents, WorkspaceControl spaces, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Function env, long spawnReadyTimeoutMs, LongSupplier nowMillis, Runnable sleeper, Path configRoot, Path discoveryRoot, - Supplier fleet, - Supplier memberCredentials) { + Supplier fleet, + Supplier memberCredentials) { super(NAME_PREFIX, agents, spaces, profiles, defaultProfile, env, spawnReadyTimeoutMs, nowMillis, sleeper, fleet, memberCredentials); this.configRoot = configRoot; @@ -201,7 +201,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * grant; and select the model with {@code -m}. */ @Override - protected Launch buildLaunch(BridgedConfig.Profile cfg, LaunchSpec spec) { + protected Launch buildLaunch(FleetConfig.Profile cfg, LaunchSpec spec) { Map workerEnv = baseEnv(cfg); // A config file is needed for the bridge MCP mount, a member charter, or a pinned endpoint (CB-508). if (cfg.hasMcp() || spec.charter() != null || hasCustomProvider(cfg)) { @@ -238,7 +238,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * primary's Anthropic subscription, and an opencode process has no Anthropic credential path * at all. Pointing it at a local vLLM cannot leak the subscription. */ - private static boolean hasCustomProvider(BridgedConfig.Profile cfg) { + private static boolean hasCustomProvider(FleetConfig.Profile cfg) { return cfg.baseUrl() != null && !cfg.baseUrl().isBlank(); } @@ -252,7 +252,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * own git worktree on its own branch, is off-subscription, and cannot merge — the lead is the * gate. */ - private List argvWithAuto(BridgedConfig.Profile cfg) { + private List argvWithAuto(FleetConfig.Profile cfg) { List argv = mutableArgv(cfg.argv()); argv.add("--auto"); return argv; @@ -275,7 +275,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { } /** The launch argv plus, when a model is configured, the opencode {@code -m provider/model} flag. */ - private List argvWithModel(List argv, BridgedConfig.Profile cfg) { + private List argvWithModel(List argv, FleetConfig.Profile cfg) { if (cfg.model() != null && !cfg.model().isBlank()) { argv.add("-m"); argv.add(cfg.model()); @@ -289,7 +289,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * {@code OPENCODE_CONFIG}. The dir is unique per spawn so concurrent workers never race on it; * it is best-effort cleaned on JVM exit (worker config is disposable — regenerated every spawn). */ - private Path writeConfig(BridgedConfig.Profile cfg, String charterText) { + private Path writeConfig(FleetConfig.Profile cfg, String charterText) { try { Path dir = Files.createTempDirectory(configRoot, "bridged-opencode-"); dir.toFile().deleteOnExit(); @@ -349,7 +349,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { *

      The provider id comes from the {@code provider/model} selector in {@code model:}, so one * field drives both the declaration and the {@code -m} flag and they cannot drift apart. */ - private void addCustomProvider(ObjectNode root, BridgedConfig.Profile cfg) { + private void addCustomProvider(ObjectNode root, FleetConfig.Profile cfg) { String[] parts = splitModelSelector(cfg); String providerId = parts[0]; String modelId = parts[1]; @@ -372,7 +372,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { * needs both, so a bare model name is rejected loudly rather than silently falling back to the * default gateway — a worker quietly talking to the wrong endpoint is the failure this avoids. */ - private static String[] splitModelSelector(BridgedConfig.Profile cfg) { + private static String[] splitModelSelector(FleetConfig.Profile cfg) { String model = cfg.model(); int slash = model == null ? -1 : model.indexOf('/'); if (model == null || model.isBlank() || slash <= 0 || slash == model.length() - 1) { @@ -496,7 +496,7 @@ public final class OpenCodeLauncher extends HerdrPeerLauncher { /** Whether any configured profile opts into a git-forge token (required for {@link Capability#SELF_PR}). */ private boolean hasGitTokenProfile() { - return profileConfigs().stream().anyMatch(BridgedConfig.Profile::hasGitToken); + return profileConfigs().stream().anyMatch(FleetConfig.Profile::hasGitToken); } // --- CB-117 reap predicate (opencode prefix), kept for direct unit testing ----------------- diff --git a/bridged/src/main/java/dev/ltms/bridged/member/OpenCodeSessionDiscovery.java b/bridged/src/main/java/dev/ltms/fleet/member/OpenCodeSessionDiscovery.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/member/OpenCodeSessionDiscovery.java rename to bridged/src/main/java/dev/ltms/fleet/member/OpenCodeSessionDiscovery.java index 52321df..ba38179 100644 --- a/bridged/src/main/java/dev/ltms/bridged/member/OpenCodeSessionDiscovery.java +++ b/bridged/src/main/java/dev/ltms/fleet/member/OpenCodeSessionDiscovery.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/bridged/src/main/java/dev/ltms/bridged/metrics/BridgedMetrics.java b/bridged/src/main/java/dev/ltms/fleet/metrics/FleetMetrics.java similarity index 95% rename from bridged/src/main/java/dev/ltms/bridged/metrics/BridgedMetrics.java rename to bridged/src/main/java/dev/ltms/fleet/metrics/FleetMetrics.java index 1691d0a..f6ad8f4 100644 --- a/bridged/src/main/java/dev/ltms/bridged/metrics/BridgedMetrics.java +++ b/bridged/src/main/java/dev/ltms/fleet/metrics/FleetMetrics.java @@ -1,8 +1,8 @@ -package dev.ltms.bridged.metrics; +package dev.ltms.fleet.metrics; -import dev.ltms.bridged.msg.ReplyInbox; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.session.MemberSession; +import dev.ltms.fleet.msg.ReplyInbox; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.session.MemberSession; import java.util.LinkedHashMap; import java.util.Map; @@ -18,7 +18,7 @@ import java.util.Map; * {@code bridged_push_nudges_total{outcome="exhausted"}}, which means the primary stopped draining * its inbox and CB-307's active push gave up. */ -public final class BridgedMetrics { +public final class FleetMetrics { /** Counter: delegated sends by terminal outcome. */ public static final String SENDS = "bridged_sends_total"; @@ -39,7 +39,7 @@ public final class BridgedMetrics { /** Gauge: undrained replies held per target. */ public static final String INBOX_DEPTH = "bridged_inbox_depth"; - private BridgedMetrics() { + private FleetMetrics() { } /** diff --git a/bridged/src/main/java/dev/ltms/bridged/metrics/Metrics.java b/bridged/src/main/java/dev/ltms/fleet/metrics/Metrics.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/metrics/Metrics.java rename to bridged/src/main/java/dev/ltms/fleet/metrics/Metrics.java index 78552bb..336f709 100644 --- a/bridged/src/main/java/dev/ltms/bridged/metrics/Metrics.java +++ b/bridged/src/main/java/dev/ltms/fleet/metrics/Metrics.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.metrics; +package dev.ltms.fleet.metrics; import java.util.Map; import java.util.NavigableMap; diff --git a/bridged/src/main/java/dev/ltms/bridged/msg/AmqpReplyInbox.java b/bridged/src/main/java/dev/ltms/fleet/msg/AmqpReplyInbox.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/msg/AmqpReplyInbox.java rename to bridged/src/main/java/dev/ltms/fleet/msg/AmqpReplyInbox.java index 5f5846d..ffd549a 100644 --- a/bridged/src/main/java/dev/ltms/bridged/msg/AmqpReplyInbox.java +++ b/bridged/src/main/java/dev/ltms/fleet/msg/AmqpReplyInbox.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/bridged/src/main/java/dev/ltms/bridged/msg/InMemoryReplyInbox.java b/bridged/src/main/java/dev/ltms/fleet/msg/InMemoryReplyInbox.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/msg/InMemoryReplyInbox.java rename to bridged/src/main/java/dev/ltms/fleet/msg/InMemoryReplyInbox.java index c1b73ec..2506473 100644 --- a/bridged/src/main/java/dev/ltms/bridged/msg/InMemoryReplyInbox.java +++ b/bridged/src/main/java/dev/ltms/fleet/msg/InMemoryReplyInbox.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import java.util.LinkedHashMap; import java.util.List; diff --git a/bridged/src/main/java/dev/ltms/bridged/msg/LeadHeartbeatLoop.java b/bridged/src/main/java/dev/ltms/fleet/msg/LeadHeartbeatLoop.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/msg/LeadHeartbeatLoop.java rename to bridged/src/main/java/dev/ltms/fleet/msg/LeadHeartbeatLoop.java index 1e7d0af..0e35667 100644 --- a/bridged/src/main/java/dev/ltms/bridged/msg/LeadHeartbeatLoop.java +++ b/bridged/src/main/java/dev/ltms/fleet/msg/LeadHeartbeatLoop.java @@ -1,11 +1,11 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.mcp.PrimaryRegistry; -import dev.ltms.bridged.metrics.BridgedMetrics; -import dev.ltms.bridged.metrics.Metrics; -import dev.ltms.bridged.session.MemberSession; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.mcp.PrimaryRegistry; +import dev.ltms.fleet.metrics.FleetMetrics; +import dev.ltms.fleet.metrics.Metrics; +import dev.ltms.fleet.session.MemberSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -99,7 +99,7 @@ public final class LeadHeartbeatLoop { /** Count one nudge outcome when a registry is wired; a no-op in unit tests. */ private void countNudge(String outcome) { if (metrics != null) { - metrics.inc(BridgedMetrics.HEARTBEAT_NUDGES, "outcome", outcome); + metrics.inc(FleetMetrics.HEARTBEAT_NUDGES, "outcome", outcome); } } diff --git a/bridged/src/main/java/dev/ltms/bridged/msg/MessageService.java b/bridged/src/main/java/dev/ltms/fleet/msg/MessageService.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/msg/MessageService.java rename to bridged/src/main/java/dev/ltms/fleet/msg/MessageService.java index 0b3d028..1b024fc 100644 --- a/bridged/src/main/java/dev/ltms/bridged/msg/MessageService.java +++ b/bridged/src/main/java/dev/ltms/fleet/msg/MessageService.java @@ -1,10 +1,10 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.inject.Injector; -import dev.ltms.bridged.metrics.BridgedMetrics; -import dev.ltms.bridged.metrics.Metrics; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.inject.Injector; +import dev.ltms.fleet.metrics.FleetMetrics; +import dev.ltms.fleet.metrics.Metrics; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -284,13 +284,13 @@ public final class MessageService { */ public boolean reply(String session, String content) { if (rendezvous.resolve(session, content)) { - count(BridgedMetrics.REPLIES, "path", "rendezvous"); + count(FleetMetrics.REPLIES, "path", "rendezvous"); return true; // a live send took it — unchanged fast path } inbox.publish(session, UUID.randomUUID().toString(), content); // A rising inbox share is the signal CB-307 exists to make visible: the worker finished but // nobody was waiting, so delivery now depends on the push loop and a drain. - count(BridgedMetrics.REPLIES, "path", "inbox"); + count(FleetMetrics.REPLIES, "path", "inbox"); if (pushLoop != null) { pushLoop.onReplyQueued(session); } @@ -308,7 +308,7 @@ public final class MessageService { private Reply recorded(Reply r) { String label = sendOutcomeLabel(r.outcome()); if (label != null) { - count(BridgedMetrics.SENDS, "outcome", label); + count(FleetMetrics.SENDS, "outcome", label); } return r; } @@ -512,7 +512,7 @@ public final class MessageService { // CB-582: the question just became visible via fleet_poll (Phase.ASKING) for an async // (wait:false) delegation — nudge the lead's own pane the same way a terminal ticket does // (CB-588), since the lead's normal poll cadence is minutes away and the reverse-rendezvous - // window (~55s, see BridgeMcp/BridgedApp) is far shorter. A blocking (wait:true) send has + // window (~55s, see FleetMcp/FleetApp) is far shorter. A blocking (wait:true) send has // no Task and gets the question directly in its own reply, so task == null there — nothing // to nudge. if (task != null && pushLoop != null) { diff --git a/bridged/src/main/java/dev/ltms/bridged/msg/Rendezvous.java b/bridged/src/main/java/dev/ltms/fleet/msg/Rendezvous.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/msg/Rendezvous.java rename to bridged/src/main/java/dev/ltms/fleet/msg/Rendezvous.java index 3e82de0..12e53dd 100644 --- a/bridged/src/main/java/dev/ltms/bridged/msg/Rendezvous.java +++ b/bridged/src/main/java/dev/ltms/fleet/msg/Rendezvous.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; diff --git a/bridged/src/main/java/dev/ltms/bridged/msg/ReplyInbox.java b/bridged/src/main/java/dev/ltms/fleet/msg/ReplyInbox.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/msg/ReplyInbox.java rename to bridged/src/main/java/dev/ltms/fleet/msg/ReplyInbox.java index 98c9b19..38ce4b9 100644 --- a/bridged/src/main/java/dev/ltms/bridged/msg/ReplyInbox.java +++ b/bridged/src/main/java/dev/ltms/fleet/msg/ReplyInbox.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import java.util.List; diff --git a/bridged/src/main/java/dev/ltms/bridged/msg/ReplyPushLoop.java b/bridged/src/main/java/dev/ltms/fleet/msg/ReplyPushLoop.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/msg/ReplyPushLoop.java rename to bridged/src/main/java/dev/ltms/fleet/msg/ReplyPushLoop.java index 29b8d90..480751f 100644 --- a/bridged/src/main/java/dev/ltms/bridged/msg/ReplyPushLoop.java +++ b/bridged/src/main/java/dev/ltms/fleet/msg/ReplyPushLoop.java @@ -1,10 +1,10 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.mcp.PrimaryRegistry; -import dev.ltms.bridged.metrics.BridgedMetrics; -import dev.ltms.bridged.metrics.Metrics; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.mcp.PrimaryRegistry; +import dev.ltms.fleet.metrics.FleetMetrics; +import dev.ltms.fleet.metrics.Metrics; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -118,7 +118,7 @@ public final class ReplyPushLoop { /** Count one nudge outcome when a registry is wired; a no-op in unit tests. */ private void countNudge(String outcome) { if (metrics != null) { - metrics.inc(BridgedMetrics.PUSH_NUDGES, "outcome", outcome); + metrics.inc(FleetMetrics.PUSH_NUDGES, "outcome", outcome); } } @@ -364,7 +364,7 @@ public final class ReplyPushLoop { /** * Called when an async ticket's worker pauses mid-turn in {@code fleet_ask} (CB-582): the * question is now visible via {@code fleet_poll} (Phase.ASKING), but the reverse-rendezvous - * window it opened with (~55s default, see {@code BridgeMcp}/{@code BridgedApp}) is far shorter + * window it opened with (~55s default, see {@code FleetMcp}/{@code FleetApp}) is far shorter * than a lead's normal minutes-long poll cadence — exactly the gap this closes. Resolves the * delegating lead the same way {@link #onTicketTerminal} does and coalesces onto the same * per-lead schedule (CB-590). diff --git a/bridged/src/main/java/dev/ltms/bridged/msg/TurnToken.java b/bridged/src/main/java/dev/ltms/fleet/msg/TurnToken.java similarity index 95% rename from bridged/src/main/java/dev/ltms/bridged/msg/TurnToken.java rename to bridged/src/main/java/dev/ltms/fleet/msg/TurnToken.java index f3f8c2e..bd1d839 100644 --- a/bridged/src/main/java/dev/ltms/bridged/msg/TurnToken.java +++ b/bridged/src/main/java/dev/ltms/fleet/msg/TurnToken.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import java.util.concurrent.CompletableFuture; diff --git a/bridged/src/main/java/dev/ltms/bridged/peer/Capability.java b/bridged/src/main/java/dev/ltms/fleet/peer/Capability.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/peer/Capability.java rename to bridged/src/main/java/dev/ltms/fleet/peer/Capability.java index 6c3882c..532586f 100644 --- a/bridged/src/main/java/dev/ltms/bridged/peer/Capability.java +++ b/bridged/src/main/java/dev/ltms/fleet/peer/Capability.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; /** * Declared capabilities of a {@link PeerLauncher}. The protocol is the union across all diff --git a/bridged/src/main/java/dev/ltms/bridged/peer/CharterReceipt.java b/bridged/src/main/java/dev/ltms/fleet/peer/CharterReceipt.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/peer/CharterReceipt.java rename to bridged/src/main/java/dev/ltms/fleet/peer/CharterReceipt.java index 79bf78b..5d48833 100644 --- a/bridged/src/main/java/dev/ltms/bridged/peer/CharterReceipt.java +++ b/bridged/src/main/java/dev/ltms/fleet/peer/CharterReceipt.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; diff --git a/bridged/src/main/java/dev/ltms/bridged/peer/MemberRole.java b/bridged/src/main/java/dev/ltms/fleet/peer/MemberRole.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/peer/MemberRole.java rename to bridged/src/main/java/dev/ltms/fleet/peer/MemberRole.java index ebf902f..4985799 100644 --- a/bridged/src/main/java/dev/ltms/bridged/peer/MemberRole.java +++ b/bridged/src/main/java/dev/ltms/fleet/peer/MemberRole.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; import java.util.Locale; diff --git a/bridged/src/main/java/dev/ltms/bridged/peer/PeerHandle.java b/bridged/src/main/java/dev/ltms/fleet/peer/PeerHandle.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/peer/PeerHandle.java rename to bridged/src/main/java/dev/ltms/fleet/peer/PeerHandle.java index ad7d3f0..7e28b5b 100644 --- a/bridged/src/main/java/dev/ltms/bridged/peer/PeerHandle.java +++ b/bridged/src/main/java/dev/ltms/fleet/peer/PeerHandle.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; /** * An opaque handle returned by {@link PeerLauncher#spawn(SpawnRequest)}. The core routes on diff --git a/bridged/src/main/java/dev/ltms/bridged/peer/PeerLauncher.java b/bridged/src/main/java/dev/ltms/fleet/peer/PeerLauncher.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/peer/PeerLauncher.java rename to bridged/src/main/java/dev/ltms/fleet/peer/PeerLauncher.java index 1bfd1cd..e3ef717 100644 --- a/bridged/src/main/java/dev/ltms/bridged/peer/PeerLauncher.java +++ b/bridged/src/main/java/dev/ltms/fleet/peer/PeerLauncher.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; import java.util.List; import java.util.Set; @@ -13,7 +13,7 @@ import java.util.Set; * and naming conventions are all adapter-private — the core sees only the returned * {@link PeerHandle} whose {@code id()} is the registry/routing key. * - *

      The interface is a superset of what {@code SessionManager} and {@code Bridged.main} call + *

      The interface is a superset of what {@code SessionManager} and {@code Fleetd.main} call * on the concrete launcher today. */ public interface PeerLauncher { diff --git a/bridged/src/main/java/dev/ltms/bridged/peer/PeerUnreachableException.java b/bridged/src/main/java/dev/ltms/fleet/peer/PeerUnreachableException.java similarity index 95% rename from bridged/src/main/java/dev/ltms/bridged/peer/PeerUnreachableException.java rename to bridged/src/main/java/dev/ltms/fleet/peer/PeerUnreachableException.java index fad0ec1..5455e13 100644 --- a/bridged/src/main/java/dev/ltms/bridged/peer/PeerUnreachableException.java +++ b/bridged/src/main/java/dev/ltms/fleet/peer/PeerUnreachableException.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; /** * Thrown when a {@link PeerLauncher} starts a peer process but the peer diff --git a/bridged/src/main/java/dev/ltms/bridged/peer/SpawnRequest.java b/bridged/src/main/java/dev/ltms/fleet/peer/SpawnRequest.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/peer/SpawnRequest.java rename to bridged/src/main/java/dev/ltms/fleet/peer/SpawnRequest.java index 4cb60b8..00f0ffd 100644 --- a/bridged/src/main/java/dev/ltms/bridged/peer/SpawnRequest.java +++ b/bridged/src/main/java/dev/ltms/fleet/peer/SpawnRequest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; /** * What a caller asks for when spawning a peer. diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/BackendQuarantine.java b/bridged/src/main/java/dev/ltms/fleet/placement/BackendQuarantine.java similarity index 95% rename from bridged/src/main/java/dev/ltms/bridged/placement/BackendQuarantine.java rename to bridged/src/main/java/dev/ltms/fleet/placement/BackendQuarantine.java index abdb95d..3fb437a 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/BackendQuarantine.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/BackendQuarantine.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; import java.util.LinkedHashMap; import java.util.Map; @@ -8,7 +8,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.LongSupplier; /** - * Where a credential (not a profile — see {@code BridgedConfig.Profile#effectiveCredentialId()}) + * Where a credential (not a profile — see {@code FleetConfig.Profile#effectiveCredentialId()}) * sits out a cooldown after a {@code BACKEND_EXHAUSTED} classification (CB-578 stage B), so a fresh * spawn does not walk straight back onto the account that just refused on a usage limit. * @@ -16,7 +16,7 @@ import java.util.function.LongSupplier; * models on the same OpenAI account) share one quarantine — {@link #quarantine} one credential id * and every profile whose {@code effectiveCredentialId()} equals it is quarantined too, without this * class knowing anything about profiles at all. That mapping is the caller's job (see - * {@code CompositePeerLauncher} and {@code dev.ltms.bridged.inject.ExhaustionSink}). + * {@code CompositePeerLauncher} and {@code dev.ltms.fleet.inject.ExhaustionSink}). * *

      The clock is injected ({@link LongSupplier}, conventionally {@code System::nanoTime} like * {@code FleetHealthMonitor}), never read inline, so a quarantine's expiry is testable without a diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/FixedPlacementPolicy.java b/bridged/src/main/java/dev/ltms/fleet/placement/FixedPlacementPolicy.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/placement/FixedPlacementPolicy.java rename to bridged/src/main/java/dev/ltms/fleet/placement/FixedPlacementPolicy.java index 713e1f6..121463c 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/FixedPlacementPolicy.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/FixedPlacementPolicy.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; /** * Backward-compatible placement: an unqualified spawn always resolves to the configured default diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementCandidate.java b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementCandidate.java similarity index 91% rename from bridged/src/main/java/dev/ltms/bridged/placement/PlacementCandidate.java rename to bridged/src/main/java/dev/ltms/fleet/placement/PlacementCandidate.java index d213fb3..9c49f2e 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementCandidate.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementCandidate.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; /** * A profile (and, in CB-308, a host) that can be chosen by a {@link PlacementPolicy}. @@ -21,7 +21,7 @@ public record PlacementCandidate(String profile, String host, float weight, Inte /** * True when this candidate carries an explicit {@code weight <= 0} (CB-554) and must be * skipped by every automatic policy — the same way a quarantined or unreachable candidate is - * skipped. {@code BridgedConfig.Profile}'s compact constructor already normalises "absent" to + * skipped. {@code FleetConfig.Profile}'s compact constructor already normalises "absent" to * {@code 1.0} and "negative" to {@code 0.0}, so this is a plain threshold check here; it does * not need to distinguish "explicit 0" from "absent" itself. * diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementContext.java b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementContext.java similarity index 96% rename from bridged/src/main/java/dev/ltms/bridged/placement/PlacementContext.java rename to bridged/src/main/java/dev/ltms/fleet/placement/PlacementContext.java index ad73c16..0d83314 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementContext.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementContext.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; import java.util.List; import java.util.Set; diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementException.java b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementException.java similarity index 90% rename from bridged/src/main/java/dev/ltms/bridged/placement/PlacementException.java rename to bridged/src/main/java/dev/ltms/fleet/placement/PlacementException.java index 9afdff3..399d1fe 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementException.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementException.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; /** * Thrown when a {@link PlacementPolicy} has no candidate available. Kept as a distinct type so diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicies.java b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicies.java similarity index 96% rename from bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicies.java rename to bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicies.java index a339602..b9a1d76 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicies.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicies.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; /** * Factory for the built-in placement policies. diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicy.java b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicy.java similarity index 93% rename from bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicy.java rename to bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicy.java index 8d8de1d..ced0f5d 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicy.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicy.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; /** * How {@code bridged} chooses a worker profile when a spawn names none. Implementations are diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicyUtil.java b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicyUtil.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicyUtil.java rename to bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicyUtil.java index 65a99a3..f402479 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/PlacementPolicyUtil.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/PlacementPolicyUtil.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; import java.util.ArrayList; import java.util.List; diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/RoundRobinPlacementPolicy.java b/bridged/src/main/java/dev/ltms/fleet/placement/RoundRobinPlacementPolicy.java similarity index 95% rename from bridged/src/main/java/dev/ltms/bridged/placement/RoundRobinPlacementPolicy.java rename to bridged/src/main/java/dev/ltms/fleet/placement/RoundRobinPlacementPolicy.java index c76115f..a577a15 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/RoundRobinPlacementPolicy.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/RoundRobinPlacementPolicy.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; diff --git a/bridged/src/main/java/dev/ltms/bridged/placement/WeightedRoundRobinPolicy.java b/bridged/src/main/java/dev/ltms/fleet/placement/WeightedRoundRobinPolicy.java similarity index 98% rename from bridged/src/main/java/dev/ltms/bridged/placement/WeightedRoundRobinPolicy.java rename to bridged/src/main/java/dev/ltms/fleet/placement/WeightedRoundRobinPolicy.java index c97ca7b..e1c4735 100644 --- a/bridged/src/main/java/dev/ltms/bridged/placement/WeightedRoundRobinPolicy.java +++ b/bridged/src/main/java/dev/ltms/fleet/placement/WeightedRoundRobinPolicy.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; import java.util.List; import java.util.Map; diff --git a/bridged/src/main/java/dev/ltms/bridged/rest/BridgedApp.java b/bridged/src/main/java/dev/ltms/fleet/rest/FleetApp.java similarity index 96% rename from bridged/src/main/java/dev/ltms/bridged/rest/BridgedApp.java rename to bridged/src/main/java/dev/ltms/fleet/rest/FleetApp.java index 342f8dc..ba78fc8 100644 --- a/bridged/src/main/java/dev/ltms/bridged/rest/BridgedApp.java +++ b/bridged/src/main/java/dev/ltms/fleet/rest/FleetApp.java @@ -1,25 +1,25 @@ -package dev.ltms.bridged.rest; +package dev.ltms.fleet.rest; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import dev.ltms.bridged.auth.AuditLog; -import dev.ltms.bridged.auth.Authz; -import dev.ltms.bridged.auth.CallerResolver; -import dev.ltms.bridged.auth.Principal; -import dev.ltms.bridged.guard.GuardException; -import dev.ltms.bridged.metrics.Metrics; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.herdr.HerdrClient; -import dev.ltms.bridged.herdr.HerdrException; -import dev.ltms.bridged.inject.MemberPresence; -import dev.ltms.bridged.peer.PeerUnreachableException; -import dev.ltms.bridged.placement.PlacementException; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.session.MemberSession; -import dev.ltms.bridged.session.WorktreeRequest; -import dev.ltms.bridged.peer.PeerLauncher; +import dev.ltms.fleet.auth.AuditLog; +import dev.ltms.fleet.auth.Authz; +import dev.ltms.fleet.auth.CallerResolver; +import dev.ltms.fleet.auth.Principal; +import dev.ltms.fleet.guard.GuardException; +import dev.ltms.fleet.metrics.Metrics; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.herdr.HerdrClient; +import dev.ltms.fleet.herdr.HerdrException; +import dev.ltms.fleet.inject.MemberPresence; +import dev.ltms.fleet.peer.PeerUnreachableException; +import dev.ltms.fleet.placement.PlacementException; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.session.MemberSession; +import dev.ltms.fleet.session.WorktreeRequest; +import dev.ltms.fleet.peer.PeerLauncher; import io.javalin.Javalin; import io.javalin.http.Context; import jakarta.servlet.http.HttpServlet; @@ -41,7 +41,7 @@ import java.util.stream.Collectors; *

      Built from injected collaborators so tests supply fakes and run on an ephemeral * port; {@code main} supplies the real Unix-socket client and worker service. */ -public final class BridgedApp { +public final class FleetApp { /** Default blocking window for a message; kept under typical HTTP idle timeouts. */ private static final long DEFAULT_MESSAGE_TIMEOUT_MS = 25_000; @@ -68,7 +68,7 @@ public final class BridgedApp { * behaved before CB-501. Retained so existing acceptance tests keep exercising handler * behaviour without each needing an auth fixture. */ - public BridgedApp(HerdrClient herdr, PeerLauncher workers, SessionManager sessions, + public FleetApp(HerdrClient herdr, PeerLauncher workers, SessionManager sessions, MessageService messages, MemberPresence presence, HttpServlet mcpServlet) { this(herdr, workers, sessions, messages, presence, mcpServlet, null, null); @@ -80,7 +80,7 @@ public final class BridgedApp { * @param metrics registry to instrument and expose at {@code GET /metrics}; {@code null} omits * the endpoint */ - public BridgedApp(HerdrClient herdr, PeerLauncher workers, SessionManager sessions, + public FleetApp(HerdrClient herdr, PeerLauncher workers, SessionManager sessions, MessageService messages, MemberPresence presence, HttpServlet mcpServlet, CallerResolver auth, Metrics metrics) { this.herdr = herdr; @@ -104,7 +104,7 @@ public final class BridgedApp { } }); // CB-501: resolve identity once per request, before any handler. /mcp does NOT pass through - // here — it is a raw servlet on Jetty's context handler — so BridgeMcp enforces separately + // here — it is a raw servlet on Jetty's context handler — so FleetMcp enforces separately // against the same CallerResolver. Any check that lives in only one place is not a control. if (auth != null) { app.before(ctx -> ctx.attribute(CALLER, @@ -219,7 +219,7 @@ public final class BridgedApp { return; } ctx.status(200).json(Map.of("agents", - workers.list().stream().map(Agent.class::cast).map(BridgedApp::view).toList())); + workers.list().stream().map(Agent.class::cast).map(FleetApp::view).toList())); } /** CB-304: bridge-owned roster merged with live herdr status by paneId. */ diff --git a/bridged/src/main/java/dev/ltms/bridged/session/GitWorktrees.java b/bridged/src/main/java/dev/ltms/fleet/session/GitWorktrees.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/session/GitWorktrees.java rename to bridged/src/main/java/dev/ltms/fleet/session/GitWorktrees.java index 37f6ce5..990534a 100644 --- a/bridged/src/main/java/dev/ltms/bridged/session/GitWorktrees.java +++ b/bridged/src/main/java/dev/ltms/fleet/session/GitWorktrees.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bridged/src/main/java/dev/ltms/bridged/session/MemberSession.java b/bridged/src/main/java/dev/ltms/fleet/session/MemberSession.java similarity index 95% rename from bridged/src/main/java/dev/ltms/bridged/session/MemberSession.java rename to bridged/src/main/java/dev/ltms/fleet/session/MemberSession.java index d7c7c13..1c16201 100644 --- a/bridged/src/main/java/dev/ltms/bridged/session/MemberSession.java +++ b/bridged/src/main/java/dev/ltms/fleet/session/MemberSession.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; -import dev.ltms.bridged.peer.CharterReceipt; -import dev.ltms.bridged.peer.MemberRole; +import dev.ltms.fleet.peer.CharterReceipt; +import dev.ltms.fleet.peer.MemberRole; /** * A bridge-owned worker session — the authoritative in-daemon record of a worker this @@ -10,7 +10,7 @@ import dev.ltms.bridged.peer.MemberRole; * * @param paneId the host-unique opaque id (CB-519) — the registry key and the argument to * teardown. Despite the historical name this is the {@link - * dev.ltms.bridged.peer.PeerHandle#id()}, a UUID, and is distinct from the + * dev.ltms.fleet.peer.PeerHandle#id()}, a UUID, and is distinct from the * launcher-private herdr pane coordinate. * @param terminalId herdr terminal handle — the {@code target} for send/read/status * @param profile the profile name that spawned this session — WHICH BACKEND diff --git a/bridged/src/main/java/dev/ltms/bridged/session/SessionManager.java b/bridged/src/main/java/dev/ltms/fleet/session/SessionManager.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/session/SessionManager.java rename to bridged/src/main/java/dev/ltms/fleet/session/SessionManager.java index d273912..a69c424 100644 --- a/bridged/src/main/java/dev/ltms/bridged/session/SessionManager.java +++ b/bridged/src/main/java/dev/ltms/fleet/session/SessionManager.java @@ -1,15 +1,15 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; -import dev.ltms.bridged.auth.MemberLifecycle; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.inject.TurnListener; -import dev.ltms.bridged.inject.MemberPresence; -import dev.ltms.bridged.msg.TurnToken; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.PeerHandle; -import dev.ltms.bridged.peer.PeerLauncher; -import dev.ltms.bridged.peer.SpawnRequest; +import dev.ltms.fleet.auth.MemberLifecycle; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.inject.TurnListener; +import dev.ltms.fleet.inject.MemberPresence; +import dev.ltms.fleet.msg.TurnToken; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.PeerHandle; +import dev.ltms.fleet.peer.PeerLauncher; +import dev.ltms.fleet.peer.SpawnRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -96,7 +96,7 @@ public final class SessionManager implements TurnListener { int contextCap, boolean clearAfterTurn) { this.launcher = launcher; this.worktrees = worktrees; - this.presence = new PresenceBridge(this); + this.presence = new PresenceFleet(this); this.nowNanos = nowNanos; this.contextCap = contextCap; this.clearAfterTurn = clearAfterTurn; @@ -105,7 +105,7 @@ public final class SessionManager implements TurnListener { /** * The single {@link MemberPresence} view of this manager: it records availability and forwards * the signal to the {@code SPAWNING → READY} transition. Pass this to the {@code Injector} and - * {@code BridgeMcp} where they previously accepted a plain {@link MemberPresence}. The same + * {@code FleetMcp} where they previously accepted a plain {@link MemberPresence}. The same * instance is returned every call — presence is shared state, so a fresh bridge per call would * fragment the {@code present} set and lose signals across callers. */ @@ -540,7 +540,7 @@ public final class SessionManager implements TurnListener { return Optional.ofNullable(registry.get(paneId)); } - /** Bridge-owned roster: all registered sessions (acquired minus released). */ + /** Fleet-owned roster: all registered sessions (acquired minus released). */ public List roster() { return List.copyOf(registry.values()); } @@ -781,9 +781,9 @@ public final class SessionManager implements TurnListener { * *

      A null {@code terminalId} is a normal input, not a caller bug: every lifecycle hook here is * fed from the MCP transport, where the primary resolves to a {@link - * dev.ltms.bridged.auth.Principal} with no terminal. {@code BridgeMcp} documents that contact as - * a no-op, and {@link dev.ltms.bridged.inject.MemberPresence#markPresent} honours it — but - * {@code PresenceBridge} then forwards the same null here. Matching on a null id can never + * dev.ltms.fleet.auth.Principal} with no terminal. {@code FleetMcp} documents that contact as + * a no-op, and {@link dev.ltms.fleet.inject.MemberPresence#markPresent} honours it — but + * {@code PresenceFleet} then forwards the same null here. Matching on a null id can never * succeed anyway (a registered session always has a terminal), so answer "no match" rather than * throwing: an NPE on this path takes down an unrelated tool call for the primary. */ @@ -811,10 +811,10 @@ public final class SessionManager implements TurnListener { } /** MemberPresence bridge that also drives the manager's READY transition. */ - private static final class PresenceBridge extends MemberPresence { + private static final class PresenceFleet extends MemberPresence { private final SessionManager sessions; - PresenceBridge(SessionManager sessions) { + PresenceFleet(SessionManager sessions) { this.sessions = sessions; } diff --git a/bridged/src/main/java/dev/ltms/bridged/session/SessionReaper.java b/bridged/src/main/java/dev/ltms/fleet/session/SessionReaper.java similarity index 97% rename from bridged/src/main/java/dev/ltms/bridged/session/SessionReaper.java rename to bridged/src/main/java/dev/ltms/fleet/session/SessionReaper.java index 5d66713..69687a0 100644 --- a/bridged/src/main/java/dev/ltms/bridged/session/SessionReaper.java +++ b/bridged/src/main/java/dev/ltms/fleet/session/SessionReaper.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -7,7 +7,7 @@ import java.util.concurrent.TimeUnit; /** * Periodic virtual-thread reaper that tears down {@code READY}/{@code DONE} sessions which have - * exceeded their idle TTL. Modeled on {@link dev.ltms.bridged.inject.StatusPoller}: a single + * exceeded their idle TTL. Modeled on {@link dev.ltms.fleet.inject.StatusPoller}: a single * virtual-thread loop, idempotent start/stop, and no {@code ScheduledExecutorService}. */ public final class SessionReaper { diff --git a/bridged/src/main/java/dev/ltms/bridged/session/WorktreeException.java b/bridged/src/main/java/dev/ltms/fleet/session/WorktreeException.java similarity index 90% rename from bridged/src/main/java/dev/ltms/bridged/session/WorktreeException.java rename to bridged/src/main/java/dev/ltms/fleet/session/WorktreeException.java index ee993ad..1073076 100644 --- a/bridged/src/main/java/dev/ltms/bridged/session/WorktreeException.java +++ b/bridged/src/main/java/dev/ltms/fleet/session/WorktreeException.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; /** Non-zero exit or I/O failure from a git worktree operation. */ public final class WorktreeException extends RuntimeException { diff --git a/bridged/src/main/java/dev/ltms/bridged/session/WorktreeRequest.java b/bridged/src/main/java/dev/ltms/fleet/session/WorktreeRequest.java similarity index 89% rename from bridged/src/main/java/dev/ltms/bridged/session/WorktreeRequest.java rename to bridged/src/main/java/dev/ltms/fleet/session/WorktreeRequest.java index 82a48a1..06149e4 100644 --- a/bridged/src/main/java/dev/ltms/bridged/session/WorktreeRequest.java +++ b/bridged/src/main/java/dev/ltms/fleet/session/WorktreeRequest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; /** Ask {@link SessionManager#acquire} to provision an isolated worktree. null ⇒ run in the shared primary tree. */ public record WorktreeRequest(String ticketSlug, String baseRef) { diff --git a/bridged/src/main/java/dev/ltms/bridged/session/Worktrees.java b/bridged/src/main/java/dev/ltms/fleet/session/Worktrees.java similarity index 99% rename from bridged/src/main/java/dev/ltms/bridged/session/Worktrees.java rename to bridged/src/main/java/dev/ltms/fleet/session/Worktrees.java index 5cf827f..e49e928 100644 --- a/bridged/src/main/java/dev/ltms/bridged/session/Worktrees.java +++ b/bridged/src/main/java/dev/ltms/fleet/session/Worktrees.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; import java.util.List; import java.util.Optional; diff --git a/bridged/src/main/resources/logback.xml b/bridged/src/main/resources/logback.xml index beda6f1..8df29f7 100644 --- a/bridged/src/main/resources/logback.xml +++ b/bridged/src/main/resources/logback.xml @@ -6,7 +6,7 @@ that SDK WARN because it would devalue the action-needed WARN level used by M4 fleet health. If a later SDK handles cancellation, this filter simply stops matching and can be removed. --> - + @@ -38,7 +38,7 @@ - + diff --git a/bridged/src/test/java/dev/ltms/bridged/BridgedDeliverabilityTest.java b/bridged/src/test/java/dev/ltms/fleet/FleetDeliverabilityTest.java similarity index 79% rename from bridged/src/test/java/dev/ltms/bridged/BridgedDeliverabilityTest.java rename to bridged/src/test/java/dev/ltms/fleet/FleetDeliverabilityTest.java index 2a5a426..d05045c 100644 --- a/bridged/src/test/java/dev/ltms/bridged/BridgedDeliverabilityTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/FleetDeliverabilityTest.java @@ -1,6 +1,6 @@ -package dev.ltms.bridged; +package dev.ltms.fleet; -import dev.ltms.bridged.inject.MemberPresence; +import dev.ltms.fleet.inject.MemberPresence; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -19,7 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * every lead→lead delivery sat on the gate for the full readiness grace and failed ~60s later without * a keystroke ever reaching the pane. */ -class BridgedDeliverabilityTest { +class FleetDeliverabilityTest { private static Supplier> leads(Map m) { return () -> m; @@ -31,13 +31,13 @@ class BridgedDeliverabilityTest { MemberPresence presence = new MemberPresence(); presence.markPresent("term_worker"); - assertTrue(Bridged.deliverableTo(presence, leads(Map.of())).test("term_worker")); + assertTrue(Fleetd.deliverableTo(presence, leads(Map.of())).test("term_worker")); } @Test @DisplayName("a worker still in its boot window is held back") void absentWorkerIsNotDeliverable() { - assertFalse(Bridged.deliverableTo(new MemberPresence(), leads(Map.of())).test("term_booting")); + assertFalse(Fleetd.deliverableTo(new MemberPresence(), leads(Map.of())).test("term_booting")); } @Test @@ -45,7 +45,7 @@ class BridgedDeliverabilityTest { void leadIsDeliverableWithoutPresence() { MemberPresence presence = new MemberPresence(); Predicate deliverable = - Bridged.deliverableTo(presence, leads(Map.of("term_lead", "opus-5.0"))); + Fleetd.deliverableTo(presence, leads(Map.of("term_lead", "opus-5.0"))); assertFalse(presence.isPresent("term_lead"), "a lead is never enrolled in worker presence"); assertTrue(deliverable.test("term_lead"), "…and must be deliverable anyway"); @@ -57,7 +57,7 @@ class BridgedDeliverabilityTest { MemberPresence presence = new MemberPresence(); presence.markPresent("term_worker"); - assertFalse(Bridged.deliverableTo(presence, leads(Map.of("term_lead", "opus-5.0"))) + assertFalse(Fleetd.deliverableTo(presence, leads(Map.of("term_lead", "opus-5.0"))) .test("term_stranger")); } @@ -65,7 +65,7 @@ class BridgedDeliverabilityTest { @DisplayName("a lead discovered after startup becomes deliverable with no restart") void leadSetIsReadThroughOnEveryCall() { Map discovered = new HashMap<>(); - Predicate deliverable = Bridged.deliverableTo(new MemberPresence(), leads(discovered)); + Predicate deliverable = Fleetd.deliverableTo(new MemberPresence(), leads(discovered)); assertFalse(deliverable.test("term_late")); discovered.put("term_late", "gpt-sol-5.6"); // leadScan picks up a newly labelled tab @@ -77,7 +77,7 @@ class BridgedDeliverabilityTest { void forgetDoesNotDisarmALead() { MemberPresence presence = new MemberPresence(); Predicate deliverable = - Bridged.deliverableTo(presence, leads(Map.of("term_lead", "opus-5.0"))); + Fleetd.deliverableTo(presence, leads(Map.of("term_lead", "opus-5.0"))); presence.forget("term_lead"); // the injector's cleanup path runs against every target diff --git a/bridged/src/test/java/dev/ltms/bridged/MemberCredentialsGapReportTest.java b/bridged/src/test/java/dev/ltms/fleet/MemberCredentialsGapReportTest.java similarity index 81% rename from bridged/src/test/java/dev/ltms/bridged/MemberCredentialsGapReportTest.java rename to bridged/src/test/java/dev/ltms/fleet/MemberCredentialsGapReportTest.java index 579019e..b60aa04 100644 --- a/bridged/src/test/java/dev/ltms/bridged/MemberCredentialsGapReportTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/MemberCredentialsGapReportTest.java @@ -1,9 +1,9 @@ -package dev.ltms.bridged; +package dev.ltms.fleet; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.config.BridgedConfig; +import dev.ltms.fleet.config.FleetConfig; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.slf4j.LoggerFactory; @@ -22,14 +22,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue; */ class MemberCredentialsGapReportTest { - private static BridgedConfig load(Path dir, String yaml) throws Exception { + private static FleetConfig load(Path dir, String yaml) throws Exception { Path f = dir.resolve("bridged.yaml"); Files.writeString(f, yaml); - return BridgedConfig.load(f); + return FleetConfig.load(f); } private static ListAppender attach() { - Logger logger = (Logger) LoggerFactory.getLogger(Bridged.class); + Logger logger = (Logger) LoggerFactory.getLogger(Fleetd.class); ListAppender appender = new ListAppender<>(); appender.start(); logger.addAppender(appender); @@ -37,16 +37,16 @@ class MemberCredentialsGapReportTest { } private static void detach(ListAppender appender) { - ((Logger) LoggerFactory.getLogger(Bridged.class)).detachAppender(appender); + ((Logger) LoggerFactory.getLogger(Fleetd.class)).detachAppender(appender); } @Test void anAbsentBlockWarnsThatEveryMemberInheritsTheWholeStore(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, "bind:\n host: 127.0.0.1\n port: 8765\n"); + FleetConfig cfg = load(dir, "bind:\n host: 127.0.0.1\n port: 8765\n"); ListAppender appender = attach(); try { - Bridged.reportMemberCredentialsGap(cfg); + Fleetd.reportMemberCredentialsGap(cfg); } finally { detach(appender); } @@ -60,14 +60,14 @@ class MemberCredentialsGapReportTest { @Test void anEmptyKnownListWarnsTheSameAsAbsent(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, """ + FleetConfig cfg = load(dir, """ memberCredentials: policy: deny-by-default """); ListAppender appender = attach(); try { - Bridged.reportMemberCredentialsGap(cfg); + Fleetd.reportMemberCredentialsGap(cfg); } finally { detach(appender); } @@ -80,21 +80,21 @@ class MemberCredentialsGapReportTest { @Test void aPopulatedKnownListLogsInfoNotWarn(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, """ + FleetConfig cfg = load(dir, """ memberCredentials: policy: deny-by-default allow: [AI_GATEWAY_TOKEN] known: [AI_GATEWAY_TOKEN, GITEA_ACCESS_TOKEN] """); - // logback-test.xml pins dev.ltms.bridged to WARN (see its own comment); raise it here so + // logback-test.xml pins dev.ltms.fleet to WARN (see its own comment); raise it here so // the INFO line this test asserts on actually reaches the appender, and restore after. - Logger logger = (Logger) LoggerFactory.getLogger(Bridged.class); + Logger logger = (Logger) LoggerFactory.getLogger(Fleetd.class); ch.qos.logback.classic.Level original = logger.getLevel(); logger.setLevel(ch.qos.logback.classic.Level.INFO); ListAppender appender = attach(); try { - Bridged.reportMemberCredentialsGap(cfg); + Fleetd.reportMemberCredentialsGap(cfg); } finally { detach(appender); logger.setLevel(original); diff --git a/bridged/src/test/java/dev/ltms/bridged/RequiredSecretEnvVarsTest.java b/bridged/src/test/java/dev/ltms/fleet/RequiredSecretEnvVarsTest.java similarity index 74% rename from bridged/src/test/java/dev/ltms/bridged/RequiredSecretEnvVarsTest.java rename to bridged/src/test/java/dev/ltms/fleet/RequiredSecretEnvVarsTest.java index 4ce7ca9..8f9d648 100644 --- a/bridged/src/test/java/dev/ltms/bridged/RequiredSecretEnvVarsTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/RequiredSecretEnvVarsTest.java @@ -1,6 +1,6 @@ -package dev.ltms.bridged; +package dev.ltms.fleet; -import dev.ltms.bridged.config.BridgedConfig; +import dev.ltms.fleet.config.FleetConfig; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -14,28 +14,28 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; /** - * CB-594: {@link Bridged#requiredSecretEnvVars(BridgedConfig)} is what decides what the startup + * CB-594: {@link Fleetd#requiredSecretEnvVars(FleetConfig)} is what decides what the startup * secret report checks — it must derive that set from the config, not a hand-written list, or a * new profile's token silently stops being reported. */ class RequiredSecretEnvVarsTest { - private static BridgedConfig load(Path dir, String yaml) throws Exception { + private static FleetConfig load(Path dir, String yaml) throws Exception { Path f = dir.resolve("bridged.yaml"); Files.writeString(f, yaml); - return BridgedConfig.load(f); + return FleetConfig.load(f); } @Test void collectsATokenEnvPerNonSubscriptionProfile(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, """ + FleetConfig cfg = load(dir, """ profiles: local: baseUrl: http://gx00.gw:8000 tokenEnv: AI_GATEWAY_TOKEN """); - Map> required = Bridged.requiredSecretEnvVars(cfg); + Map> required = Fleetd.requiredSecretEnvVars(cfg); assertTrue(required.containsKey("AI_GATEWAY_TOKEN")); assertEquals(List.of("profile 'local' tokenEnv"), required.get("AI_GATEWAY_TOKEN")); @@ -43,20 +43,20 @@ class RequiredSecretEnvVarsTest { @Test void aSubscriptionProfileNeedsNoTokenEnv(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, """ + FleetConfig cfg = load(dir, """ profiles: opus: subscription: true model: claude-opus-5 """); - assertTrue(Bridged.requiredSecretEnvVars(cfg).isEmpty(), + assertTrue(Fleetd.requiredSecretEnvVars(cfg).isEmpty(), "subscription: true never reads ANTHROPIC_AUTH_TOKEN — see Profile#isSubscription"); } @Test void gitTokenEnvIsOptInAndCollectedWhenSet(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, """ + FleetConfig cfg = load(dir, """ profiles: local: baseUrl: http://gx00.gw:8000 @@ -64,7 +64,7 @@ class RequiredSecretEnvVarsTest { gitTokenEnv: WORKER_GITEA_TOKEN """); - Map> required = Bridged.requiredSecretEnvVars(cfg); + Map> required = Fleetd.requiredSecretEnvVars(cfg); assertTrue(required.containsKey("WORKER_GITEA_TOKEN")); assertEquals(List.of("profile 'local' gitTokenEnv"), required.get("WORKER_GITEA_TOKEN")); @@ -72,19 +72,19 @@ class RequiredSecretEnvVarsTest { @Test void noGitTokenEnvMeansNothingIsRequiredForIt(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, """ + FleetConfig cfg = load(dir, """ profiles: local: baseUrl: http://gx00.gw:8000 tokenEnv: AI_GATEWAY_TOKEN """); - assertFalse(Bridged.requiredSecretEnvVars(cfg).containsKey("WORKER_GITEA_TOKEN")); + assertFalse(Fleetd.requiredSecretEnvVars(cfg).containsKey("WORKER_GITEA_TOKEN")); } @Test void aVarSharedByTwoProfilesIsReportedOnceNamingBoth(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, """ + FleetConfig cfg = load(dir, """ profiles: local: baseUrl: http://gx00.gw:8000 @@ -97,7 +97,7 @@ class RequiredSecretEnvVarsTest { gitTokenEnv: WORKER_GITEA_TOKEN """); - Map> required = Bridged.requiredSecretEnvVars(cfg); + Map> required = Fleetd.requiredSecretEnvVars(cfg); assertEquals(List.of("profile 'local' tokenEnv", "profile 'gx' tokenEnv"), required.get("AI_GATEWAY_TOKEN")); @@ -107,8 +107,8 @@ class RequiredSecretEnvVarsTest { @Test void noProfilesMeansNothingIsRequired(@TempDir Path dir) throws Exception { - BridgedConfig cfg = load(dir, "bind:\n host: 127.0.0.1\n port: 8765\n"); + FleetConfig cfg = load(dir, "bind:\n host: 127.0.0.1\n port: 8765\n"); - assertTrue(Bridged.requiredSecretEnvVars(cfg).isEmpty()); + assertTrue(Fleetd.requiredSecretEnvVars(cfg).isEmpty()); } } diff --git a/bridged/src/test/java/dev/ltms/bridged/auth/AuditLogTest.java b/bridged/src/test/java/dev/ltms/fleet/auth/AuditLogTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/auth/AuditLogTest.java rename to bridged/src/test/java/dev/ltms/fleet/auth/AuditLogTest.java index 3e35109..338ae45 100644 --- a/bridged/src/test/java/dev/ltms/bridged/auth/AuditLogTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/auth/AuditLogTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; diff --git a/bridged/src/test/java/dev/ltms/bridged/auth/AuthzTest.java b/bridged/src/test/java/dev/ltms/fleet/auth/AuthzTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/auth/AuthzTest.java rename to bridged/src/test/java/dev/ltms/fleet/auth/AuthzTest.java index 63cfd2c..0abbb69 100644 --- a/bridged/src/test/java/dev/ltms/bridged/auth/AuthzTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/auth/AuthzTest.java @@ -1,8 +1,8 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; import org.junit.jupiter.api.Test; -import static dev.ltms.bridged.auth.Authz.Action.*; +import static dev.ltms.fleet.auth.Authz.Action.*; import static org.junit.jupiter.api.Assertions.*; /** CB-505 — the authorization table, pinned so it cannot drift silently. */ diff --git a/bridged/src/test/java/dev/ltms/bridged/auth/CallerResolverTest.java b/bridged/src/test/java/dev/ltms/fleet/auth/CallerResolverTest.java similarity index 93% rename from bridged/src/test/java/dev/ltms/bridged/auth/CallerResolverTest.java rename to bridged/src/test/java/dev/ltms/fleet/auth/CallerResolverTest.java index 060f5af..31a3bce 100644 --- a/bridged/src/test/java/dev/ltms/bridged/auth/CallerResolverTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/auth/CallerResolverTest.java @@ -1,10 +1,10 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.PaneLocator; -import dev.ltms.bridged.mcp.ConnectionIdentity; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.peer.MemberRole; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.PaneLocator; +import dev.ltms.fleet.mcp.ConnectionIdentity; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.peer.MemberRole; import org.junit.jupiter.api.Test; import java.util.Map; @@ -35,12 +35,12 @@ class CallerResolverTest { } private static MemberRegistry boundMembers(String slot, MemberRole role) { - Map architects = role == MemberRole.ARCHITECT - ? Map.of("lead-designer", new BridgedConfig.Slot("sonnet")) : Map.of(); - Map devs = role == MemberRole.DEV - ? Map.of("builder", new BridgedConfig.Slot("sonnet")) : Map.of(); + Map architects = role == MemberRole.ARCHITECT + ? Map.of("lead-designer", new FleetConfig.Slot("sonnet")) : Map.of(); + Map devs = role == MemberRole.DEV + ? Map.of("builder", new FleetConfig.Slot("sonnet")) : Map.of(); MemberRegistry members = new MemberRegistry( - new BridgedConfig.Fleet(Map.of(), architects, devs, Map.of(), null)); + new FleetConfig.Fleet(Map.of(), architects, devs, Map.of(), null)); assertTrue(members.bind(slot, "term_a")); return members; } @@ -150,7 +150,7 @@ class CallerResolverTest { // ── CB-530: the leaders registry ──────────────────────────────────────────────────────────── // The fake resolves exactly one pane (term_a) from a PID, so "two leads both resolve" is - // asserted at the config layer (BridgedConfigTest#leaderTerminals…). What matters here is that + // asserted at the config layer (FleetConfigTest#leaderTerminals…). What matters here is that // resolution is a REGISTRY LOOKUP rather than a single equality test against one pin. @Test @@ -315,7 +315,7 @@ class CallerResolverTest { @Test void aBoundArchitectPaneResolvesToArchitectBeforeTheWorkerFallback() { - // This is the production construction path used by Bridged. + // This is the production construction path used by Fleetd. Principal p = CallerResolver.withLeadsAndMembers(workerIdentity(), false, null, Map::of, boundMembers("architect:lead-designer", MemberRole.ARCHITECT)) .resolve("127.0.0.1", 42, null); @@ -339,8 +339,8 @@ class CallerResolverTest { @Test void anUnboundPaneStillResolvesAsAWorker() { - MemberRegistry members = new MemberRegistry(new BridgedConfig.Fleet(Map.of(), - Map.of("lead-designer", new BridgedConfig.Slot("sonnet")), Map.of(), Map.of(), null)); + MemberRegistry members = new MemberRegistry(new FleetConfig.Fleet(Map.of(), + Map.of("lead-designer", new FleetConfig.Slot("sonnet")), Map.of(), Map.of(), null)); Principal p = CallerResolver.withLeadsAndMembers(workerIdentity(), false, null, Map::of, members).resolve("127.0.0.1", 42, null); @@ -365,8 +365,8 @@ class CallerResolverTest { /** The registry is live, like leads: a binding injected after construction is honoured. */ @Test void anArchitectBoundAfterConstructionIsHonouredWithoutRebuildingTheResolver() { - MemberRegistry members = new MemberRegistry(new BridgedConfig.Fleet(Map.of(), - Map.of("lead-designer", new BridgedConfig.Slot("sonnet")), Map.of(), Map.of(), null)); + MemberRegistry members = new MemberRegistry(new FleetConfig.Fleet(Map.of(), + Map.of("lead-designer", new FleetConfig.Slot("sonnet")), Map.of(), Map.of(), null)); CallerResolver r = CallerResolver.withLeadsAndMembers(workerIdentity(), false, null, Map::of, members); diff --git a/bridged/src/test/java/dev/ltms/bridged/auth/MemberRegistryTest.java b/bridged/src/test/java/dev/ltms/fleet/auth/MemberRegistryTest.java similarity index 91% rename from bridged/src/test/java/dev/ltms/bridged/auth/MemberRegistryTest.java rename to bridged/src/test/java/dev/ltms/fleet/auth/MemberRegistryTest.java index d3b8487..e64711a 100644 --- a/bridged/src/test/java/dev/ltms/bridged/auth/MemberRegistryTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/auth/MemberRegistryTest.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.auth; +package dev.ltms.fleet.auth; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.peer.MemberRole; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.peer.MemberRole; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -31,14 +31,14 @@ class MemberRegistryTest { private static final String DESIGNER = "architect:lead-designer"; private static final String REVIEWER = "architect:code-reviewer"; - private static BridgedConfig.Fleet fleetWith(Map architects) { - return new BridgedConfig.Fleet(Map.of(), architects, Map.of(), Map.of(), null); + private static FleetConfig.Fleet fleetWith(Map architects) { + return new FleetConfig.Fleet(Map.of(), architects, Map.of(), Map.of(), null); } - private static Map architects() { - Map pool = new LinkedHashMap<>(); - pool.put("lead-designer", new BridgedConfig.Slot("sonnet")); - pool.put("code-reviewer", new BridgedConfig.Slot("gx10")); + private static Map architects() { + Map pool = new LinkedHashMap<>(); + pool.put("lead-designer", new FleetConfig.Slot("sonnet")); + pool.put("code-reviewer", new FleetConfig.Slot("gx10")); return pool; } @@ -56,10 +56,10 @@ class MemberRegistryTest { /** The case the pool shape exists for: one profile serving two roles is not a duplicate. */ @Test void oneProfileMayServeTwoRolesUnderTheSameSlotName() { - Map devs = Map.of("sonnet", new BridgedConfig.Slot("sonnet")); - Map revs = Map.of("sonnet", new BridgedConfig.Slot("sonnet")); + Map devs = Map.of("sonnet", new FleetConfig.Slot("sonnet")); + Map revs = Map.of("sonnet", new FleetConfig.Slot("sonnet")); MemberRegistry r = new MemberRegistry( - new BridgedConfig.Fleet(Map.of(), Map.of(), devs, revs, null)); + new FleetConfig.Fleet(Map.of(), Map.of(), devs, revs, null)); assertEquals(Set.of("dev:sonnet", "reviewer:sonnet"), r.slots().keySet()); assertEquals(MemberRole.DEV, r.roleForSlot("dev:sonnet")); @@ -259,10 +259,10 @@ class MemberRegistryTest { /** A handed-over slot map is snapshotted at construction, not offered as live state. */ @Test void theSlotSnapshotIsFixedByConstruction() { - Map mutable = architects(); + Map mutable = architects(); MemberRegistry r = new MemberRegistry(fleetWith(mutable)); - mutable.put("hijack", new BridgedConfig.Slot("gx10")); + mutable.put("hijack", new FleetConfig.Slot("gx10")); assertFalse(r.isSlot("architect:hijack"), "a handed-over map is not offered as live state"); } diff --git a/bridged/src/test/java/dev/ltms/bridged/config/ConfigRefTest.java b/bridged/src/test/java/dev/ltms/fleet/config/ConfigRefTest.java similarity index 96% rename from bridged/src/test/java/dev/ltms/bridged/config/ConfigRefTest.java rename to bridged/src/test/java/dev/ltms/fleet/config/ConfigRefTest.java index 7b33a21..3f8e393 100644 --- a/bridged/src/test/java/dev/ltms/bridged/config/ConfigRefTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/config/ConfigRefTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.config; +package dev.ltms.fleet.config; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -35,7 +35,7 @@ class ConfigRefTest { } private static ConfigRef refFor(Path f) { - return new ConfigRef(f, BridgedConfig.load(f)); + return new ConfigRef(f, FleetConfig.load(f)); } @Test @@ -76,7 +76,7 @@ class ConfigRefTest { """)); ConfigRef ref = refFor(f); assertEquals("old charter", ref.get().fleet().charterFor( - dev.ltms.bridged.peer.MemberRole.ARCHITECT)); + dev.ltms.fleet.peer.MemberRole.ARCHITECT)); Files.writeString(f, yaml(""" fleet: @@ -88,7 +88,7 @@ class ConfigRefTest { assertTrue(out.applied()); assertTrue(out.deferred().isEmpty()); assertEquals("new charter", ref.get().fleet().charterFor( - dev.ltms.bridged.peer.MemberRole.ARCHITECT)); + dev.ltms.fleet.peer.MemberRole.ARCHITECT)); } @Test @@ -100,7 +100,7 @@ class ConfigRefTest { architect: valid charter """)); ConfigRef ref = refFor(f); - BridgedConfig before = ref.get(); + FleetConfig before = ref.get(); Files.writeString(f, yaml(""" fleet: @@ -166,7 +166,7 @@ class ConfigRefTest { Path f = dir.resolve("bridged.yaml"); Files.writeString(f, yaml("placement: weighted\n")); ConfigRef ref = refFor(f); - BridgedConfig before = ref.get(); + FleetConfig before = ref.get(); Files.writeString(f, "profiles:\n sonnet:\n baseUrl: \"unclosed\n"); ConfigRef.Outcome out = ref.reload(); @@ -183,7 +183,7 @@ class ConfigRefTest { Path f = dir.resolve("bridged.yaml"); Files.writeString(f, yaml("placement: weighted\n")); ConfigRef ref = refFor(f); - BridgedConfig before = ref.get(); + FleetConfig before = ref.get(); // A member slot naming a profile that does not exist — validateMembers refuses this at // startup, so it must refuse it here too. @@ -205,7 +205,7 @@ class ConfigRefTest { Path f = dir.resolve("bridged.yaml"); Files.writeString(f, yaml("")); ConfigRef ref = refFor(f); - BridgedConfig before = ref.get(); + FleetConfig before = ref.get(); Files.delete(f); ConfigRef.Outcome out = ref.reload(); @@ -339,7 +339,7 @@ class ConfigRefTest { } /** - * CB-578 stage B: exhaustedPattern is compiled once into Bridged.main's pattern map at startup + * CB-578 stage B: exhaustedPattern is compiled once into Fleetd.main's pattern map at startup * (see ExhaustedPatternLookup), so a reload never re-reads it — a changed pattern must be * reported deferred exactly like model/baseUrl, not silently claimed as applied. */ @@ -388,7 +388,7 @@ class ConfigRefTest { @Test void aFixedRefHasNoFileAndRefusesToReload() { - BridgedConfig cfg = new BridgedConfig(null, null, null, null, null, null, + FleetConfig cfg = new FleetConfig(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).withDefaults(); ConfigRef ref = ConfigRef.fixed(cfg); diff --git a/bridged/src/test/java/dev/ltms/bridged/config/ConfigWatcherTest.java b/bridged/src/test/java/dev/ltms/fleet/config/ConfigWatcherTest.java similarity index 87% rename from bridged/src/test/java/dev/ltms/bridged/config/ConfigWatcherTest.java rename to bridged/src/test/java/dev/ltms/fleet/config/ConfigWatcherTest.java index 753e0c4..b4b7942 100644 --- a/bridged/src/test/java/dev/ltms/bridged/config/ConfigWatcherTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/config/ConfigWatcherTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.config; +package dev.ltms.fleet.config; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -41,7 +41,7 @@ class ConfigWatcherTest { void aChangedMtimeTriggersAReload(@TempDir Path dir) throws Exception { Path f = dir.resolve("bridged.yaml"); write(f, yaml("weighted"), 1_000L); - ConfigRef ref = new ConfigRef(f, BridgedConfig.load(f)); + ConfigRef ref = new ConfigRef(f, FleetConfig.load(f)); ConfigWatcher watcher = new ConfigWatcher(ref, 10); try { @@ -58,8 +58,8 @@ class ConfigWatcherTest { void anUnchangedFileIsNotReloaded(@TempDir Path dir) throws Exception { Path f = dir.resolve("bridged.yaml"); write(f, yaml("weighted"), 1_000L); - ConfigRef ref = new ConfigRef(f, BridgedConfig.load(f)); - BridgedConfig before = ref.get(); + ConfigRef ref = new ConfigRef(f, FleetConfig.load(f)); + FleetConfig before = ref.get(); ConfigWatcher watcher = new ConfigWatcher(ref, 10); try { @@ -81,8 +81,8 @@ class ConfigWatcherTest { void aRefusedReloadIsNotRetriedUntilTheFileChangesAgain(@TempDir Path dir) throws Exception { Path f = dir.resolve("bridged.yaml"); write(f, yaml("weighted"), 1_000L); - ConfigRef ref = new ConfigRef(f, BridgedConfig.load(f)); - BridgedConfig before = ref.get(); + ConfigRef ref = new ConfigRef(f, FleetConfig.load(f)); + FleetConfig before = ref.get(); ConfigWatcher watcher = new ConfigWatcher(ref, 10); try { @@ -112,8 +112,8 @@ class ConfigWatcherTest { void aMissingFileIsSkippedAndTheNextTickTriesAgain(@TempDir Path dir) throws Exception { Path f = dir.resolve("bridged.yaml"); write(f, yaml("weighted"), 1_000L); - ConfigRef ref = new ConfigRef(f, BridgedConfig.load(f)); - BridgedConfig before = ref.get(); + ConfigRef ref = new ConfigRef(f, FleetConfig.load(f)); + FleetConfig before = ref.get(); ConfigWatcher watcher = new ConfigWatcher(ref, 10); try { @@ -132,7 +132,7 @@ class ConfigWatcherTest { /** A ref with no file behind it must not start a scheduler that could never do anything. */ @Test void aFixedRefStartsNoWatch() { - BridgedConfig cfg = new BridgedConfig(null, null, null, null, null, null, + FleetConfig cfg = new FleetConfig(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).withDefaults(); ConfigWatcher watcher = new ConfigWatcher(ConfigRef.fixed(cfg), 10); try { @@ -147,15 +147,15 @@ class ConfigWatcherTest { void configReloadIsOffUnlessTheBlockSaysOtherwise(@TempDir Path dir) throws Exception { Path f = dir.resolve("bridged.yaml"); write(f, yaml("weighted"), 1_000L); - assertNull(BridgedConfig.load(f).configReload()); + assertNull(FleetConfig.load(f).configReload()); write(f, yaml("weighted") + "configReload:\n enabled: true\n", 2_000L); - BridgedConfig.ConfigReload on = BridgedConfig.load(f).configReload(); + FleetConfig.ConfigReload on = FleetConfig.load(f).configReload(); assertTrue(on.isEnabled()); assertEquals(10, on.intervalSeconds(), "an absent interval defaults to 10s"); write(f, yaml("weighted") + "configReload:\n intervalSeconds: 30\n", 3_000L); - BridgedConfig.ConfigReload off = BridgedConfig.load(f).configReload(); + FleetConfig.ConfigReload off = FleetConfig.load(f).configReload(); assertFalse(off.isEnabled(), "a block that only sets the interval does not enable the watch"); assertEquals(30, off.intervalSeconds()); } diff --git a/bridged/src/test/java/dev/ltms/bridged/config/BridgedConfigTest.java b/bridged/src/test/java/dev/ltms/fleet/config/FleetConfigTest.java similarity index 91% rename from bridged/src/test/java/dev/ltms/bridged/config/BridgedConfigTest.java rename to bridged/src/test/java/dev/ltms/fleet/config/FleetConfigTest.java index 30cb531..3d84e3e 100644 --- a/bridged/src/test/java/dev/ltms/bridged/config/BridgedConfigTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/config/FleetConfigTest.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.config; +package dev.ltms.fleet.config; -import dev.ltms.bridged.auth.MemberRegistry; -import dev.ltms.bridged.peer.MemberRole; +import dev.ltms.fleet.auth.MemberRegistry; +import dev.ltms.fleet.peer.MemberRole; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -14,7 +14,7 @@ import java.util.regex.Pattern; import static org.junit.jupiter.api.Assertions.*; -class BridgedConfigTest { +class FleetConfigTest { @Test void loadsFullConfig(@TempDir Path dir) throws Exception { @@ -34,7 +34,7 @@ class BridgedConfigTest { - ollama.ltms.dev """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(8080, cfg.bind().port()); // The profile field is defaulted to the map key by the compact constructor. assertEquals("ltms-local", cfg.profiles().get("ltms-local").profile()); @@ -47,7 +47,7 @@ class BridgedConfigTest { Path f = dir.resolve("minimal.yaml"); Files.writeString(f, "bind:\n host: 0.0.0.0\n port: 9000\n"); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(9000, cfg.bind().port()); assertNotNull(cfg.guard(), "guard must default to empty, never null"); assertTrue(cfg.guard().offSubscriptionHosts().isEmpty()); @@ -63,7 +63,7 @@ class BridgedConfigTest { baseUrl: http://gx00.gw:8000 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(Set.of("ltms-local"), cfg.profiles().keySet()); assertEquals("ltms-local", cfg.effectiveDefaultProfile(), "with one profile configured there is nothing to choose between"); @@ -90,7 +90,7 @@ class BridgedConfigTest { offSubscriptionHosts: [gx10.gw, ollama.ltms.dev] """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(Set.of("gx10", "ollama"), cfg.profiles().keySet()); // Order, not just membership: placement breaks an exact-weight tie on definition order, so a // hash-ordered map here would make equal-weight placement differ from one restart to the next. @@ -109,27 +109,27 @@ class BridgedConfigTest { void ignoresUnknownKeys(@TempDir Path dir) throws Exception { Path f = dir.resolve("future.yaml"); Files.writeString(f, "bind:\n port: 8080\nfutureFeature:\n enabled: true\n"); - assertDoesNotThrow(() -> BridgedConfig.load(f)); + assertDoesNotThrow(() -> FleetConfig.load(f)); } @Test void absentChartersRemainValidAndPresentChartersUseRoleWireNames(@TempDir Path dir) throws Exception { Path absent = dir.resolve("absent.yaml"); Files.writeString(absent, "fleet: {}\n"); - BridgedConfig withoutCharters = BridgedConfig.load(absent); + FleetConfig withoutCharters = FleetConfig.load(absent); assertDoesNotThrow(withoutCharters::validateCharters); assertNull(withoutCharters.fleet().charterFor(MemberRole.ARCHITECT)); Path blank = dir.resolve("blank.yaml"); Files.writeString(blank, "fleet:\n charters:\n architect: ' '\n"); IllegalStateException blankError = assertThrows(IllegalStateException.class, - () -> BridgedConfig.load(blank).validateCharters()); + () -> FleetConfig.load(blank).validateCharters()); assertTrue(blankError.getMessage().contains("fleet.charters.architect is blank")); Path unknown = dir.resolve("unknown.yaml"); Files.writeString(unknown, "fleet:\n charters:\n architetc: text\n"); IllegalStateException unknownError = assertThrows(IllegalStateException.class, - () -> BridgedConfig.load(unknown).validateCharters()); + () -> FleetConfig.load(unknown).validateCharters()); assertTrue(unknownError.getMessage().contains("architetc")); assertTrue(unknownError.getMessage().contains("[architect, dev, reviewer]")); } @@ -143,14 +143,14 @@ class BridgedConfigTest { @Test void unknownTopLevelKeysAreNamedSoADroppedBlockCannotLookLikeAWorkingOne() { assertEquals(List.of("futureFeature", "leedars"), - BridgedConfig.unknownTopLevelKeys( + FleetConfig.unknownTopLevelKeys( "bind:\n port: 8080\nleedars:\n a: b\nfutureFeature: true\n"), "a typo'd key is the common case and must be reported by name"); } @Test void everyKeyThisBuildUnderstandsIsAbsentFromTheUnknownList() { - assertTrue(BridgedConfig.unknownTopLevelKeys(""" + assertTrue(FleetConfig.unknownTopLevelKeys(""" bind: port: 8080 herdrSocket: /tmp/s @@ -171,8 +171,8 @@ class BridgedConfigTest { @Test void aMalformedOrEmptyDocumentIsNotReportedAsUnknownKeys() { - assertTrue(BridgedConfig.unknownTopLevelKeys("").isEmpty()); - assertTrue(BridgedConfig.unknownTopLevelKeys("just a scalar").isEmpty()); + assertTrue(FleetConfig.unknownTopLevelKeys("").isEmpty()); + assertTrue(FleetConfig.unknownTopLevelKeys("just a scalar").isEmpty()); } // ── CB-531: lead discovery by tab label ───────────────────────────────────────────────────── @@ -182,7 +182,7 @@ class BridgedConfigTest { Path f = dir.resolve("no-scan.yaml"); Files.writeString(f, "bind:\n port: 8080\n"); - assertTrue(BridgedConfig.load(f).fleet().leaders().isEmpty(), + assertTrue(FleetConfig.load(f).fleet().leaders().isEmpty(), "turning this on widens who resolves as PRIMARY — upgrading the daemon must not do that"); } @@ -198,7 +198,7 @@ class BridgedConfigTest { tab: "lead: opus" """); - BridgedConfig.Leader lead = BridgedConfig.load(f).fleet().leaders().get("opus"); + FleetConfig.Leader lead = FleetConfig.load(f).fleet().leaders().get("opus"); assertEquals("lead:", lead.tabPrefix()); assertEquals(10, lead.scanIntervalSeconds()); assertEquals(1, lead.instances(), "one of a lead is the assumption worth defaulting to"); @@ -218,7 +218,7 @@ class BridgedConfigTest { scanIntervalSeconds: 30 """); - BridgedConfig.Leader lead = BridgedConfig.load(f).fleet().leaders().get("opus"); + FleetConfig.Leader lead = FleetConfig.load(f).fleet().leaders().get("opus"); assertEquals("drive:", lead.tabPrefix()); assertEquals(30, lead.scanIntervalSeconds()); } @@ -247,7 +247,7 @@ class BridgedConfigTest { tab: "lead: pinned" """); - var leaders = BridgedConfig.load(f).fleet().leaders(); + var leaders = FleetConfig.load(f).fleet().leaders(); assertTrue(leaders.get("launched").isCreatable()); assertFalse(leaders.get("pinned").isCreatable(), "no profile to launch on ⇒ recognise-only, the pre-CB-557 behaviour"); @@ -268,7 +268,7 @@ class BridgedConfigTest { ghost: tabPrefix: "lead:" """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateMembers); assertTrue(e.getMessage().contains("ghost"), "the message must name the useless entry"); @@ -292,7 +292,7 @@ class BridgedConfigTest { """); IllegalStateException e = - assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("opus"), "the message must name the offending entry"); assertTrue(e.getMessage().contains("tab:"), "the message must name the replacement key"); assertTrue(e.getMessage().contains("terminal"), "the message must name the retired key"); @@ -314,7 +314,7 @@ class BridgedConfigTest { """); IllegalStateException e = - assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("opus")); assertTrue(e.getMessage().contains("sol")); } @@ -325,7 +325,7 @@ class BridgedConfigTest { Path f = dir.resolve("primary-terminal-ok.yaml"); Files.writeString(f, "bind:\n port: 8080\nprimary:\n terminal: term_fixed\n"); - assertDoesNotThrow(() -> BridgedConfig.load(f)); + assertDoesNotThrow(() -> FleetConfig.load(f)); } /** CB-579 acceptance (3): distinct `tab:` labels need no shared prefix — one scanner finds both. */ @@ -343,7 +343,7 @@ class BridgedConfigTest { tab: "captain: sol" """); - var leaders = BridgedConfig.load(f).fleet().leaders(); + var leaders = FleetConfig.load(f).fleet().leaders(); assertEquals("lead: opus", leaders.get("opus").tab()); assertEquals("captain: sol", leaders.get("sol").tab()); } @@ -359,7 +359,7 @@ class BridgedConfigTest { Path f = dir.resolve("no-heartbeat.yaml"); Files.writeString(f, "bind:\n port: 8080\n"); - assertNull(BridgedConfig.load(f).leadHeartbeat(), + assertNull(FleetConfig.load(f).leadHeartbeat(), "no leadHeartbeat: block ⇒ the loop is never constructed and never fires (CB-551)"); } @@ -368,7 +368,7 @@ class BridgedConfigTest { Path f = dir.resolve("bare-heartbeat.yaml"); Files.writeString(f, "bind:\n port: 8080\nleadHeartbeat: {}\n"); - BridgedConfig.LeadHeartbeat hb = BridgedConfig.load(f).leadHeartbeat(); + FleetConfig.LeadHeartbeat hb = FleetConfig.load(f).leadHeartbeat(); assertNotNull(hb); assertEquals(300, hb.idleAfterSeconds(), "default quiet period"); assertEquals(60_000L, hb.backoffMs(), "default backoff"); @@ -387,7 +387,7 @@ class BridgedConfigTest { quietNudgeCap: 5 """); - BridgedConfig.LeadHeartbeat hb = BridgedConfig.load(f).leadHeartbeat(); + FleetConfig.LeadHeartbeat hb = FleetConfig.load(f).leadHeartbeat(); assertEquals(600, hb.idleAfterSeconds()); assertEquals(45_000L, hb.backoffMs()); assertEquals(5, hb.quietNudgeCap()); @@ -413,7 +413,7 @@ class BridgedConfigTest { tab: "lead: opus" tabPrefix: "lead:" """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateLeadTabPrefixes); @@ -433,7 +433,7 @@ class BridgedConfigTest { opus: tab: "lead: opus" """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateLeadTabPrefixes); @@ -459,9 +459,9 @@ class BridgedConfigTest { tab: "lead: opus" """); - assertDoesNotThrow(() -> BridgedConfig.load(f).validateLeadTabPrefixes()); + assertDoesNotThrow(() -> FleetConfig.load(f).validateLeadTabPrefixes()); for (MemberRole role : MemberRole.values()) { - assertFalse(BridgedConfig.Fleet.DEFAULT_TAB_LABEL + assertFalse(FleetConfig.Fleet.DEFAULT_TAB_LABEL .replace("{role}", role.wireName()).startsWith("lead:"), "no role renders a label that reads as a lead"); } @@ -478,7 +478,7 @@ class BridgedConfigTest { tabLabel: "lead: {profile}" """); - assertDoesNotThrow(() -> BridgedConfig.load(f).validateLeadTabPrefixes(), + assertDoesNotThrow(() -> FleetConfig.load(f).validateLeadTabPrefixes(), "a label that collides with a convention nobody reads is not a problem"); } @@ -501,7 +501,7 @@ class BridgedConfigTest { model: openai/gpt-5.6-terra """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); var leaders = cfg.fleet().leaders(); assertEquals(Set.of("opus-5.0", "gpt-sol-5.6"), leaders.keySet()); @@ -517,7 +517,7 @@ class BridgedConfigTest { Path f = dir.resolve("legacy-pin.yaml"); Files.writeString(f, "bind:\n port: 8080\nprimary:\n terminal: term_fixed\n"); - assertEquals(Map.of("term_fixed", "primary"), BridgedConfig.load(f).leaderTerminals(), + assertEquals(Map.of("term_fixed", "primary"), FleetConfig.load(f).leaderTerminals(), "configs that never migrate must behave exactly as they did before CB-530"); } @@ -526,7 +526,7 @@ class BridgedConfigTest { Path f = dir.resolve("none.yaml"); Files.writeString(f, "bind:\n port: 8080\n"); - assertTrue(BridgedConfig.load(f).leaderTerminals().isEmpty()); + assertTrue(FleetConfig.load(f).leaderTerminals().isEmpty()); } /** @@ -546,7 +546,7 @@ class BridgedConfigTest { tab: "lead: opus-5.0" """); - assertTrue(BridgedConfig.load(f).leaderTerminals().isEmpty(), + assertTrue(FleetConfig.load(f).leaderTerminals().isEmpty(), "no primary.terminal pin ⇒ nothing registered, even with fleet.leaders configured"); } @@ -569,7 +569,7 @@ class BridgedConfigTest { profile: sonnet """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); var pool = cfg.fleet().pool(MemberRole.ARCHITECT); assertEquals(Set.of("lead-designer", "second-opinion"), pool.keySet(), "slot names are the keys — unique within their pool by construction"); @@ -600,7 +600,7 @@ class BridgedConfigTest { profile: sonnet """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(List.of("sonnet"), cfg.fleet().profilesFor(MemberRole.DEV)); assertEquals(List.of("sonnet"), cfg.fleet().profilesFor(MemberRole.REVIEWER)); assertTrue(cfg.fleet().profilesFor(MemberRole.ARCHITECT).isEmpty()); @@ -626,7 +626,7 @@ class BridgedConfigTest { profile: sonnet """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertDoesNotThrow(cfg::validateMembers); assertEquals("sonnet", cfg.defaultProfileFor(MemberRole.DEV)); assertEquals("sonnet", cfg.defaultProfileFor(MemberRole.REVIEWER)); @@ -649,7 +649,7 @@ class BridgedConfigTest { terminal: term_design profile: sonnet """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals("sonnet", cfg.fleet().pool(MemberRole.ARCHITECT).get("lead-designer").profile(), "the profile is still read even when a stray terminal is ignored"); @@ -665,7 +665,7 @@ class BridgedConfigTest { Path f = dir.resolve("no-arch.yaml"); Files.writeString(f, "bind:\n port: 8080\n"); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertNotNull(cfg.fleet(), "an absent block is an empty fleet, not a null one"); assertTrue(cfg.fleet().rolesConfigured().isEmpty(), "no fleet: block ⇒ no member identity, exactly as before CB-548"); @@ -688,7 +688,7 @@ class BridgedConfigTest { profile: ltms-local """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertDoesNotThrow(cfg::validateMembers); assertEquals("ltms-local", cfg.fleet().pool(MemberRole.ARCHITECT).get("lead-designer").profile()); @@ -708,7 +708,7 @@ class BridgedConfigTest { lead-designer: profile: sonnet """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateMembers); assertTrue(e.getMessage().contains("lead-designer"), "the refusal names the slot"); @@ -729,7 +729,7 @@ class BridgedConfigTest { lead-designer: profile: "" """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateMembers); assertTrue(e.getMessage().contains("lead-designer"), "the refusal names the slot"); @@ -755,7 +755,7 @@ class BridgedConfigTest { profile: gx10 """); - assertDoesNotThrow(() -> BridgedConfig.load(f).validateMembers()); + assertDoesNotThrow(() -> FleetConfig.load(f).validateMembers()); } @Test @@ -763,7 +763,7 @@ class BridgedConfigTest { Path f = dir.resolve("no-arch.yaml"); Files.writeString(f, "bind:\n port: 8080\n"); - assertDoesNotThrow(() -> BridgedConfig.load(f).validateMembers()); + assertDoesNotThrow(() -> FleetConfig.load(f).validateMembers()); } @Test @@ -784,7 +784,7 @@ class BridgedConfigTest { """); IllegalStateException e = - assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("lead-designer"), "the refusal names the duplicated slot, was: " + e.getMessage()); assertTrue(e.getMessage().contains("fleet.architects"), @@ -813,7 +813,7 @@ class BridgedConfigTest { profile: sonnet """); - BridgedConfig cfg = assertDoesNotThrow(() -> BridgedConfig.load(f)); + FleetConfig cfg = assertDoesNotThrow(() -> FleetConfig.load(f)); assertEquals(Set.of("sonnet"), cfg.fleet().pool(MemberRole.DEV).keySet()); assertEquals(Set.of("sonnet"), cfg.fleet().pool(MemberRole.REVIEWER).keySet()); } @@ -833,7 +833,7 @@ class BridgedConfigTest { baseUrl: http://gx10.gw:8000 """); // Last-wins for a non-pool duplicate is untouched: only the fleet pools are walked. - assertEquals(Set.of("sonnet"), BridgedConfig.load(f).profiles().keySet()); + assertEquals(Set.of("sonnet"), FleetConfig.load(f).profiles().keySet()); } @Test @@ -860,7 +860,7 @@ class BridgedConfigTest { """); IllegalStateException e = - assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("lead-designer"), "the real top-level duplicate must be reported, was: " + e.getMessage()); assertFalse(e.getMessage().contains("nested-slot"), @@ -889,7 +889,7 @@ class BridgedConfigTest { a: 1 """); - BridgedConfig cfg = assertDoesNotThrow(() -> BridgedConfig.load(f)); + FleetConfig cfg = assertDoesNotThrow(() -> FleetConfig.load(f)); assertDoesNotThrow(cfg::validateMembers, "a nested duplicate inside a slot is not a duplicate slot and must not refuse startup"); var pool = cfg.fleet().pool(MemberRole.ARCHITECT); @@ -902,7 +902,7 @@ class BridgedConfigTest { Path f = dir.resolve("no-broker.yaml"); Files.writeString(f, "bind:\n port: 8080\n"); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertNull(cfg.broker(), "no broker: block → null → in-memory inbox is selected"); } @@ -916,7 +916,7 @@ class BridgedConfigTest { uri: amqp://guest:guest@127.0.0.1:5672/ """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertNotNull(cfg.broker()); assertTrue(cfg.broker().isConfigured(), "a non-blank uri enables the AMQP adapter"); assertEquals("amqp://guest:guest@127.0.0.1:5672/", cfg.broker().uri()); @@ -927,7 +927,7 @@ class BridgedConfigTest { Path f = dir.resolve("broker-blank.yaml"); Files.writeString(f, "bind:\n port: 8080\nbroker:\n uri: \"\"\n"); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertNotNull(cfg.broker()); assertFalse(cfg.broker().isConfigured(), "an empty uri must not enable AMQP"); } @@ -937,7 +937,7 @@ class BridgedConfigTest { Path f = dir.resolve("no-primary.yaml"); Files.writeString(f, "bind:\n port: 8080\n"); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertNull(cfg.primary(), "no primary: block → null → connection-derived identity"); } @@ -951,7 +951,7 @@ class BridgedConfigTest { terminal: term_fixed """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertNotNull(cfg.primary()); assertEquals("term_fixed", cfg.primary().terminal()); } @@ -961,7 +961,7 @@ class BridgedConfigTest { Path f = dir.resolve("primary-blank.yaml"); Files.writeString(f, "bind:\n port: 8080\nprimary:\n terminal: \"\"\n"); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertNotNull(cfg.primary()); assertTrue(cfg.primary().terminal() == null || cfg.primary().terminal().isBlank(), "a blank terminal in yaml should be treated as absent — null or empty are equivalent"); @@ -979,8 +979,8 @@ class BridgedConfigTest { argv: ["ccs", "gx10"] """); - BridgedConfig cfg = BridgedConfig.load(f); - assertEquals(BridgedConfig.Profile.KIND_CLAUDE_CODE, cfg.profiles().get("gx10").kind(), + FleetConfig cfg = FleetConfig.load(f); + assertEquals(FleetConfig.Profile.KIND_CLAUDE_CODE, cfg.profiles().get("gx10").kind(), "a worker with no kind: is a claude-code worker (backward compatible)"); } @@ -995,8 +995,8 @@ class BridgedConfigTest { argv: ["opencode"] """); - BridgedConfig cfg = BridgedConfig.load(f); - assertEquals(BridgedConfig.Profile.KIND_OPENCODE, cfg.profiles().get("gemini").kind(), + FleetConfig cfg = FleetConfig.load(f); + assertEquals(FleetConfig.Profile.KIND_OPENCODE, cfg.profiles().get("gemini").kind(), "kind is normalised to lower-case so YAML casing does not matter"); } @@ -1012,9 +1012,9 @@ class BridgedConfigTest { model: google/gemini-2.5-pro """); - BridgedConfig cfg = BridgedConfig.load(f); - BridgedConfig.Profile claude = cfg.profiles().get("claude"); - BridgedConfig.Profile gemini = cfg.profiles().get("gemini"); + FleetConfig cfg = FleetConfig.load(f); + FleetConfig.Profile claude = cfg.profiles().get("claude"); + FleetConfig.Profile gemini = cfg.profiles().get("gemini"); assertTrue(claude.isClaudeCode(), "the default-kind worker is claude-code"); assertFalse(claude.isOpenCode(), "a claude-code worker is not opencode"); assertTrue(gemini.isOpenCode(), "the kind: opencode worker is opencode"); @@ -1033,7 +1033,7 @@ class BridgedConfigTest { model: google/gemini-2.5-pro """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(java.util.List.of("claude"), cfg.profiles().get("claude").argv(), "a claude-code worker with no argv defaults to the claude binary"); assertEquals(java.util.List.of("opencode"), cfg.profiles().get("gemini").argv(), @@ -1055,7 +1055,7 @@ class BridgedConfigTest { model: google/gemini-2.5-pro """); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("gemini"), "error names the profile: " + e.getMessage()); assertTrue(e.getMessage().contains("opencod"), "error names the bad value: " + e.getMessage()); assertTrue(e.getMessage().contains("claude-code") && e.getMessage().contains("opencode"), @@ -1073,8 +1073,8 @@ class BridgedConfigTest { argv: ["ccs", "gx10"] """); - BridgedConfig cfg = BridgedConfig.load(f); - assertEquals(BridgedConfig.Profile.KIND_CLAUDE_CODE, cfg.profiles().get("gx10").kind(), + FleetConfig cfg = FleetConfig.load(f); + assertEquals(FleetConfig.Profile.KIND_CLAUDE_CODE, cfg.profiles().get("gx10").kind(), "a blank kind: is documented to behave exactly like an absent one"); } @@ -1083,7 +1083,7 @@ class BridgedConfigTest { Path f = dir.resolve("no-auth-block.yaml"); Files.writeString(f, "bind:\n host: 127.0.0.1\n port: 8765\n"); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertNotNull(cfg.auth(), "auth must default rather than be null"); assertFalse(cfg.auth().tokenMode()); assertEquals("BRIDGED_API_TOKEN", cfg.auth().tokenEnv(), "documented default env var"); @@ -1100,7 +1100,7 @@ class BridgedConfigTest { Path f = dir.resolve("exposed.yaml"); Files.writeString(f, "bind:\n host: 0.0.0.0\n port: 8765\n"); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateAuthExposure); assertTrue(e.getMessage().contains("auth.mode: token"), "the error must say how to fix it, not just that it refused"); @@ -1118,7 +1118,7 @@ class BridgedConfigTest { tokenEnv: MY_TOKEN """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertTrue(cfg.auth().tokenMode()); assertEquals("MY_TOKEN", cfg.auth().tokenEnv()); assertDoesNotThrow(cfg::validateAuthExposure); @@ -1129,7 +1129,7 @@ class BridgedConfigTest { for (String host : new String[]{"127.0.0.1", "localhost", "::1", "127.0.0.53"}) { Path f = dir.resolve("lb-" + host.replace(':', '_') + ".yaml"); Files.writeString(f, "bind:\n host: \"" + host + "\"\n port: 8765\n"); - assertDoesNotThrow(() -> BridgedConfig.load(f).validateAuthExposure(), + assertDoesNotThrow(() -> FleetConfig.load(f).validateAuthExposure(), host + " is loopback and must not trip the exposure guard"); } } @@ -1145,7 +1145,7 @@ class BridgedConfigTest { Path example = Path.of("bridged.example.yaml"); assertTrue(Files.exists(example), "bridged.example.yaml must ship next to the pom"); - BridgedConfig cfg = BridgedConfig.load(example); + FleetConfig cfg = FleetConfig.load(example); assertEquals(8765, cfg.bind().port(), "example binds the documented default port"); assertTrue(cfg.profiles().containsKey("gx10"), "example documents the gx10 profile"); assertEquals("gx10", cfg.effectiveDefaultProfile(), "example's dev pool resolves"); @@ -1202,12 +1202,12 @@ class BridgedConfigTest { known: [AI_GATEWAY_TOKEN, GITEA_ACCESS_TOKEN] """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(25000, cfg.spawnReadyTimeoutMs(), "spawnReadyTimeoutMs is camelCase, not snake_case"); assertEquals(400, cfg.spawnReadyPollMs(), "spawnReadyPollMs is camelCase, not snake_case"); assertEquals("/tmp/bridged-worktrees", cfg.worktreeRoot()); - BridgedConfig.Profile w = cfg.profiles().get("gx10"); + FleetConfig.Profile w = cfg.profiles().get("gx10"); assertEquals("/tmp/ccs/gx10", w.configDir()); assertEquals("/tmp/repo", w.cwd()); assertEquals(java.util.List.of(".mcp.json", ".env"), w.parityOverlay()); @@ -1231,21 +1231,21 @@ class BridgedConfigTest { assertEquals(45_000L, cfg.leadHeartbeat().backoffMs()); assertEquals(5, cfg.leadHeartbeat().quietNudgeCap()); - assertEquals(BridgedConfig.MemberCredentials.POLICY_DENY_BY_DEFAULT, cfg.memberCredentials().policy(), + assertEquals(FleetConfig.MemberCredentials.POLICY_DENY_BY_DEFAULT, cfg.memberCredentials().policy(), "memberCredentials binds at the top level"); assertEquals(Set.of("AI_GATEWAY_TOKEN"), cfg.memberCredentials().allowSet()); assertEquals(Set.of("GITEA_ACCESS_TOKEN"), cfg.memberCredentials().blockedSet()); } /** - * A top-level key {@code BridgedConfig} reads but that appears nowhere in + * A top-level key {@code FleetConfig} reads but that appears nowhere in * {@code bridged.example.yaml} — live or commented — is invisible drift: {@code bridged.yaml} * is gitignored, so the example is the ONLY committed description of the config schema, and * neither {@link #shippedExampleConfigParses} (example → code: does the example still parse) * nor {@link #everyOptionalKnobDocumentedInTheExampleBinds} (a hand-maintained list of keys * that must bind) can catch a brand-new key nobody added to either. * - *

      This test compares the OTHER direction: every key in {@link BridgedConfig#KNOWN_TOP_LEVEL_KEYS} + *

      This test compares the OTHER direction: every key in {@link FleetConfig#KNOWN_TOP_LEVEL_KEYS} * (the parser's own accepted set, which backs the unknown-key WARN) must appear as a top-level * key in the example text, live or commented-out — see {@link #topLevelKeyDocumented}. */ @@ -1255,13 +1255,13 @@ class BridgedConfigTest { assertTrue(Files.exists(example), "bridged.example.yaml must ship next to the pom"); String text = Files.readString(example); - List undocumented = BridgedConfig.KNOWN_TOP_LEVEL_KEYS.stream() + List undocumented = FleetConfig.KNOWN_TOP_LEVEL_KEYS.stream() .filter(key -> !topLevelKeyDocumented(text, key)) .sorted() .toList(); assertTrue(undocumented.isEmpty(), () -> "key(s) " + undocumented - + " are read by BridgedConfig but appear nowhere in bridged.example.yaml — " + + " are read by FleetConfig but appear nowhere in bridged.example.yaml — " + "document each one there, commented out if optional. bridged.yaml is " + "gitignored, so this file is the only committed description of the config " + "schema an operator or a worker can see."); @@ -1321,7 +1321,7 @@ class BridgedConfigTest { baseUrl: http://gx10.gw:8000 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals("fixed", cfg.placement(), "omitted placement must default to fixed"); } @@ -1336,8 +1336,8 @@ class BridgedConfigTest { baseUrl: http://gx10.gw:8000 """); - BridgedConfig cfg = BridgedConfig.load(f); - BridgedConfig.Profile w = cfg.profiles().get("gx10"); + FleetConfig cfg = FleetConfig.load(f); + FleetConfig.Profile w = cfg.profiles().get("gx10"); assertEquals(1.0f, w.weight(), 0.0001f, "absent weight defaults to 1.0"); assertNull(w.maxLoad(), "absent maxLoad defaults to unlimited (null)"); } @@ -1356,8 +1356,8 @@ class BridgedConfigTest { weight: 0 """); - BridgedConfig cfg = BridgedConfig.load(f); - BridgedConfig.Profile w = cfg.profiles().get("opus"); + FleetConfig cfg = FleetConfig.load(f); + FleetConfig.Profile w = cfg.profiles().get("opus"); assertEquals(0.0f, w.weight(), 0.0001f, "an explicit weight: 0 must stay 0, not coerce to 1.0"); } @@ -1373,8 +1373,8 @@ class BridgedConfigTest { weight: -3.0 """); - BridgedConfig cfg = BridgedConfig.load(f); - BridgedConfig.Profile w = cfg.profiles().get("gx10"); + FleetConfig cfg = FleetConfig.load(f); + FleetConfig.Profile w = cfg.profiles().get("gx10"); assertEquals(0.0f, w.weight(), 0.0001f, "a negative weight behaves as excluded (0), not as an error and not as 1.0"); } @@ -1394,8 +1394,8 @@ class BridgedConfigTest { maxLoad: 0 """); - BridgedConfig cfg = BridgedConfig.load(f); - BridgedConfig.Profile w = cfg.profiles().get("opus"); + FleetConfig cfg = FleetConfig.load(f); + FleetConfig.Profile w = cfg.profiles().get("opus"); assertEquals(0, w.maxLoad(), "an explicit maxLoad: 0 must stay 0, not coerce to unlimited (null)"); } @@ -1411,15 +1411,15 @@ class BridgedConfigTest { maxLoad: -2 """); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("opus"), "error names the profile: " + e.getMessage()); assertTrue(e.getMessage().contains("maxLoad"), "error names the key: " + e.getMessage()); } /** * CB-606: an unrecognized {@code auth.mode} used to silently fall back to - * {@code loopback-trust} — {@link BridgedConfig.Auth#tokenMode()} only checked equality - * against {@code "token"}. On a loopback bind {@link BridgedConfig#validateAuthExposure()} + * {@code loopback-trust} — {@link FleetConfig.Auth#tokenMode()} only checked equality + * against {@code "token"}. On a loopback bind {@link FleetConfig#validateAuthExposure()} * never runs (it only fires for a non-loopback bind), so the typo was completely invisible: * the daemon started cleanly and authenticated nobody while the operator believed token mode * was active. @@ -1435,7 +1435,7 @@ class BridgedConfigTest { mode: toekn """); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("toekn"), "error names the bad value: " + e.getMessage()); assertTrue(e.getMessage().contains("loopback-trust") && e.getMessage().contains("token"), "error names the accepted set: " + e.getMessage()); @@ -1443,7 +1443,7 @@ class BridgedConfigTest { /** * CB-606: an unrecognized per-profile {@code placement:} used to silently fall back to legacy - * pane placement — {@link BridgedConfig.Profile#tabPlacement()} only checked equality against + * pane placement — {@link FleetConfig.Profile#tabPlacement()} only checked equality against * {@code "tab"}. */ @Test @@ -1456,7 +1456,7 @@ class BridgedConfigTest { placement: tabb """); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("gx10"), "error names the profile: " + e.getMessage()); assertTrue(e.getMessage().contains("tabb"), "error names the bad value: " + e.getMessage()); assertTrue(e.getMessage().contains("tab") && e.getMessage().contains("pane"), @@ -1482,12 +1482,12 @@ class BridgedConfigTest { - GITEA_ACCESS_TOKEN """); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("deny-by-defualt"), "error names the bad value: " + e.getMessage()); assertTrue(e.getMessage().contains("deny-by-default"), "error names the accepted set: " + e.getMessage()); } - /** {@code allow}/{@code known} bind and {@link BridgedConfig.MemberCredentials#blockedSet()} is known minus allow. */ + /** {@code allow}/{@code known} bind and {@link FleetConfig.MemberCredentials#blockedSet()} is known minus allow. */ @Test void memberCredentialsBindsAllowAndKnownAndComputesBlockedSet(@TempDir Path dir) throws Exception { Path f = dir.resolve("member-credentials.yaml"); @@ -1506,8 +1506,8 @@ class BridgedConfigTest { - GITLAB_PERSONAL_ACCESS_TOKEN """); - BridgedConfig.MemberCredentials mc = BridgedConfig.load(f).memberCredentials(); - assertEquals(BridgedConfig.MemberCredentials.POLICY_DENY_BY_DEFAULT, mc.policy()); + FleetConfig.MemberCredentials mc = FleetConfig.load(f).memberCredentials(); + assertEquals(FleetConfig.MemberCredentials.POLICY_DENY_BY_DEFAULT, mc.policy()); assertEquals(Set.of("AI_GATEWAY_TOKEN", "WORKER_GITEA_TOKEN"), mc.allowSet()); assertEquals(Set.of("GITEA_ACCESS_TOKEN", "GITLAB_PERSONAL_ACCESS_TOKEN"), mc.blockedSet(), "blockedSet is known minus allow"); @@ -1516,7 +1516,7 @@ class BridgedConfigTest { /** * CB-596: omitting {@code memberCredentials:} entirely must NOT crash a reader that assumes a * non-null block (the same "fill in nested defaults" contract every other structural field - * gets — see {@link BridgedConfig#withDefaults()}), but it also must not pretend anything is + * gets — see {@link FleetConfig#withDefaults()}), but it also must not pretend anything is * blocked: an empty {@code known} list blocks nothing, and that is a real gap the operator must * close by configuring this block, not a safe default. */ @@ -1525,7 +1525,7 @@ class BridgedConfigTest { Path f = dir.resolve("member-credentials-absent.yaml"); Files.writeString(f, "bind:\n port: 8080\n"); - BridgedConfig.MemberCredentials mc = BridgedConfig.load(f).memberCredentials(); + FleetConfig.MemberCredentials mc = FleetConfig.load(f).memberCredentials(); assertNotNull(mc, "withDefaults() must never leave this null"); assertTrue(mc.known().isEmpty(), "no known list configured — nothing is blocked"); assertTrue(mc.allowSet().isEmpty()); @@ -1541,8 +1541,8 @@ class BridgedConfigTest { baseUrl: http://gx10.gw:8000 """); - BridgedConfig cfg = BridgedConfig.load(f); - BridgedConfig.Profile w = cfg.profiles().get("gx10"); + FleetConfig cfg = FleetConfig.load(f); + FleetConfig.Profile w = cfg.profiles().get("gx10"); assertTrue(w.tabPlacement(), "an absent placement must keep defaulting to tab"); } @@ -1561,7 +1561,7 @@ class BridgedConfigTest { placement: weightd """); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("weightd"), "error names the bad value: " + e.getMessage()); assertTrue(e.getMessage().contains("fixed") && e.getMessage().contains("round-robin") && e.getMessage().contains("weighted"), @@ -1580,7 +1580,7 @@ class BridgedConfigTest { baseUrl: http://gx10.gw:8000 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertTrue(cfg.profiles().get("sonnet").isSubscription(), "subscription: true binds as an explicit opt-in"); assertFalse(cfg.profiles().get("opted").isSubscription(), @@ -1598,7 +1598,7 @@ class BridgedConfigTest { baseUrl: http://gx10.gw:8000 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(List.of(".env", ".envrc"), cfg.profiles().get("gx10").parityOverlay(), "the default parity overlay is the env files; settings.local.json is no longer copied by default"); @@ -1616,7 +1616,7 @@ class BridgedConfigTest { parityOverlay: [".claude/settings.local.json", ".env"] """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals(List.of(".claude/settings.local.json", ".env"), cfg.profiles().get("gx10").parityOverlay(), "an operator's explicit list survives verbatim — the default only changes when unset"); @@ -1635,7 +1635,7 @@ class BridgedConfigTest { env: ANTHROPIC_BASE_URL: http://anything-not-on-the-allowlist """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateSubscriptionProfiles); @@ -1655,7 +1655,7 @@ class BridgedConfigTest { env: ANTHROPIC_AUTH_TOKEN: sk-ant-not-on-any-allowlist """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateSubscriptionProfiles); @@ -1675,7 +1675,7 @@ class BridgedConfigTest { env: JAVA_HOME: /opt/jdk """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertDoesNotThrow(cfg::validateSubscriptionProfiles, "a subscription profile may carry env: — just not the Anthropic binding keys"); @@ -1693,7 +1693,7 @@ class BridgedConfigTest { env: ANTHROPIC_BASE_URL: http://something """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertDoesNotThrow(cfg::validateSubscriptionProfiles, "only subscription:true profiles are checked — off-subscription ones keep the baseUrl guard"); @@ -1717,7 +1717,7 @@ class BridgedConfigTest { baseUrl: http://gx00.gw:8000 """); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("'workers' is now 'profiles'"), "the error must name the replacement key, not just say the key is wrong: " + e.getMessage()); } @@ -1735,7 +1735,7 @@ class BridgedConfigTest { profile: gx10 """); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> BridgedConfig.load(f)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> FleetConfig.load(f)); assertTrue(e.getMessage().contains("'architects' is now 'fleet.architects'"), e.getMessage()); assertTrue(e.getMessage().contains("'defaultWorker' is now a role pool"), e.getMessage()); assertTrue(e.getMessage().contains("'workers' is now 'profiles'"), e.getMessage()); @@ -1759,7 +1759,7 @@ class BridgedConfigTest { profile: gx10 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertDoesNotThrow(cfg::validateMembers); assertEquals("opus", cfg.fleet().pool(MemberRole.ARCHITECT).get("architect-1").profile()); assertEquals("gx10", cfg.fleet().pool(MemberRole.REVIEWER).get("reviewer-1").profile()); @@ -1787,7 +1787,7 @@ class BridgedConfigTest { profile: gx10 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertDoesNotThrow(cfg::validateMembers); assertEquals(cfg.fleet().pool(MemberRole.DEV).get("dev-1").profile(), cfg.fleet().pool(MemberRole.REVIEWER).get("reviewer-1").profile(), @@ -1815,7 +1815,7 @@ class BridgedConfigTest { profile: gx10 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertDoesNotThrow(cfg::validateMembers); assertTrue(cfg.fleet().rolesConfigured().isEmpty(), "a pool name that is not a role declares nothing at all"); @@ -1845,7 +1845,7 @@ class BridgedConfigTest { slot-1: {} """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); IllegalStateException e = assertThrows(IllegalStateException.class, cfg::validateMembers); assertTrue(e.getMessage().contains("fleet.developers.slot-1"), e.getMessage()); assertTrue(e.getMessage().contains("has no profile:"), e.getMessage()); @@ -1863,7 +1863,7 @@ class BridgedConfigTest { baseUrl: http://gx01.gw:8000 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertEquals("gx10", cfg.profiles().get("gx10").profile(), "a profile that names no profile: field is defaulted to its map key"); assertEquals("explicitly-set", cfg.profiles().get("terra").profile(), @@ -1883,7 +1883,7 @@ class BridgedConfigTest { baseUrl: http://gx01.gw:8000 """); - BridgedConfig cfg = BridgedConfig.load(f); + FleetConfig cfg = FleetConfig.load(f); assertTrue(cfg.fleet().profilesFor(MemberRole.DEV).isEmpty(), "no dev pool is configured"); assertEquals("gx10", cfg.effectiveDefaultProfile(), "with no pool to choose from, every configured profile is a candidate and the " diff --git a/bridged/src/test/java/dev/ltms/bridged/guard/SubscriptionGuardTest.java b/bridged/src/test/java/dev/ltms/fleet/guard/SubscriptionGuardTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/guard/SubscriptionGuardTest.java rename to bridged/src/test/java/dev/ltms/fleet/guard/SubscriptionGuardTest.java index ca58f52..26c0a9f 100644 --- a/bridged/src/test/java/dev/ltms/bridged/guard/SubscriptionGuardTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/guard/SubscriptionGuardTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.guard; +package dev.ltms.fleet.guard; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/health/FleetHealthMonitorTest.java b/bridged/src/test/java/dev/ltms/fleet/health/FleetHealthMonitorTest.java similarity index 92% rename from bridged/src/test/java/dev/ltms/bridged/health/FleetHealthMonitorTest.java rename to bridged/src/test/java/dev/ltms/fleet/health/FleetHealthMonitorTest.java index 28c53e2..cea9824 100644 --- a/bridged/src/test/java/dev/ltms/bridged/health/FleetHealthMonitorTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/health/FleetHealthMonitorTest.java @@ -1,19 +1,19 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.inject.Injector; -import dev.ltms.bridged.msg.InMemoryReplyInbox; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.member.ClaudeCodeLauncher; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.config.BridgedConfig; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.inject.Injector; +import dev.ltms.fleet.msg.InMemoryReplyInbox; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.member.ClaudeCodeLauncher; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.config.FleetConfig; import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; @@ -29,7 +29,7 @@ class FleetHealthMonitorTest { @Test void oneTickUsesOneFleetListForAnyRosterSize() { FakeHerdr herdr = new FakeHerdr(); AgentControl agents = new AgentControl(herdr); - BridgedConfig.Profile profile = new BridgedConfig.Profile("test", "http://test:1", null, + FleetConfig.Profile profile = new FleetConfig.Profile("test", "http://test:1", null, null, null, null, null, null, null, null, null, null); ClaudeCodeLauncher launcher = new ClaudeCodeLauncher(agents, new WorkspaceControl(herdr), new SubscriptionGuard(Set.of("test")), Map.of("test", profile), "test", _ -> "token"); diff --git a/bridged/src/test/java/dev/ltms/bridged/health/FleetHealthTest.java b/bridged/src/test/java/dev/ltms/fleet/health/FleetHealthTest.java similarity index 93% rename from bridged/src/test/java/dev/ltms/bridged/health/FleetHealthTest.java rename to bridged/src/test/java/dev/ltms/fleet/health/FleetHealthTest.java index 6cc2e55..8ff0994 100644 --- a/bridged/src/test/java/dev/ltms/bridged/health/FleetHealthTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/health/FleetHealthTest.java @@ -1,8 +1,8 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.session.MemberSession; -import dev.ltms.bridged.msg.Rendezvous; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.session.MemberSession; +import dev.ltms.fleet.msg.Rendezvous; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/bridged/src/test/java/dev/ltms/bridged/health/PaneBudgetTest.java b/bridged/src/test/java/dev/ltms/fleet/health/PaneBudgetTest.java similarity index 93% rename from bridged/src/test/java/dev/ltms/bridged/health/PaneBudgetTest.java rename to bridged/src/test/java/dev/ltms/fleet/health/PaneBudgetTest.java index 162ec20..8dc1b2b 100644 --- a/bridged/src/test/java/dev/ltms/bridged/health/PaneBudgetTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/health/PaneBudgetTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.health; +package dev.ltms.fleet.health; import org.junit.jupiter.api.Test; import java.util.List; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/AgentControlContractTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/AgentControlContractTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/herdr/AgentControlContractTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/AgentControlContractTest.java index d5b5fec..5ced79c 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/AgentControlContractTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/AgentControlContractTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/AgentControlTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/AgentControlTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/herdr/AgentControlTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/AgentControlTest.java index 023c0ea..15b5845 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/AgentControlTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/AgentControlTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/AgentStatusTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/AgentStatusTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/herdr/AgentStatusTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/AgentStatusTest.java index 364e3f4..4bb724b 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/AgentStatusTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/AgentStatusTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/FakeHerdr.java b/bridged/src/test/java/dev/ltms/fleet/herdr/FakeHerdr.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/herdr/FakeHerdr.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/FakeHerdr.java index 3da81cb..27b5af2 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/FakeHerdr.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/FakeHerdr.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -24,7 +24,7 @@ public final class FakeHerdr implements HerdrClient { private final ObjectMapper mapper = new ObjectMapper(); /** - * Thread-safe on purpose. Background loops — {@link dev.ltms.bridged.msg.ReplyPushLoop} and the + * Thread-safe on purpose. Background loops — {@link dev.ltms.fleet.msg.ReplyPushLoop} and the * lead heartbeat — call this fake from their own scheduler threads while a test polls * {@link #called} from the test thread. A plain {@code ArrayList} threw * {@code ConcurrentModificationException} out of {@code called()} when a nudge landed mid-stream. diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/HerdrCodecTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/HerdrCodecTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/herdr/HerdrCodecTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/HerdrCodecTest.java index b680c20..75335ca 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/HerdrCodecTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/HerdrCodecTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/HerdrContractTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/HerdrContractTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/herdr/HerdrContractTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/HerdrContractTest.java index fcc7141..b0278af 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/HerdrContractTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/HerdrContractTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import org.junit.jupiter.api.Tag; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/LeadTabScannerTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/LeadTabScannerTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/herdr/LeadTabScannerTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/LeadTabScannerTest.java index b06c405..f581806 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/LeadTabScannerTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/LeadTabScannerTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/PaneLocatorContractTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/PaneLocatorContractTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/herdr/PaneLocatorContractTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/PaneLocatorContractTest.java index d391948..1ffcd1a 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/PaneLocatorContractTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/PaneLocatorContractTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import org.junit.jupiter.api.Tag; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/PaneLocatorTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/PaneLocatorTest.java similarity index 95% rename from bridged/src/test/java/dev/ltms/bridged/herdr/PaneLocatorTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/PaneLocatorTest.java index 54262d4..7b01877 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/PaneLocatorTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/PaneLocatorTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/herdr/WorkspacePlacementContractTest.java b/bridged/src/test/java/dev/ltms/fleet/herdr/WorkspacePlacementContractTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/herdr/WorkspacePlacementContractTest.java rename to bridged/src/test/java/dev/ltms/fleet/herdr/WorkspacePlacementContractTest.java index 6a6e373..40d46e9 100644 --- a/bridged/src/test/java/dev/ltms/bridged/herdr/WorkspacePlacementContractTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/herdr/WorkspacePlacementContractTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.herdr; +package dev.ltms.fleet.herdr; import com.fasterxml.jackson.databind.JsonNode; import org.junit.jupiter.api.Tag; diff --git a/bridged/src/test/java/dev/ltms/bridged/inject/CompletionResolverTest.java b/bridged/src/test/java/dev/ltms/fleet/inject/CompletionResolverTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/inject/CompletionResolverTest.java rename to bridged/src/test/java/dev/ltms/fleet/inject/CompletionResolverTest.java index b22be4d..388a49b 100644 --- a/bridged/src/test/java/dev/ltms/bridged/inject/CompletionResolverTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/inject/CompletionResolverTest.java @@ -1,14 +1,14 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.msg.TestTurnTokens; -import dev.ltms.bridged.msg.TurnToken; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.msg.TestTurnTokens; +import dev.ltms.fleet.msg.TurnToken; import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; diff --git a/bridged/src/test/java/dev/ltms/bridged/inject/InjectorTest.java b/bridged/src/test/java/dev/ltms/fleet/inject/InjectorTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/inject/InjectorTest.java rename to bridged/src/test/java/dev/ltms/fleet/inject/InjectorTest.java index fddd39a..54d87fe 100644 --- a/bridged/src/test/java/dev/ltms/bridged/inject/InjectorTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/inject/InjectorTest.java @@ -1,14 +1,14 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.HerdrException; -import dev.ltms.bridged.msg.TestTurnTokens; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.HerdrException; +import dev.ltms.fleet.msg.TestTurnTokens; import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; diff --git a/bridged/src/test/java/dev/ltms/bridged/inject/MemberPresenceTest.java b/bridged/src/test/java/dev/ltms/fleet/inject/MemberPresenceTest.java similarity index 96% rename from bridged/src/test/java/dev/ltms/bridged/inject/MemberPresenceTest.java rename to bridged/src/test/java/dev/ltms/fleet/inject/MemberPresenceTest.java index b9a6efa..c45e30e 100644 --- a/bridged/src/test/java/dev/ltms/bridged/inject/MemberPresenceTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/inject/MemberPresenceTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/inject/StatusRefinerTest.java b/bridged/src/test/java/dev/ltms/fleet/inject/StatusRefinerTest.java similarity index 95% rename from bridged/src/test/java/dev/ltms/bridged/inject/StatusRefinerTest.java rename to bridged/src/test/java/dev/ltms/fleet/inject/StatusRefinerTest.java index 392e311..7034bea 100644 --- a/bridged/src/test/java/dev/ltms/bridged/inject/StatusRefinerTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/inject/StatusRefinerTest.java @@ -1,8 +1,8 @@ -package dev.ltms.bridged.inject; +package dev.ltms.fleet.inject; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.herdr.FakeHerdr; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/bridged/src/test/java/dev/ltms/bridged/lead/LeadLauncherTest.java b/bridged/src/test/java/dev/ltms/fleet/lead/LeadLauncherTest.java similarity index 91% rename from bridged/src/test/java/dev/ltms/bridged/lead/LeadLauncherTest.java rename to bridged/src/test/java/dev/ltms/fleet/lead/LeadLauncherTest.java index c87b788..7df86c6 100644 --- a/bridged/src/test/java/dev/ltms/bridged/lead/LeadLauncherTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/lead/LeadLauncherTest.java @@ -1,9 +1,9 @@ -package dev.ltms.bridged.lead; +package dev.ltms.fleet.lead; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; import org.junit.jupiter.api.Test; import java.util.LinkedHashMap; @@ -22,8 +22,8 @@ import static org.junit.jupiter.api.Assertions.*; class LeadLauncherTest { /** The lead's backend: a subscription profile with the bridge mounted, as `opus` really is. */ - private static BridgedConfig.Profile opusProfile() { - return new BridgedConfig.Profile( + private static FleetConfig.Profile opusProfile() { + return new FleetConfig.Profile( "opus", null, "claude-opus-5", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms"), "tab", "bridged-workers", null, "http://127.0.0.1:8765/mcp", null, null, @@ -31,22 +31,22 @@ class LeadLauncherTest { Map.of("CLAUDE_CODE_AUTO_COMPACT_WINDOW", "300000"), null, null, true, null); } - private static BridgedConfig configWith(BridgedConfig.Leader lead) { - Map leaders = new LinkedHashMap<>(); + private static FleetConfig configWith(FleetConfig.Leader lead) { + Map leaders = new LinkedHashMap<>(); leaders.put("opus", lead); - BridgedConfig.Fleet fleet = - new BridgedConfig.Fleet(leaders, Map.of(), Map.of(), Map.of(), null); - return new BridgedConfig( + FleetConfig.Fleet fleet = + new FleetConfig.Fleet(leaders, Map.of(), Map.of(), Map.of(), null); + return new FleetConfig( null, null, Map.of("opus", opusProfile()), null, null, null, null, null, null, null, fleet, null, "fixed", null).withDefaults(); } - private static BridgedConfig.Leader lead(String profile, String tab, int instances) { - return new BridgedConfig.Leader(profile, tab, instances, "lead:", 10, null, null, + private static FleetConfig.Leader lead(String profile, String tab, int instances) { + return new FleetConfig.Leader(profile, tab, instances, "lead:", 10, null, null, "leads", "/repo"); } - private static LeadLauncher launcher(FakeHerdr herdr, BridgedConfig cfg) { + private static LeadLauncher launcher(FakeHerdr herdr, FleetConfig cfg) { return new LeadLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), cfg); } @@ -179,7 +179,7 @@ class LeadLauncherTest { /** It still mounts the bridge — a lead that cannot orchestrate is pointless. */ @Test - void theLeadMountsTheBridgeMcpAndPinsItsModel() { + void theLeadMountsTheFleetMcpAndPinsItsModel() { FakeHerdr herdr = new FakeHerdr(); launcher(herdr, configWith(lead("opus", "lead: opus", 1))).ensureLeads(); @@ -248,7 +248,7 @@ class LeadLauncherTest { @Test void noLeadersConfiguredTouchesHerdrNotAtAll() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig cfg = new BridgedConfig( + FleetConfig cfg = new FleetConfig( null, null, Map.of("opus", opusProfile()), null, null, null, null, null, null, null, null, null, "fixed", null).withDefaults(); diff --git a/bridged/src/test/java/dev/ltms/bridged/logging/McpCancelledNotificationFilterTest.java b/bridged/src/test/java/dev/ltms/fleet/logging/McpCancelledNotificationFilterTest.java similarity index 97% rename from bridged/src/test/java/dev/ltms/bridged/logging/McpCancelledNotificationFilterTest.java rename to bridged/src/test/java/dev/ltms/fleet/logging/McpCancelledNotificationFilterTest.java index ef205bc..e48af71 100644 --- a/bridged/src/test/java/dev/ltms/bridged/logging/McpCancelledNotificationFilterTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/logging/McpCancelledNotificationFilterTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.logging; +package dev.ltms.fleet.logging; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; diff --git a/bridged/src/test/java/dev/ltms/bridged/mcp/ConnectionIdentityTest.java b/bridged/src/test/java/dev/ltms/fleet/mcp/ConnectionIdentityTest.java similarity index 93% rename from bridged/src/test/java/dev/ltms/bridged/mcp/ConnectionIdentityTest.java rename to bridged/src/test/java/dev/ltms/fleet/mcp/ConnectionIdentityTest.java index cad86d4..20d6c0f 100644 --- a/bridged/src/test/java/dev/ltms/bridged/mcp/ConnectionIdentityTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/mcp/ConnectionIdentityTest.java @@ -1,7 +1,7 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.PaneLocator; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.PaneLocator; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; diff --git a/bridged/src/test/java/dev/ltms/bridged/mcp/BridgeMcpAuthzTest.java b/bridged/src/test/java/dev/ltms/fleet/mcp/FleetMcpAuthzTest.java similarity index 65% rename from bridged/src/test/java/dev/ltms/bridged/mcp/BridgeMcpAuthzTest.java rename to bridged/src/test/java/dev/ltms/fleet/mcp/FleetMcpAuthzTest.java index 523137d..f308418 100644 --- a/bridged/src/test/java/dev/ltms/bridged/mcp/BridgeMcpAuthzTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/mcp/FleetMcpAuthzTest.java @@ -1,25 +1,25 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; -import dev.ltms.bridged.auth.Authz; -import dev.ltms.bridged.auth.CallerResolver; -import dev.ltms.bridged.auth.MemberRegistry; -import dev.ltms.bridged.auth.Principal; -import dev.ltms.bridged.auth.Role; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.PaneLocator; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.inject.Injector; -import dev.ltms.bridged.metrics.BridgedMetrics; -import dev.ltms.bridged.metrics.Metrics; -import dev.ltms.bridged.msg.InMemoryReplyInbox; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.session.FakeWorktrees; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.member.ClaudeCodeLauncher; +import dev.ltms.fleet.auth.Authz; +import dev.ltms.fleet.auth.CallerResolver; +import dev.ltms.fleet.auth.MemberRegistry; +import dev.ltms.fleet.auth.Principal; +import dev.ltms.fleet.auth.Role; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.PaneLocator; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.inject.Injector; +import dev.ltms.fleet.metrics.FleetMetrics; +import dev.ltms.fleet.metrics.Metrics; +import dev.ltms.fleet.msg.InMemoryReplyInbox; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.session.FakeWorktrees; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.member.ClaudeCodeLauncher; import io.modelcontextprotocol.spec.McpSchema; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -33,30 +33,30 @@ import static org.junit.jupiter.api.Assertions.*; * CB-513 — the CB-505 authorization gate on the MCP entry path. * *

      Why this file exists: CB-505 claimed authorization is "enforced on both entry paths", and it - * is — but only REST was ever tested ({@code BridgedAppAuthTest}). Coverage showed - * {@code BridgeMcp.deny()}, {@code principal()} and every tool-registration lambda at zero - * executed lines, because no test had ever constructed a {@code BridgeMcp} — the existing - * {@code BridgeMcpTest} calls only the static handler methods. An unexercised security control is + * is — but only REST was ever tested ({@code FleetAppAuthTest}). Coverage showed + * {@code FleetMcp.deny()}, {@code principal()} and every tool-registration lambda at zero + * executed lines, because no test had ever constructed a {@code FleetMcp} — the existing + * {@code FleetMcpTest} calls only the static handler methods. An unexercised security control is * a claim, not a control. * - *

      These tests construct a real {@code BridgeMcp} (which also exercises the constructor and the + *

      These tests construct a real {@code FleetMcp} (which also exercises the constructor and the * tool wiring) and drive the policy half of the gate directly. */ -class BridgeMcpAuthzTest { +class FleetMcpAuthzTest { private final FakeHerdr herdr = new FakeHerdr(); private final AgentControl agents = new AgentControl(herdr); private Metrics metrics; - private BridgeMcp mcp; + private FleetMcp mcp; @AfterEach void close() { if (mcp != null) mcp.close(); } - /** A fully wired BridgeMcp on fakes — constructing it is itself part of what is under test. */ - private BridgeMcp mcp(boolean enforce) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + /** A fully wired FleetMcp on fakes — constructing it is itself part of what is under test. */ + private FleetMcp mcp(boolean enforce) { + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", null, "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); ClaudeCodeLauncher workers = new ClaudeCodeLauncher(agents, new WorkspaceControl(herdr), @@ -66,14 +66,14 @@ class BridgeMcpAuthzTest { MessageService messages = new MessageService(agents, new Injector(agents), new Rendezvous(), new InMemoryReplyInbox()); ConnectionIdentity identity = new ConnectionIdentity(new PaneLocator(herdr), _ -> 999_999); - metrics = BridgedMetrics.create(sessions, new InMemoryReplyInbox()); + metrics = FleetMetrics.create(sessions, new InMemoryReplyInbox()); - mcp = new BridgeMcp(messages, workers, sessions, identity, sessions.asPresence(), + mcp = new FleetMcp(messages, workers, sessions, identity, sessions.asPresence(), new PrimaryRegistry(null), enforce ? CallerResolver.withLeadsAndMembers(identity, false, null, Map::of, new MemberRegistry(null)) : null, - metrics, BridgeMcp.CapacitySource.none(), new BridgeMcp.HealthCoverageSource(() -> "off"), - BridgeMcp.QuarantineSource.none()); + metrics, FleetMcp.CapacitySource.none(), new FleetMcp.HealthCoverageSource(() -> "off"), + FleetMcp.QuarantineSource.none()); return mcp; } @@ -86,7 +86,7 @@ class BridgeMcpAuthzTest { @Test void primaryMayOrchestrate() { - BridgeMcp m = mcp(true); + FleetMcp m = mcp(true); for (Authz.Action a : new Authz.Action[]{Authz.Action.SPAWN, Authz.Action.STOP, Authz.Action.SEND, Authz.Action.DRAIN, Authz.Action.READ}) { assertNull(m.denyFor(PRIMARY, a, "term_a"), a + " is the primary's to perform"); @@ -95,7 +95,7 @@ class BridgeMcpAuthzTest { @Test void aWorkerMayNotOrchestrateOverMcp() { - BridgeMcp m = mcp(true); + FleetMcp m = mcp(true); for (Authz.Action a : new Authz.Action[]{Authz.Action.SPAWN, Authz.Action.STOP, Authz.Action.SEND, Authz.Action.DRAIN}) { McpSchema.CallToolResult denied = m.denyFor(WORKER_A, a, "term_a"); @@ -106,7 +106,7 @@ class BridgeMcpAuthzTest { @Test void aWorkerMayReplyAndAskOnlyAsItself() { - BridgeMcp m = mcp(true); + FleetMcp m = mcp(true); assertNull(m.denyFor(WORKER_A, Authz.Action.REPLY, "term_a"), "its own session is allowed"); assertNull(m.denyFor(WORKER_A, Authz.Action.ASK, "term_a")); @@ -117,7 +117,7 @@ class BridgeMcpAuthzTest { @Test void thePrimaryMayNotForgeAWorkerReplyOverMcp() { - BridgeMcp m = mcp(true); + FleetMcp m = mcp(true); // A forged reply would resolve the very rendezvous the primary is blocked on. assertNotNull(m.denyFor(PRIMARY, Authz.Action.REPLY, "term_a")); assertNotNull(m.denyFor(PRIMARY, Authz.Action.ASK, "term_a")); @@ -127,7 +127,7 @@ class BridgeMcpAuthzTest { @Test void anArchitectMaySendAndReadButNotOrchestrateOverMcp() { - BridgeMcp m = mcp(true); + FleetMcp m = mcp(true); assertNull(m.denyFor(ARCH_DESIGN, Authz.Action.SEND, "term_a"), "delegating a turn is the architect's job"); assertNull(m.denyFor(ARCH_DESIGN, Authz.Action.READ, null)); @@ -142,7 +142,7 @@ class BridgeMcpAuthzTest { @Test void anArchitectMayReplyAndAskOnlyAsItsOwnPaneOverMcp() { - BridgeMcp m = mcp(true); + FleetMcp m = mcp(true); assertNull(m.denyFor(ARCH_DESIGN, Authz.Action.REPLY, "term_design")); assertNull(m.denyFor(ARCH_DESIGN, Authz.Action.ASK, "term_design")); @@ -152,29 +152,29 @@ class BridgeMcpAuthzTest { @Test void anonymousIsRefusedEverythingAndCountedAsUnauthenticated() { - BridgeMcp m = mcp(true); + FleetMcp m = mcp(true); McpSchema.CallToolResult denied = m.denyFor(ANON, Authz.Action.READ, null); assertNotNull(denied, "authenticated as nothing ⇒ authorized for nothing"); - assertEquals(1, metrics.count(BridgedMetrics.AUTH_FAILURES, "reason", "unauthenticated")); - assertEquals(0, metrics.count(BridgedMetrics.AUTH_FAILURES, "reason", "forbidden"), + assertEquals(1, metrics.count(FleetMetrics.AUTH_FAILURES, "reason", "unauthenticated")); + assertEquals(0, metrics.count(FleetMetrics.AUTH_FAILURES, "reason", "forbidden"), "a missing credential is 401-shaped, not 403-shaped"); } @Test void aWrongRoleIsCountedAsForbiddenNotUnauthenticated() { - BridgeMcp m = mcp(true); + FleetMcp m = mcp(true); assertNotNull(m.denyFor(WORKER_A, Authz.Action.SPAWN, null)); - assertEquals(1, metrics.count(BridgedMetrics.AUTH_FAILURES, "reason", "forbidden")); - assertEquals(0, metrics.count(BridgedMetrics.AUTH_FAILURES, "reason", "unauthenticated"), + assertEquals(1, metrics.count(FleetMetrics.AUTH_FAILURES, "reason", "forbidden")); + assertEquals(0, metrics.count(FleetMetrics.AUTH_FAILURES, "reason", "unauthenticated"), "the caller IS authenticated — it is just not the right role"); } @Test void theLegacyConstructorLeavesTheGateOpen() { - // The 22 pre-existing BridgeMcpTest cases rely on no authorization being enforced. - BridgeMcp m = mcp(false); + // The 22 pre-existing FleetMcpTest cases rely on no authorization being enforced. + FleetMcp m = mcp(false); assertNull(m.denyFor(ANON, Authz.Action.SPAWN, null), "no CallerResolver supplied ⇒ authorization not enforced (legacy behaviour)"); } @@ -183,12 +183,12 @@ class BridgeMcpAuthzTest { @Test void principalIsRebuiltFromTheStashedRole() { - assertEquals(Role.WORKER, BridgeMcp.principalFrom("WORKER", "term_a", 7).role()); - assertEquals("term_a", BridgeMcp.principalFrom("WORKER", "term_a", 7).terminal()); - assertEquals(Role.PRIMARY, BridgeMcp.principalFrom("PRIMARY", null, 7).role()); - assertEquals(Role.ANONYMOUS, BridgeMcp.principalFrom("ANONYMOUS", null, -1).role()); + assertEquals(Role.WORKER, FleetMcp.principalFrom("WORKER", "term_a", 7).role()); + assertEquals("term_a", FleetMcp.principalFrom("WORKER", "term_a", 7).terminal()); + assertEquals(Role.PRIMARY, FleetMcp.principalFrom("PRIMARY", null, 7).role()); + assertEquals(Role.ANONYMOUS, FleetMcp.principalFrom("ANONYMOUS", null, -1).role()); // CB-548: an architect round-trips through the same stash, carrying its slot name. - Principal arch = BridgeMcp.principalFrom("ARCHITECT", "term_design", 7, "lead-designer"); + Principal arch = FleetMcp.principalFrom("ARCHITECT", "term_design", 7, "lead-designer"); assertEquals(Role.ARCHITECT, arch.role()); assertEquals("lead-designer", arch.name()); assertEquals("term_design", arch.terminal()); @@ -198,7 +198,7 @@ class BridgeMcpAuthzTest { void aMissingRoleFallsBackToTheHistoricalInterpretation() { // Legacy path: no role stashed. A terminal means worker; its absence meant "the primary", // which is exactly the pre-CB-501 default CB-501 inverted — preserved only here. - assertEquals(Role.WORKER, BridgeMcp.principalFrom(null, "term_a", 7).role()); - assertEquals(Role.PRIMARY, BridgeMcp.principalFrom(null, null, 7).role()); + assertEquals(Role.WORKER, FleetMcp.principalFrom(null, "term_a", 7).role()); + assertEquals(Role.PRIMARY, FleetMcp.principalFrom(null, null, 7).role()); } } diff --git a/bridged/src/test/java/dev/ltms/bridged/mcp/BridgeMcpTest.java b/bridged/src/test/java/dev/ltms/fleet/mcp/FleetMcpTest.java similarity index 80% rename from bridged/src/test/java/dev/ltms/bridged/mcp/BridgeMcpTest.java rename to bridged/src/test/java/dev/ltms/fleet/mcp/FleetMcpTest.java index 588c1be..f522887 100644 --- a/bridged/src/test/java/dev/ltms/bridged/mcp/BridgeMcpTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/mcp/FleetMcpTest.java @@ -1,27 +1,27 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; -import dev.ltms.bridged.auth.Principal; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.inject.Injector; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.session.FakeWorktrees; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.inject.MemberPresence; -import dev.ltms.bridged.session.MemberSession; -import dev.ltms.bridged.session.WorktreeRequest; -import dev.ltms.bridged.member.ClaudeCodeLauncher; -import dev.ltms.bridged.member.CompositePeerLauncher; -import dev.ltms.bridged.placement.BackendQuarantine; -import dev.ltms.bridged.placement.PlacementPolicies; +import dev.ltms.fleet.auth.Principal; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.inject.Injector; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.session.FakeWorktrees; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.inject.MemberPresence; +import dev.ltms.fleet.session.MemberSession; +import dev.ltms.fleet.session.WorktreeRequest; +import dev.ltms.fleet.member.ClaudeCodeLauncher; +import dev.ltms.fleet.member.CompositePeerLauncher; +import dev.ltms.fleet.placement.BackendQuarantine; +import dev.ltms.fleet.placement.PlacementPolicies; import io.modelcontextprotocol.server.McpSyncServerExchange; import io.modelcontextprotocol.spec.McpSchema; -import dev.ltms.bridged.msg.InMemoryReplyInbox; +import dev.ltms.fleet.msg.InMemoryReplyInbox; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; @@ -45,7 +45,7 @@ import static org.junit.jupiter.api.Assertions.*; * since both drive the same {@link MessageService}/{@link Rendezvous}. The MCP wire protocol itself * is the SDK's concern; here we test the thin adapter logic directly. */ -class BridgeMcpTest { +class FleetMcpTest { private static final String T = "term_a"; @@ -67,18 +67,18 @@ class BridgeMcpTest { private void assertSendRoundTrips(String target, Set profiles) throws Exception { CompletableFuture send = CompletableFuture.supplyAsync( - () -> BridgeMcp.send(messages, target, "hi", 4000L, null, profiles)); + () -> FleetMcp.send(messages, target, "hi", 4000L, null, profiles)); long deadline = System.currentTimeMillis() + 3000; while (!rendezvous.isWaiting(target) && System.currentTimeMillis() < deadline) { Thread.sleep(5); } assertTrue(rendezvous.isWaiting(target), "send should be accepted for " + target); - BridgeMcp.reply(messages, target, "received"); + FleetMcp.reply(messages, target, "received"); assertEquals("received", textOf(send.get(6, TimeUnit.SECONDS))); } private static ClaudeCodeLauncher workerService(FakeHerdr h, String baseUrl, Set allow) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", baseUrl, "coder", null, "BRIDGED_WORKER_TOKEN", null, "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); return new ClaudeCodeLauncher(new AgentControl(h), new WorkspaceControl(h), @@ -93,7 +93,7 @@ class BridgeMcpTest { void sendThenReplyRoundTrips() throws Exception { // fleet_send blocks; fleet_reply resolves it with the worker's structured answer. CompletableFuture send = CompletableFuture.supplyAsync( - () -> BridgeMcp.send(messages, "term_a", "review this", 4000L, null, Set.of())); + () -> FleetMcp.send(messages, "term_a", "review this", 4000L, null, Set.of())); // Wait until the send has opened its waiter so the reply resolves it (CB-307: reply now // queues in the inbox if no waiter is open, which would break the round-trip). @@ -104,7 +104,7 @@ class BridgeMcpTest { } assertTrue(rendezvous.isWaiting("term_a"), "send should have opened its waiter"); - McpSchema.CallToolResult reply = BridgeMcp.reply(messages, "term_a", "LGTM"); + McpSchema.CallToolResult reply = FleetMcp.reply(messages, "term_a", "LGTM"); assertEquals("delivered", textOf(reply)); McpSchema.CallToolResult res = send.get(6, TimeUnit.SECONDS); @@ -115,7 +115,7 @@ class BridgeMcpTest { @Test void asyncSendReturnsATicketThenPollReportsTheReply() throws Exception { // wait:false parity — a ticket is issued, resolved by a reply, and surfaced by fleet_poll. - McpSchema.CallToolResult accepted = BridgeMcp.sendAsync(messages, "term_a", "do it", null, Set.of()); + McpSchema.CallToolResult accepted = FleetMcp.sendAsync(messages, "term_a", "do it", null, Set.of()); assertNotEquals(Boolean.TRUE, accepted.isError()); String out = textOf(accepted); assertTrue(out.contains("ticket="), out); @@ -130,23 +130,23 @@ class BridgeMcpTest { } assertTrue(rendezvous.isWaiting("term_a"), "send should have opened its waiter"); - McpSchema.CallToolResult reply = BridgeMcp.reply(messages, "term_a", "async LGTM"); + McpSchema.CallToolResult reply = FleetMcp.reply(messages, "term_a", "async LGTM"); assertEquals("delivered", textOf(reply)); // Poll until the async send completes and reports the reply. - McpSchema.CallToolResult polled = BridgeMcp.poll(messages, ticket, null); + McpSchema.CallToolResult polled = FleetMcp.poll(messages, ticket, null); deadline = System.currentTimeMillis() + 3000; while (!textOf(polled).contains("async LGTM") && System.currentTimeMillis() < deadline) { //noinspection BusyWait Thread.sleep(10); - polled = BridgeMcp.poll(messages, ticket, null); + polled = FleetMcp.poll(messages, ticket, null); } assertEquals("async LGTM", textOf(polled)); } @Test void asyncSendSurfacesAnAskThenKeepsTheTicketForTheFinalReply() throws Exception { - McpSchema.CallToolResult accepted = BridgeMcp.sendAsync(messages, "term_a", "do it", null, Set.of()); + McpSchema.CallToolResult accepted = FleetMcp.sendAsync(messages, "term_a", "do it", null, Set.of()); String ticket = textOf(accepted).substring(textOf(accepted).indexOf("ticket=") + "ticket=".length()).trim(); long deadline = System.currentTimeMillis() + 3000; @@ -156,12 +156,12 @@ class BridgeMcpTest { assertTrue(rendezvous.isWaiting("term_a")); CompletableFuture ask = CompletableFuture.supplyAsync( - () -> BridgeMcp.ask(messages, "term_a", "which config?", 5000L)); - McpSchema.CallToolResult question = BridgeMcp.poll(messages, ticket, null); + () -> FleetMcp.ask(messages, "term_a", "which config?", 5000L)); + McpSchema.CallToolResult question = FleetMcp.poll(messages, ticket, null); deadline = System.currentTimeMillis() + 3000; while (!textOf(question).contains("[question") && System.currentTimeMillis() < deadline) { Thread.sleep(5); - question = BridgeMcp.poll(messages, ticket, null); + question = FleetMcp.poll(messages, ticket, null); } assertTrue(textOf(question).contains("which config?"), textOf(question)); String questionText = textOf(question); @@ -169,7 +169,7 @@ class BridgeMcpTest { String turnId = afterTurnId.substring(0, afterTurnId.indexOf('"')); CompletableFuture answer = CompletableFuture.supplyAsync( - () -> BridgeMcp.answer(messages, turnId, "config.yaml", 5000L)); + () -> FleetMcp.answer(messages, turnId, "config.yaml", 5000L)); assertEquals("config.yaml", textOf(ask.get(6, TimeUnit.SECONDS))); deadline = System.currentTimeMillis() + 3000; @@ -177,21 +177,21 @@ class BridgeMcpTest { Thread.sleep(5); } assertTrue(rendezvous.isWaiting("term_a")); - BridgeMcp.reply(messages, "term_a", "done"); + FleetMcp.reply(messages, "term_a", "done"); assertEquals("done", textOf(answer.get(6, TimeUnit.SECONDS))); - McpSchema.CallToolResult done = BridgeMcp.poll(messages, ticket, null); + McpSchema.CallToolResult done = FleetMcp.poll(messages, ticket, null); deadline = System.currentTimeMillis() + 3000; while (!"done".equals(textOf(done)) && System.currentTimeMillis() < deadline) { Thread.sleep(5); - done = BridgeMcp.poll(messages, ticket, null); + done = FleetMcp.poll(messages, ticket, null); } assertEquals("done", textOf(done)); } @Test void unansweredAsyncAskReturnsTheTicketToPending() throws Exception { - McpSchema.CallToolResult accepted = BridgeMcp.sendAsync(messages, "term_a", "do it", null, Set.of()); + McpSchema.CallToolResult accepted = FleetMcp.sendAsync(messages, "term_a", "do it", null, Set.of()); String ticket = textOf(accepted).substring(textOf(accepted).indexOf("ticket=") + "ticket=".length()).trim(); long deadline = System.currentTimeMillis() + 3000; @@ -200,11 +200,11 @@ class BridgeMcpTest { } assertTrue(rendezvous.isWaiting("term_a")); - McpSchema.CallToolResult ask = BridgeMcp.ask(messages, "term_a", "still there?", 50L); + McpSchema.CallToolResult ask = FleetMcp.ask(messages, "term_a", "still there?", 50L); assertTrue(textOf(ask).contains("no answer"), textOf(ask)); - assertTrue(textOf(BridgeMcp.poll(messages, ticket, null)).startsWith("[pending")); + assertTrue(textOf(FleetMcp.poll(messages, ticket, null)).startsWith("[pending")); - BridgeMcp.reply(messages, "term_a", "finished after timeout"); + FleetMcp.reply(messages, "term_a", "finished after timeout"); assertEquals("finished after timeout", messages.drainReplies("term_a").getFirst().content()); } @@ -226,7 +226,7 @@ class BridgeMcpTest { @Test void anotherAsyncTicketCannotCaptureAReplyWhileTheFirstTicketIsAsking() throws Exception { - McpSchema.CallToolResult firstAccepted = BridgeMcp.sendAsync(messages, "term_a", "first", null, Set.of()); + McpSchema.CallToolResult firstAccepted = FleetMcp.sendAsync(messages, "term_a", "first", null, Set.of()); String firstTicket = textOf(firstAccepted).substring(textOf(firstAccepted).indexOf("ticket=") + "ticket=".length()).trim(); long deadline = System.currentTimeMillis() + 3000; @@ -236,7 +236,7 @@ class BridgeMcpTest { assertTrue(rendezvous.isWaiting("term_a")); CompletableFuture ask = CompletableFuture.supplyAsync( - () -> BridgeMcp.ask(messages, "term_a", "which config?", 5000L)); + () -> FleetMcp.ask(messages, "term_a", "which config?", 5000L)); MessageService.TaskView first = messages.poll(firstTicket); deadline = System.currentTimeMillis() + 3000; while (first.phase() != MessageService.Phase.ASKING && System.currentTimeMillis() < deadline) { @@ -246,7 +246,7 @@ class BridgeMcpTest { assertEquals(MessageService.Phase.ASKING, first.phase()); String firstTurnId = first.turnId(); - McpSchema.CallToolResult secondAccepted = BridgeMcp.sendAsync(messages, "term_a", "second", null, Set.of()); + McpSchema.CallToolResult secondAccepted = FleetMcp.sendAsync(messages, "term_a", "second", null, Set.of()); String secondTicket = textOf(secondAccepted).substring(textOf(secondAccepted).indexOf("ticket=") + "ticket=".length()).trim(); MessageService.TaskView second = messages.poll(secondTicket); deadline = System.currentTimeMillis() + 3000; @@ -256,43 +256,43 @@ class BridgeMcpTest { } assertEquals(MessageService.Phase.FAILED, second.phase()); - BridgeMcp.reply(messages, "term_a", "late reply"); + FleetMcp.reply(messages, "term_a", "late reply"); assertEquals("late reply", messages.drainReplies("term_a").getFirst().content()); CompletableFuture answer = CompletableFuture.supplyAsync( - () -> BridgeMcp.answer(messages, firstTurnId, "config.yaml", 5000L)); + () -> FleetMcp.answer(messages, firstTurnId, "config.yaml", 5000L)); assertEquals("config.yaml", textOf(ask.get(6, TimeUnit.SECONDS))); while (!rendezvous.isWaiting("term_a") && System.currentTimeMillis() < deadline) { Thread.sleep(5); } - BridgeMcp.reply(messages, "term_a", "done"); + FleetMcp.reply(messages, "term_a", "done"); assertEquals("done", textOf(answer.get(6, TimeUnit.SECONDS))); } @Test void pollUnknownTicketIsAnError() { - McpSchema.CallToolResult res = BridgeMcp.poll(messages, "task-999", null); + McpSchema.CallToolResult res = FleetMcp.poll(messages, "task-999", null); assertTrue(res.isError()); assertTrue(textOf(res).contains("unknown ticket")); } @Test void sendTimesOutWithAWorkingNote() { - McpSchema.CallToolResult res = BridgeMcp.send(messages, "term_a", "hi", 120L, null, Set.of()); + McpSchema.CallToolResult res = FleetMcp.send(messages, "term_a", "hi", 120L, null, Set.of()); assertNotEquals(Boolean.TRUE, res.isError(), "a timeout is informational, not a tool error"); assertTrue(textOf(res).contains("no reply"), "got: " + textOf(res)); } @Test void sendRejectsMissingArgs() { - assertTrue(BridgeMcp.send(messages, null, "hi", null, null, Set.of()).isError()); - assertTrue(BridgeMcp.send(messages, "term_a", " ", null, null, Set.of()).isError()); + assertTrue(FleetMcp.send(messages, null, "hi", null, null, Set.of()).isError()); + assertTrue(FleetMcp.send(messages, "term_a", " ", null, null, Set.of()).isError()); } @Test void sendRejectsAConfiguredProfileNameBeforeAcceptingIt() { - McpSchema.CallToolResult blocking = BridgeMcp.send(messages, "sol", "hi", 100L, null, Set.of("sol")); - McpSchema.CallToolResult async = BridgeMcp.sendAsync(messages, "sol", "hi", null, Set.of("sol")); + McpSchema.CallToolResult blocking = FleetMcp.send(messages, "sol", "hi", 100L, null, Set.of("sol")); + McpSchema.CallToolResult async = FleetMcp.sendAsync(messages, "sol", "hi", null, Set.of("sol")); assertTrue(blocking.isError()); assertTrue(async.isError()); @@ -310,14 +310,14 @@ class BridgeMcpTest { assertSendRoundTrips("term_live_member", profiles); // A herdr-owned pane outside the bridge roster cannot be classified at accept time. - McpSchema.CallToolResult result = BridgeMcp.send(messages, "external-pane", "hi", 10L, null, profiles); + McpSchema.CallToolResult result = FleetMcp.send(messages, "external-pane", "hi", 10L, null, profiles); assertFalse(result.isError(), "an unclassified target must not be rejected at acceptance time"); } @Test void replyWithNoPendingSendIsQueuedNotError() { // CB-307: a reply with no open send is now queued in the inbox, not an error. - McpSchema.CallToolResult res = BridgeMcp.reply(messages, "term_a", "orphan"); + McpSchema.CallToolResult res = FleetMcp.reply(messages, "term_a", "orphan"); assertNotEquals(Boolean.TRUE, res.isError(), "a queued reply is not an error"); assertEquals("delivered", textOf(res)); @@ -330,16 +330,16 @@ class BridgeMcpTest { @Test void bridgePollWithTargetDrainsReplies() { // A reply with no open send queues it in the inbox. - BridgeMcp.reply(messages, "term_a", "queued-msg"); + FleetMcp.reply(messages, "term_a", "queued-msg"); // fleet_poll with target drains the inbox. - McpSchema.CallToolResult res = BridgeMcp.poll(messages, null, "term_a"); + McpSchema.CallToolResult res = FleetMcp.poll(messages, null, "term_a"); assertNotEquals(Boolean.TRUE, res.isError()); String text = textOf(res); assertTrue(text.contains("queued-msg"), "the drained reply should appear in the result"); // Second drain returns empty. - McpSchema.CallToolResult empty = BridgeMcp.poll(messages, null, "term_a"); + McpSchema.CallToolResult empty = FleetMcp.poll(messages, null, "term_a"); assertEquals("[]", textOf(empty)); } @@ -347,7 +347,7 @@ class BridgeMcpTest { void askThenAnswerRoundTrips() throws Exception { // The primary delegates and blocks; wait until its waiter is open before the worker asks. CompletableFuture send = CompletableFuture.supplyAsync( - () -> BridgeMcp.send(messages, "term_a", "do X", 5000L, null, Set.of())); + () -> FleetMcp.send(messages, "term_a", "do X", 5000L, null, Set.of())); long deadline = System.currentTimeMillis() + 3000; while (!rendezvous.isWaiting("term_a") && System.currentTimeMillis() < deadline) { //noinspection BusyWait @@ -357,7 +357,7 @@ class BridgeMcpTest { // The worker asks mid-turn; the call blocks for the primary's answer. CompletableFuture ask = CompletableFuture.supplyAsync( - () -> BridgeMcp.ask(messages, "term_a", "which config?", 5000L)); + () -> FleetMcp.ask(messages, "term_a", "which config?", 5000L)); // The primary's send unblocks with the question and a turnId to answer on. McpSchema.CallToolResult q = send.get(6, TimeUnit.SECONDS); @@ -369,7 +369,7 @@ class BridgeMcpTest { // The primary answers via fleet_send(turnId); this blocks again for the worker's reply. CompletableFuture answer = CompletableFuture.supplyAsync( - () -> BridgeMcp.answer(messages, turnId, "config.yaml", 5000L)); + () -> FleetMcp.answer(messages, turnId, "config.yaml", 5000L)); // The worker's ask returns the answer — it resumes the same turn. assertEquals("config.yaml", textOf(ask.get(6, TimeUnit.SECONDS))); @@ -381,21 +381,21 @@ class BridgeMcpTest { Thread.sleep(5); } assertTrue(rendezvous.isWaiting("term_a"), "the answer should have reopened a waiter"); - McpSchema.CallToolResult reply = BridgeMcp.reply(messages, "term_a", "done"); + McpSchema.CallToolResult reply = FleetMcp.reply(messages, "term_a", "done"); assertEquals("delivered", textOf(reply)); assertEquals("done", textOf(answer.get(6, TimeUnit.SECONDS))); } @Test void askFromANonWorkerConnectionIsAnError() { - McpSchema.CallToolResult res = BridgeMcp.ask(messages, null, "which config?", 500L); + McpSchema.CallToolResult res = FleetMcp.ask(messages, null, "which config?", 500L); assertTrue(res.isError()); assertTrue(textOf(res).contains("workers only"), textOf(res)); } @Test void answerToAStaleTurnIsAnError() { - McpSchema.CallToolResult res = BridgeMcp.answer(messages, "term_a#999", "too late", 500L); + McpSchema.CallToolResult res = FleetMcp.answer(messages, "term_a#999", "too late", 500L); assertTrue(res.isError()); assertTrue(textOf(res).contains("no longer open"), textOf(res)); } @@ -404,7 +404,7 @@ class BridgeMcpTest { void spawnReturnsTheNewWorkersSessionAndPane() { FakeHerdr h = new FakeHerdr(); SessionManager sm = sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")); - McpSchema.CallToolResult res = BridgeMcp.spawn(sm, null); + McpSchema.CallToolResult res = FleetMcp.spawn(sm, null); assertNotEquals(Boolean.TRUE, res.isError()); String out = textOf(res); assertTrue(out.contains("\"sessionId\":\"term_new_1\""), out); @@ -419,7 +419,7 @@ class BridgeMcpTest { void spawnRejectsAnOffAllowlistProfileWithoutTouchingHerdr() { FakeHerdr h = new FakeHerdr(); McpSchema.CallToolResult res = - BridgeMcp.spawn(sessionManager(h, "https://api.anthropic.com", Set.of("gx00.gw")), null); + FleetMcp.spawn(sessionManager(h, "https://api.anthropic.com", Set.of("gx00.gw")), null); assertTrue(res.isError()); assertTrue(textOf(res).contains("subscription boundary")); assertFalse(h.called("agent.start"), "the guard must block before any spawn"); @@ -429,7 +429,7 @@ class BridgeMcpTest { void spawnRejectsAnUnknownProfileAsAnError() { FakeHerdr h = new FakeHerdr(); McpSchema.CallToolResult res = - BridgeMcp.spawn(sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), "nope"); + FleetMcp.spawn(sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), "nope"); assertTrue(res.isError()); assertTrue(textOf(res).contains("unknown worker profile"), textOf(res)); } @@ -441,11 +441,11 @@ class BridgeMcpTest { @Test void spawnAtMaxLoadSurfacesTheCapacityReason() { FakeHerdr h = new FakeHerdr(); - BridgedConfig.Profile wcfg = new BridgedConfig.Profile( + FleetConfig.Profile wcfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", null, "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null, null, null, null, null, null, 0, null, null, null); - Map profiles = Map.of(wcfg.profile(), wcfg); + Map profiles = Map.of(wcfg.profile(), wcfg); ClaudeCodeLauncher delegate = new ClaudeCodeLauncher( new AgentControl(h), new WorkspaceControl(h), new SubscriptionGuard(Set.of("gx00.gw")), profiles, wcfg.profile(), k -> "BRIDGED_WORKER_TOKEN".equals(k) ? "tok" : null); @@ -453,7 +453,7 @@ class BridgeMcpTest { List.of(delegate), wcfg.profile(), profiles, PlacementPolicies.fixed(), _ -> 0); SessionManager sm = new SessionManager(composite); - McpSchema.CallToolResult res = BridgeMcp.spawn(sm, "ltms-local"); + McpSchema.CallToolResult res = FleetMcp.spawn(sm, "ltms-local"); assertTrue(res.isError()); String text = textOf(res); @@ -466,7 +466,7 @@ class BridgeMcpTest { @Test void spawnPassesTheRequestedCwdToTheWorker() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.spawn( + McpSchema.CallToolResult res = FleetMcp.spawn( sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), null, null, "/req/dir", null, null, null, null, null); assertNotEquals(Boolean.TRUE, res.isError()); @@ -479,8 +479,8 @@ class BridgeMcpTest { @Test void profilesListsConfiguredProfilesAndDefault() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.profiles( - workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), BridgeMcp.QuarantineSource.none()); + McpSchema.CallToolResult res = FleetMcp.profiles( + workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), FleetMcp.QuarantineSource.none()); assertNotEquals(Boolean.TRUE, res.isError()); String out = textOf(res); assertTrue(out.contains("ltms-local"), out); @@ -493,9 +493,9 @@ class BridgeMcpTest { FakeHerdr h = new FakeHerdr(); BackendQuarantine quarantine = new BackendQuarantine(() -> 0L, TimeUnit.MINUTES.toNanos(30)); quarantine.quarantine("shared-openai"); - BridgeMcp.QuarantineSource source = new BridgeMcp.QuarantineSource( + FleetMcp.QuarantineSource source = new FleetMcp.QuarantineSource( profile -> "ltms-local".equals(profile) ? "shared-openai" : null, quarantine); - McpSchema.CallToolResult res = BridgeMcp.profiles( + McpSchema.CallToolResult res = FleetMcp.profiles( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), source); assertNotEquals(Boolean.TRUE, res.isError()); String out = textOf(res); @@ -512,7 +512,7 @@ class BridgeMcpTest { MemberSession s = sessions.acquire("ltms-local", null, "/caller/proj", "term_primary", new WorktreeRequest("cb-304", null)); - McpSchema.CallToolResult res = BridgeMcp.listFleet( + McpSchema.CallToolResult res = FleetMcp.listFleet( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), sessions, Map.of(), ""); assertNotEquals(Boolean.TRUE, res.isError()); @@ -532,10 +532,10 @@ class BridgeMcpTest { FakeHerdr h = new FakeHerdr(); SessionManager sessions = new SessionManager(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); sessions.acquire("ltms-local", null, null, null); - McpSchema.CallToolResult res = BridgeMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), - sessions, null, new BridgeMcp.CapacitySource(profile -> 2, profile -> 2, - () -> Set.of("ltms-local"), () -> 0), new BridgeMcp.HealthCoverageSource(() -> "off"), - BridgeMcp.QuarantineSource.none(), Map.of(), ""); + McpSchema.CallToolResult res = FleetMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), + sessions, null, new FleetMcp.CapacitySource(profile -> 2, profile -> 2, + () -> Set.of("ltms-local"), () -> 0), new FleetMcp.HealthCoverageSource(() -> "off"), + FleetMcp.QuarantineSource.none(), Map.of(), ""); String out = textOf(res); assertTrue(out.contains("\"maxLoad\":2"), out); assertTrue(out.contains("\"live\":2"), out); @@ -548,10 +548,10 @@ class BridgeMcpTest { void capacityIncludesConfiguredProfileWithoutMembers() { FakeHerdr h = new FakeHerdr(); SessionManager sessions = new SessionManager(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); - String out = textOf(BridgeMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), - sessions, null, new BridgeMcp.CapacitySource(profile -> 0, profile -> 2, - () -> Set.of("terra"), () -> 0), new BridgeMcp.HealthCoverageSource(() -> "off"), - BridgeMcp.QuarantineSource.none(), Map.of(), "")); + String out = textOf(FleetMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), + sessions, null, new FleetMcp.CapacitySource(profile -> 0, profile -> 2, + () -> Set.of("terra"), () -> 0), new FleetMcp.HealthCoverageSource(() -> "off"), + FleetMcp.QuarantineSource.none(), Map.of(), "")); assertTrue(out.contains("\"profile\":\"terra\""), out); assertTrue(out.contains("\"live\":0"), out); assertTrue(out.contains("\"free\":2"), out); @@ -561,10 +561,10 @@ class BridgeMcpTest { @Test void inertCapacitySourceOmitsCapacityBlock() { FakeHerdr h = new FakeHerdr(); - String out = textOf(BridgeMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), + String out = textOf(FleetMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), new SessionManager(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))), null, - BridgeMcp.CapacitySource.none(), new BridgeMcp.HealthCoverageSource(() -> "off"), - BridgeMcp.QuarantineSource.none(), Map.of(), "")); + FleetMcp.CapacitySource.none(), new FleetMcp.HealthCoverageSource(() -> "off"), + FleetMcp.QuarantineSource.none(), Map.of(), "")); assertFalse(out.contains("\"capacity\":"), out); } @@ -574,12 +574,12 @@ class BridgeMcpTest { SessionManager sessions = new SessionManager(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); BackendQuarantine quarantine = new BackendQuarantine(() -> 0L, TimeUnit.MINUTES.toNanos(20)); quarantine.quarantine("shared-openai"); - BridgeMcp.QuarantineSource source = new BridgeMcp.QuarantineSource( + FleetMcp.QuarantineSource source = new FleetMcp.QuarantineSource( profile -> "terra".equals(profile) ? "shared-openai" : null, quarantine); - String out = textOf(BridgeMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), - sessions, null, new BridgeMcp.CapacitySource(profile -> 0, profile -> 2, - () -> Set.of("terra"), () -> 0), new BridgeMcp.HealthCoverageSource(() -> "off"), + String out = textOf(FleetMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), + sessions, null, new FleetMcp.CapacitySource(profile -> 0, profile -> 2, + () -> Set.of("terra"), () -> 0), new FleetMcp.HealthCoverageSource(() -> "off"), source, Map.of(), "")); assertTrue(out.contains("\"profile\":\"terra\""), out); @@ -596,11 +596,11 @@ class BridgeMcpTest { SessionManager sessions = new SessionManager(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); BackendQuarantine quarantine = new BackendQuarantine(() -> 0L, TimeUnit.MINUTES.toNanos(20)); quarantine.quarantine("shared-openai"); - BridgeMcp.QuarantineSource source = new BridgeMcp.QuarantineSource(_ -> "shared-openai", quarantine); + FleetMcp.QuarantineSource source = new FleetMcp.QuarantineSource(_ -> "shared-openai", quarantine); - String out = textOf(BridgeMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), - sessions, null, new BridgeMcp.CapacitySource(profile -> 0, profile -> 2, - () -> Set.of("terra", "sol"), () -> 0), new BridgeMcp.HealthCoverageSource(() -> "off"), + String out = textOf(FleetMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), + sessions, null, new FleetMcp.CapacitySource(profile -> 0, profile -> 2, + () -> Set.of("terra", "sol"), () -> 0), new FleetMcp.HealthCoverageSource(() -> "off"), source, Map.of(), "")); assertEquals(2, out.split("\"free\":0", -1).length - 1, out); @@ -612,14 +612,14 @@ class BridgeMcpTest { SessionManager sessions = new SessionManager(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); BackendQuarantine quarantine = new BackendQuarantine(() -> 0L, TimeUnit.MINUTES.toNanos(20)); quarantine.quarantine("shared-openai"); - BridgeMcp.QuarantineSource source = new BridgeMcp.QuarantineSource( + FleetMcp.QuarantineSource source = new FleetMcp.QuarantineSource( profile -> "ltms-local".equals(profile) ? "shared-openai" : null, quarantine); var workers = workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")); - String listOut = textOf(BridgeMcp.listFleet(workers, sessions, null, - new BridgeMcp.CapacitySource(profile -> 0, profile -> 2, () -> Set.of("ltms-local"), () -> 0), - new BridgeMcp.HealthCoverageSource(() -> "off"), source, Map.of(), "")); - String profilesOut = textOf(BridgeMcp.profiles(workers, source)); + String listOut = textOf(FleetMcp.listFleet(workers, sessions, null, + new FleetMcp.CapacitySource(profile -> 0, profile -> 2, () -> Set.of("ltms-local"), () -> 0), + new FleetMcp.HealthCoverageSource(() -> "off"), source, Map.of(), "")); + String profilesOut = textOf(FleetMcp.profiles(workers, source)); assertTrue(listOut.contains("\"free\":0"), listOut); assertTrue(listOut.contains("\"credentialId\":\"shared-openai\""), listOut); @@ -635,12 +635,12 @@ class BridgeMcpTest { BackendQuarantine quarantine = new BackendQuarantine(() -> clockNanos[0], TimeUnit.MINUTES.toNanos(20)); quarantine.quarantine("shared-openai"); clockNanos[0] = TimeUnit.MINUTES.toNanos(21); // clock advances past the cooldown - BridgeMcp.QuarantineSource source = new BridgeMcp.QuarantineSource( + FleetMcp.QuarantineSource source = new FleetMcp.QuarantineSource( profile -> "terra".equals(profile) ? "shared-openai" : null, quarantine); - String out = textOf(BridgeMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), - sessions, null, new BridgeMcp.CapacitySource(profile -> 0, profile -> 2, - () -> Set.of("terra"), () -> 0), new BridgeMcp.HealthCoverageSource(() -> "off"), + String out = textOf(FleetMcp.listFleet(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), + sessions, null, new FleetMcp.CapacitySource(profile -> 0, profile -> 2, + () -> Set.of("terra"), () -> 0), new FleetMcp.HealthCoverageSource(() -> "off"), source, Map.of(), "")); assertTrue(out.contains("\"free\":2"), out); @@ -653,7 +653,7 @@ class BridgeMcpTest { SessionManager sessions = new SessionManager( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); - McpSchema.CallToolResult res = BridgeMcp.listFleet( + McpSchema.CallToolResult res = FleetMcp.listFleet( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), sessions, Map.of("term_me", "opus-5.0", "term_peer", "gpt-sol-5.6"), "term_me"); @@ -674,7 +674,7 @@ class BridgeMcpTest { SessionManager sessions = new SessionManager( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); - McpSchema.CallToolResult res = BridgeMcp.listFleet( + McpSchema.CallToolResult res = FleetMcp.listFleet( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), sessions, Map.of(), ""); // An absent "leads" key is what made an empty member roster read as "no peers" (CB-535). @@ -689,7 +689,7 @@ class BridgeMcpTest { SessionManager sessions = new SessionManager( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); - McpSchema.CallToolResult res = BridgeMcp.listFleet( + McpSchema.CallToolResult res = FleetMcp.listFleet( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), sessions, Map.of("term_ghost", "gone-away"), "term_me"); @@ -702,7 +702,7 @@ class BridgeMcpTest { @Test void stopTearsDownAWorkerByPane() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.stop( + McpSchema.CallToolResult res = FleetMcp.stop( sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), "w9:pW"); assertNotEquals(Boolean.TRUE, res.isError()); assertEquals("stopped w9:pW", textOf(res)); @@ -712,34 +712,34 @@ class BridgeMcpTest { @Test void stopRequiresAPaneId() { FakeHerdr h = new FakeHerdr(); - assertTrue(BridgeMcp.stop( + assertTrue(FleetMcp.stop( sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), " ").isError()); } @Test void bridgeAckReturnsConfirmationForValidArgs() { - McpSchema.CallToolResult res = BridgeMcp.ack(messages, "term_a", "msg-1"); + McpSchema.CallToolResult res = FleetMcp.ack(messages, "term_a", "msg-1"); assertNotEquals(Boolean.TRUE, res.isError()); assertTrue(textOf(res).contains("msg-1"), "response should mention the msgId"); } @Test void bridgeAckRejectsMissingArgs() { - assertTrue(BridgeMcp.ack(messages, null, "msg-1").isError()); - assertTrue(BridgeMcp.ack(messages, "term_a", null).isError()); - assertTrue(BridgeMcp.ack(messages, " ", "msg-1").isError()); + assertTrue(FleetMcp.ack(messages, null, "msg-1").isError()); + assertTrue(FleetMcp.ack(messages, "term_a", null).isError()); + assertTrue(FleetMcp.ack(messages, " ", "msg-1").isError()); } @Test void bridgeAckRemovesSpecificReply() { // Queue a reply and capture its msgId. - BridgeMcp.reply(messages, "term_a", "orphan"); + FleetMcp.reply(messages, "term_a", "orphan"); var before = messages.drainReplies("term_a"); assertEquals(1, before.size(), "one reply in the inbox"); String msgId = before.getFirst().msgId(); // Publish the same reply again and ack it via fleet_ack surface. - BridgeMcp.reply(messages, "term_a", "orphan-again"); + FleetMcp.reply(messages, "term_a", "orphan-again"); var peeked = messages.drainReplies("term_a"); assertEquals(1, peeked.size(), "one fresh reply in the inbox"); @@ -753,8 +753,8 @@ class BridgeMcpTest { Principal architect = Principal.architect("lead-designer", "term_design", 400); MemberPresence presence = new MemberPresence(); - BridgeMcp.markSpawnedMemberPresent(worker, presence); - BridgeMcp.markSpawnedMemberPresent(architect, presence); + FleetMcp.markSpawnedMemberPresent(worker, presence); + FleetMcp.markSpawnedMemberPresent(architect, presence); assertTrue(presence.isPresent("term_worker")); assertTrue(presence.isPresent("term_design")); @@ -765,8 +765,8 @@ class BridgeMcpTest { Principal lead = Principal.leader("opus", "term_lead", 100); MemberPresence presence = new MemberPresence(); - BridgeMcp.markSpawnedMemberPresent(lead, presence); - BridgeMcp.markSpawnedMemberPresent(Principal.anonymous(), presence); + FleetMcp.markSpawnedMemberPresent(lead, presence); + FleetMcp.markSpawnedMemberPresent(Principal.anonymous(), presence); assertFalse(presence.isPresent("term_lead")); } @@ -775,7 +775,7 @@ class BridgeMcpTest { void statusReportsLiveAgentStatus() { FakeHerdr blocked = new FakeHerdr().agentStatus("blocked"); AgentControl blockedAgents = new AgentControl(blocked); - McpSchema.CallToolResult res = BridgeMcp.status( + McpSchema.CallToolResult res = FleetMcp.status( new MessageService(blockedAgents, new Injector(blockedAgents), rendezvous), "term_a"); assertNotEquals(Boolean.TRUE, res.isError()); assertEquals("blocked", textOf(res)); @@ -806,7 +806,7 @@ class BridgeMcpTest { } while (asking.phase() != MessageService.Phase.ASKING && System.currentTimeMillis() < deadline); assertEquals(MessageService.Phase.ASKING, asking.phase()); - McpSchema.CallToolResult res = BridgeMcp.status(messages, T); + McpSchema.CallToolResult res = FleetMcp.status(messages, T); assertNotEquals(Boolean.TRUE, res.isError()); String out = textOf(res); assertTrue(out.startsWith("idle"), "the live status must still lead the text: " + out); @@ -832,7 +832,7 @@ class BridgeMcpTest { @Test void whoamiReportsThePrimaryAsPrimaryAndNothingElse() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.whoami( + McpSchema.CallToolResult res = FleetMcp.whoami( Principal.primary(100), sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); assertNotEquals(Boolean.TRUE, res.isError()); @@ -851,7 +851,7 @@ class BridgeMcpTest { MemberSession s = sessions.acquire("ltms-local", null, "/caller/proj", "term_primary", new WorktreeRequest("cb-517", null)); - McpSchema.CallToolResult res = BridgeMcp.whoami(Principal.worker(s.terminalId(), 200), sessions); + McpSchema.CallToolResult res = FleetMcp.whoami(Principal.worker(s.terminalId(), 200), sessions); assertNotEquals(Boolean.TRUE, res.isError()); String out = textOf(res); @@ -871,7 +871,7 @@ class BridgeMcpTest { @Test void whoamiStillReportsWorkerRoleWhenTheSessionIsUnregistered() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.whoami(Principal.worker("term_orphan", 200), + McpSchema.CallToolResult res = FleetMcp.whoami(Principal.worker("term_orphan", 200), sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); assertNotEquals(Boolean.TRUE, res.isError()); @@ -888,7 +888,7 @@ class BridgeMcpTest { @Test void whoamiReportsAnArchitectWithItsSlotAndPane() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.whoami( + McpSchema.CallToolResult res = FleetMcp.whoami( Principal.architect("lead-designer", "term_design", 400), sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); @@ -910,25 +910,25 @@ class BridgeMcpTest { void architectSendDoesNotClaimThePrimarySingletonButALeadSendStillCan() { // Architect SEND: does not change the legacy primary fallback. PrimaryRegistry reg = new PrimaryRegistry(null); - BridgeMcp.recordPrimarySingleton(reg, "term_design", Principal.architect("design", "term_design", 400)); + FleetMcp.recordPrimarySingleton(reg, "term_design", Principal.architect("design", "term_design", 400)); assertTrue(reg.primaryTerminal().isEmpty(), "an architect must never become the legacy primary fallback"); // Lead SEND (a named PRIMARY) still claims it — preserved from CB-530/CB-532. PrimaryRegistry leadReg = new PrimaryRegistry(null); - BridgeMcp.recordPrimarySingleton(leadReg, "term_lead_opus", Principal.leader("opus", "term_lead_opus", 100)); + FleetMcp.recordPrimarySingleton(leadReg, "term_lead_opus", Principal.leader("opus", "term_lead_opus", 100)); assertEquals("term_lead_opus", leadReg.primaryTerminal().orElseThrow(), "a named lead is a primary and may claim the fallback"); // Unnamed primary likewise. PrimaryRegistry primaryReg = new PrimaryRegistry(null); - BridgeMcp.recordPrimarySingleton(primaryReg, "term_p", Principal.primary(50)); + FleetMcp.recordPrimarySingleton(primaryReg, "term_p", Principal.primary(50)); assertEquals("term_p", primaryReg.primaryTerminal().orElseThrow(), "an unnamed primary may claim the fallback"); // A null caller (legacy/no-auth path) records nothing. PrimaryRegistry legacy = new PrimaryRegistry(null); - BridgeMcp.recordPrimarySingleton(legacy, "term_x", null); + FleetMcp.recordPrimarySingleton(legacy, "term_x", null); assertTrue(legacy.primaryTerminal().isEmpty(), "no caller means nothing is recorded"); } @@ -940,7 +940,7 @@ class BridgeMcpTest { SessionManager sessions = new SessionManager(workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw"))); sessions.acquire("ltms-local", MemberRole.REVIEWER, null, "/caller/proj", "term_primary", null); - McpSchema.CallToolResult res = BridgeMcp.listFleet( + McpSchema.CallToolResult res = FleetMcp.listFleet( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), sessions, Map.of(), ""); String out = textOf(res); @@ -960,7 +960,7 @@ class BridgeMcpTest { sessions.acquire("ltms-local", MemberRole.DEV, null, "/caller/proj", "term_primary", null); sessions.acquire("ltms-local", MemberRole.REVIEWER, null, "/caller/proj", "term_primary", null); - String out = textOf(BridgeMcp.listFleet( + String out = textOf(FleetMcp.listFleet( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), sessions, Map.of(), "")); assertTrue(out.contains("\"role\":\"dev\""), out); @@ -972,7 +972,7 @@ class BridgeMcpTest { @Test void spawnDefaultsTheRoleToDev() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.spawn( + McpSchema.CallToolResult res = FleetMcp.spawn( sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), null, null, null, null, null, null, null, null); @@ -983,7 +983,7 @@ class BridgeMcpTest { @Test void spawnAcceptsAnExplicitRole() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.spawn( + McpSchema.CallToolResult res = FleetMcp.spawn( sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), null, "architect", null, null, null, null, null, null); @@ -994,7 +994,7 @@ class BridgeMcpTest { @Test void spawnRejectsAnUnknownRoleAndNamesTheValidOnes() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.spawn( + McpSchema.CallToolResult res = FleetMcp.spawn( sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), null, "worker", null, null, null, null, null, null); @@ -1009,11 +1009,11 @@ class BridgeMcpTest { FakeHerdr h = new FakeHerdr(); SessionManager sessions = sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")); - McpSchema.CallToolResult res = BridgeMcp.spawn(sessions, "ltms-local", null, null, null, null, null, + McpSchema.CallToolResult res = FleetMcp.spawn(sessions, "ltms-local", null, null, null, null, null, null, "cb-resume-99"); assertNotEquals(Boolean.TRUE, res.isError(), textOf(res)); - String listOut = textOf(BridgeMcp.listFleet( + String listOut = textOf(FleetMcp.listFleet( workerService(h, "http://gx00.gw:8000", Set.of("gx00.gw")), sessions, Map.of(), "")); assertTrue(listOut.contains("\"agentSessionId\":\"cb-resume-99\""), listOut); } @@ -1021,7 +1021,7 @@ class BridgeMcpTest { @Test void spawnRefusesResumeSessionIdWithoutAnExplicitProfile() { FakeHerdr h = new FakeHerdr(); - McpSchema.CallToolResult res = BridgeMcp.spawn( + McpSchema.CallToolResult res = FleetMcp.spawn( sessionManager(h, "http://gx00.gw:8000", Set.of("gx00.gw")), null, null, null, null, null, null, null, "cb-resume-99"); @@ -1047,7 +1047,7 @@ class BridgeMcpTest { @Test void deprecatedTwinNamesTheOldToolAndDefersToTheFleetDescription() { McpSchema.Tool fleetTool = fakeTool("fleet_cb622_twin"); - McpSchema.Tool twin = BridgeMcp.deprecatedTwin(fleetTool, "bridge_cb622_twin"); + McpSchema.Tool twin = FleetMcp.deprecatedTwin(fleetTool, "bridge_cb622_twin"); assertEquals("bridge_cb622_twin", twin.name()); assertTrue(twin.description().startsWith("DEPRECATED: use fleet_cb622_twin instead."), @@ -1067,7 +1067,7 @@ class BridgeMcpTest { }; BiFunction deprecated = - BridgeMcp.deprecatedHandler(fleetTool, "bridge_cb622_dual", handler); + FleetMcp.deprecatedHandler(fleetTool, "bridge_cb622_dual", handler); // Calling the fleet_* name directly and calling the wrapped bridge_* name both end up // running the SAME `handler` instance — not a copy of its logic. @@ -1081,7 +1081,7 @@ class BridgeMcpTest { @Test void deprecatedNameWarnsOnceForTheProcessNotOncePerCall() { - Logger logger = (Logger) LoggerFactory.getLogger(BridgeMcp.class); + Logger logger = (Logger) LoggerFactory.getLogger(FleetMcp.class); ListAppender appender = new ListAppender<>(); appender.start(); logger.addAppender(appender); @@ -1089,9 +1089,9 @@ class BridgeMcpTest { // the same JVM) cannot leave the "already warned" flag set before this assertion. String oldName = "bridge_cb622_warnonce_" + System.identityHashCode(appender); try { - BridgeMcp.warnDeprecatedOnce(oldName, "fleet_cb622_warnonce"); - BridgeMcp.warnDeprecatedOnce(oldName, "fleet_cb622_warnonce"); - BridgeMcp.warnDeprecatedOnce(oldName, "fleet_cb622_warnonce"); + FleetMcp.warnDeprecatedOnce(oldName, "fleet_cb622_warnonce"); + FleetMcp.warnDeprecatedOnce(oldName, "fleet_cb622_warnonce"); + FleetMcp.warnDeprecatedOnce(oldName, "fleet_cb622_warnonce"); List matching = appender.list.stream() .filter(e -> e.getFormattedMessage().contains(oldName)) @@ -1107,7 +1107,7 @@ class BridgeMcpTest { @Test void deprecatedNameWarnsAgainForADifferentOldName() { - Logger logger = (Logger) LoggerFactory.getLogger(BridgeMcp.class); + Logger logger = (Logger) LoggerFactory.getLogger(FleetMcp.class); ListAppender appender = new ListAppender<>(); appender.start(); logger.addAppender(appender); @@ -1115,8 +1115,8 @@ class BridgeMcpTest { String nameA = "bridge_cb622_multi_a_" + suffix; String nameB = "bridge_cb622_multi_b_" + suffix; try { - BridgeMcp.warnDeprecatedOnce(nameA, "fleet_cb622_multi_a"); - BridgeMcp.warnDeprecatedOnce(nameB, "fleet_cb622_multi_b"); + FleetMcp.warnDeprecatedOnce(nameA, "fleet_cb622_multi_a"); + FleetMcp.warnDeprecatedOnce(nameB, "fleet_cb622_multi_b"); long distinctNamesWarned = appender.list.stream() .map(ILoggingEvent::getFormattedMessage) diff --git a/bridged/src/test/java/dev/ltms/bridged/mcp/PrimaryRegistryTest.java b/bridged/src/test/java/dev/ltms/fleet/mcp/PrimaryRegistryTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/mcp/PrimaryRegistryTest.java rename to bridged/src/test/java/dev/ltms/fleet/mcp/PrimaryRegistryTest.java index b58eae4..5132c23 100644 --- a/bridged/src/test/java/dev/ltms/bridged/mcp/PrimaryRegistryTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/mcp/PrimaryRegistryTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.mcp; +package dev.ltms.fleet.mcp; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/member/ClaudeCodeLauncherTest.java b/bridged/src/test/java/dev/ltms/fleet/member/ClaudeCodeLauncherTest.java similarity index 94% rename from bridged/src/test/java/dev/ltms/bridged/member/ClaudeCodeLauncherTest.java rename to bridged/src/test/java/dev/ltms/fleet/member/ClaudeCodeLauncherTest.java index 8b417b0..8d5af20 100644 --- a/bridged/src/test/java/dev/ltms/bridged/member/ClaudeCodeLauncherTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/member/ClaudeCodeLauncherTest.java @@ -1,19 +1,19 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.GuardException; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.PeerHandle; -import dev.ltms.bridged.peer.PeerUnreachableException; -import dev.ltms.bridged.peer.SpawnRequest; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.GuardException; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.PeerHandle; +import dev.ltms.fleet.peer.PeerUnreachableException; +import dev.ltms.fleet.peer.SpawnRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.slf4j.LoggerFactory; @@ -34,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.*; class ClaudeCodeLauncherTest { private ClaudeCodeLauncher service(FakeHerdr herdr, List argv, String mcpUrl) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", argv, "tab", "bridged-workers", "worker: {profile} #{n}", mcpUrl, null, null); return new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -48,7 +48,7 @@ class ClaudeCodeLauncherTest { } @Test - void appendsBridgeMcpAndReplyCharterWhenMcpUrlSet() { + void appendsFleetMcpAndReplyCharterWhenMcpUrlSet() { FakeHerdr herdr = new FakeHerdr(); service(herdr, List.of("claude"), "http://127.0.0.1:8765/mcp").spawn(); @@ -69,7 +69,7 @@ class ClaudeCodeLauncherTest { ClaudeCodeLauncher svc = new ClaudeCodeLauncher( new AgentControl(herdr), new WorkspaceControl(herdr), new SubscriptionGuard(Set.of("gx00.gw")), - Map.of("ltms-local", new BridgedConfig.Profile( + Map.of("ltms-local", new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null)), "ltms-local", _ -> null, @@ -96,7 +96,7 @@ class ClaudeCodeLauncherTest { } @Test - void noBridgeFlagsWhenMcpUrlAbsent() { + void noFleetFlagsWhenMcpUrlAbsent() { FakeHerdr herdr = new FakeHerdr(); service(herdr, List.of("claude", "--verbose"), null).spawn(); @@ -127,7 +127,7 @@ class ClaudeCodeLauncherTest { void bothChartersTravelInOneFileAndNeverOnBothFlags() { FakeHerdr herdr = new FakeHerdr(); String roleCharter = "You review changes.\nLine two.\nLine three."; - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "sonnet", "http://gx00.gw:8000", null, null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", "http://127.0.0.1:8765/mcp", null, null); @@ -191,7 +191,7 @@ class ClaudeCodeLauncherTest { FakeHerdr herdr = new FakeHerdr(); Path agentsDir = Files.createDirectories(cwd.resolve(".claude/agents")); Files.writeString(agentsDir.resolve("reviewer.md"), "---\nname: reviewer\n---\nBe a reviewer."); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "sonnet", "http://gx00.gw:8000", null, null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null); ClaudeCodeLauncher svc = new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -208,7 +208,7 @@ class ClaudeCodeLauncherTest { @Test void noAgentFlagWhenTheRoleAgentDefinitionFileIsAbsent(@TempDir Path cwd) { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "sonnet", "http://gx00.gw:8000", null, null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null); ClaudeCodeLauncher svc = new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -222,9 +222,9 @@ class ClaudeCodeLauncherTest { } private ClaudeCodeLauncher multiProfile(FakeHerdr herdr) { - BridgedConfig.Profile gx10 = new BridgedConfig.Profile("gx10", "http://gx10.gw:8000", "coder", + FleetConfig.Profile gx10 = new FleetConfig.Profile("gx10", "http://gx10.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null); - BridgedConfig.Profile ollama = new BridgedConfig.Profile("ollama", "http://ollama.ltms.dev", null, + FleetConfig.Profile ollama = new FleetConfig.Profile("ollama", "http://ollama.ltms.dev", null, null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null); return new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), new SubscriptionGuard(Set.of("gx10.gw", "ollama.ltms.dev")), @@ -265,7 +265,7 @@ class ClaudeCodeLauncherTest { @Test void profileConfigCwdBeatsTheCallerCwd() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile("ltms-local", "http://gx00.gw:8000", "coder", + FleetConfig.Profile cfg = new FleetConfig.Profile("ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "w #{n}", null, "/pinned/dir", null); ClaudeCodeLauncher svc = new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -292,7 +292,7 @@ class ClaudeCodeLauncherTest { @Test void injectsForgeTokenAndHostWhenProfileGrantsIt() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "impl", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "impl"), "tab", "bridged-workers", "w #{n}", null, null, null, "GITEA_ACCESS_TOKEN", null); // parityOverlay null; gitHostEnv null → defaults to GITEA_HOST @@ -314,7 +314,7 @@ class ClaudeCodeLauncherTest { FakeHerdr herdr = new FakeHerdr(); // gitTokenEnv unset (12-arg ctor); the env would resolve a token if asked, proving the gate // is the profile config, not a missing env var. - BridgedConfig.Profile cfg = new BridgedConfig.Profile("ltms-local", "http://gx00.gw:8000", "coder", + FleetConfig.Profile cfg = new FleetConfig.Profile("ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs"), "tab", "bridged-workers", "w #{n}", null, null, null); new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -445,7 +445,7 @@ class ClaudeCodeLauncherTest { @Test void capabilitiesIncludeSelfPrWhenProfileHasGitToken() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "impl", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "impl"), "tab", "bridged-workers", "w #{n}", null, null, null, "GITEA_ACCESS_TOKEN", null); @@ -598,8 +598,8 @@ class ClaudeCodeLauncherTest { // --- CB-306 spawn-readiness gate ----------------------------------------------------------- - private static Map workerConfigMap(String profile, String mcpUrl) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + private static Map workerConfigMap(String profile, String mcpUrl) { + FleetConfig.Profile cfg = new FleetConfig.Profile( profile, "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", profile), "tab", "bridged-workers", "worker: {profile} #{n}", mcpUrl, null, null); @@ -701,7 +701,7 @@ class ClaudeCodeLauncherTest { @Test void workerInheritsTheDaemonPath() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null); new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -715,7 +715,7 @@ class ClaudeCodeLauncherTest { @Test void profileEnvIsInjectedIntoTheWorker() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, Map.of("JAVA_HOME", "/opt/jdk", "PATH", "/profile/bin"), null, null); @@ -736,7 +736,7 @@ class ClaudeCodeLauncherTest { @Test void profileEnvCannotOverrideGuardCheckedAnthropicVars() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, Map.of("ANTHROPIC_BASE_URL", "http://evil.example.com"), null, null); @@ -751,14 +751,14 @@ class ClaudeCodeLauncherTest { // --- CB-596: config-driven member-credential policy (replaces CB-592's hardcoded single name) -- /** A representative {@code memberCredentials} — 4 allowed, 4 blocked, matching the real ticket shape. */ - private static final BridgedConfig.MemberCredentials TEST_MEMBER_CREDENTIALS = new BridgedConfig.MemberCredentials( + private static final FleetConfig.MemberCredentials TEST_MEMBER_CREDENTIALS = new FleetConfig.MemberCredentials( null, List.of("AI_GATEWAY_TOKEN", "WORKER_GITEA_TOKEN", "CONTEXT7_TOKEN", "GITEA_HOST"), List.of("AI_GATEWAY_TOKEN", "WORKER_GITEA_TOKEN", "CONTEXT7_TOKEN", "GITEA_HOST", "GITEA_ACCESS_TOKEN", "GITLAB_PERSONAL_ACCESS_TOKEN", "TS_AUTHKEY", "HASS_TOKEN")); - private ClaudeCodeLauncher serviceWithCredentials(FakeHerdr herdr, BridgedConfig.MemberCredentials creds) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + private ClaudeCodeLauncher serviceWithCredentials(FakeHerdr herdr, FleetConfig.MemberCredentials creds) { + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); return new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -833,7 +833,7 @@ class ClaudeCodeLauncherTest { @Test void aProfileEnvEntryCannotRestoreABlockedName() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, Map.of("GITEA_ACCESS_TOKEN", "admin-secret-from-profile-config"), null, null); @@ -855,7 +855,7 @@ class ClaudeCodeLauncherTest { @Test void aCredentialShapedNameOnNeitherListIsLoggedAsAGap() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); ClaudeCodeLauncher svc = new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -904,7 +904,7 @@ class ClaudeCodeLauncherTest { @Test void aProfileEnvEntryCannotClearTheMemberMarker() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, Map.of("BRIDGED_MEMBER", ""), null, null); @@ -920,14 +920,14 @@ class ClaudeCodeLauncherTest { /** A launcher for a profile identical but for its {@code model:} — the only variable here. */ private ClaudeCodeLauncher serviceWithModel(FakeHerdr herdr, String model) { - BridgedConfig.Profile cfg = profileWithModel(model); + FleetConfig.Profile cfg = profileWithModel(model); return new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), new SubscriptionGuard(Set.of("gx00.gw")), Map.of(cfg.profile(), cfg), cfg.profile(), _ -> null); } - private static BridgedConfig.Profile profileWithModel(String model) { - return new BridgedConfig.Profile("sonnet", "http://gx00.gw:8000", model, null, + private static FleetConfig.Profile profileWithModel(String model) { + return new FleetConfig.Profile("sonnet", "http://gx00.gw:8000", model, null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "sonnet"), "tab", "bridged-workers", "w #{n}", "http://127.0.0.1:8765/mcp", null, null); } @@ -969,8 +969,8 @@ class ClaudeCodeLauncherTest { // --- CB-539: subscription-profile opt-in ---------------------------------------------------- /** A claude-code profile on the subscription: no baseUrl (by design), no off-sub endpoint. */ - private static BridgedConfig.Profile subscriptionCfg(String profile, String baseUrl) { - return new BridgedConfig.Profile( + private static FleetConfig.Profile subscriptionCfg(String profile, String baseUrl) { + return new FleetConfig.Profile( profile, baseUrl, "sonnet", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", profile), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, Map.of(), null, null, true, null); @@ -981,7 +981,7 @@ class ClaudeCodeLauncherTest { // Requirement 1: absent subscription:true ⇒ byte-identical refusal to today. A claude-code // profile with no baseUrl and no subscription must still be refused (it would bill the sub). FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", null, "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "w #{n}", null, null, null); ClaudeCodeLauncher svc = new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -1000,7 +1000,7 @@ class ClaudeCodeLauncherTest { // ANTHROPIC_BASE_URL nor ANTHROPIC_AUTH_TOKEN is injected even though the token env would // resolve one if asked. FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = subscriptionCfg("sonnet", null); + FleetConfig.Profile cfg = subscriptionCfg("sonnet", null); new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), new SubscriptionGuard(Set.of("gx00.gw")), Map.of(cfg.profile(), cfg), cfg.profile(), _ -> "would-be-token").spawn(); @@ -1017,7 +1017,7 @@ class ClaudeCodeLauncherTest { // Requirement 2: subscription:true + a baseUrl state opposite intents — refuse at spawn, // naming the profile, rather than silently picking a winner. FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = subscriptionCfg("sonnet", "http://gx00.gw:8000"); + FleetConfig.Profile cfg = subscriptionCfg("sonnet", "http://gx00.gw:8000"); ClaudeCodeLauncher svc = new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), new SubscriptionGuard(Set.of("gx00.gw")), Map.of(cfg.profile(), cfg), cfg.profile(), _ -> null); @@ -1034,7 +1034,7 @@ class ClaudeCodeLauncherTest { // Requirement 3: the guard keeps its teeth for every other profile — a base_url whose host is // not on the allowlist is still refused, whether or not any subscription profile exists. FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile rogue = new BridgedConfig.Profile( + FleetConfig.Profile rogue = new FleetConfig.Profile( "rogue", "http://evil.example.com:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "rogue"), "tab", "bridged-workers", "w #{n}", null, null, null); ClaudeCodeLauncher svc = new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -1053,7 +1053,7 @@ class ClaudeCodeLauncherTest { // load refuses this loudly; this launcher-side strip is the belt-and-braces that makes the // invariant hold for a profile built in code that never passed through that validation. FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "sonnet", null, "sonnet", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "sonnet"), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, @@ -1083,13 +1083,13 @@ class ClaudeCodeLauncherTest { .toList(); } - private static BridgedConfig.Fleet fleet(Map charters, String tabLabel) { - return new BridgedConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), charters, tabLabel); + private static FleetConfig.Fleet fleet(Map charters, String tabLabel) { + return new FleetConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), charters, tabLabel); } /** A profile with no {@code tabLabel:} of its own — the fleet template decides. */ - private ClaudeCodeLauncher labelService(FakeHerdr herdr, Supplier fleet) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + private ClaudeCodeLauncher labelService(FakeHerdr herdr, Supplier fleet) { + FleetConfig.Profile cfg = new FleetConfig.Profile( "sonnet", "http://gx00.gw:8000", "sonnet", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", null, null, null, null); return new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -1099,7 +1099,7 @@ class ClaudeCodeLauncherTest { /** * The knob must reach the rename call. It was inert once — {@code HerdrPeerLauncher} accepted a - * template while {@code Bridged} passed none, and the label stayed right only because the + * template while {@code Fleetd} passed none, and the label stayed right only because the * fallback happened to match. Pin the wiring, not the coincidence. */ @Test @@ -1134,14 +1134,14 @@ class ClaudeCodeLauncherTest { new SpawnRequest("sonnet", null, null, null, null, MemberRole.ARCHITECT)); assertEquals(List.of("architect: sonnet #1"), tabLabels(herdr)); - assertEquals("{role}: {profile} #{n}", BridgedConfig.Fleet.DEFAULT_TAB_LABEL); + assertEquals("{role}: {profile} #{n}", FleetConfig.Fleet.DEFAULT_TAB_LABEL); } /** A profile that wants its own label still outranks the fleet template. */ @Test void aProfileTabLabelOverridesTheFleetTemplate() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "sonnet", "http://gx00.gw:8000", "sonnet", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "pinned {profile}", null, null, null); new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), diff --git a/bridged/src/test/java/dev/ltms/bridged/member/CompositePeerLauncherTest.java b/bridged/src/test/java/dev/ltms/fleet/member/CompositePeerLauncherTest.java similarity index 89% rename from bridged/src/test/java/dev/ltms/bridged/member/CompositePeerLauncherTest.java rename to bridged/src/test/java/dev/ltms/fleet/member/CompositePeerLauncherTest.java index 849b19d..98db5df 100644 --- a/bridged/src/test/java/dev/ltms/bridged/member/CompositePeerLauncherTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/member/CompositePeerLauncherTest.java @@ -1,24 +1,24 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.Agent; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.CharterReceipt; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.PeerHandle; -import dev.ltms.bridged.peer.PeerLauncher; -import dev.ltms.bridged.peer.PeerUnreachableException; -import dev.ltms.bridged.peer.SpawnRequest; -import dev.ltms.bridged.placement.BackendQuarantine; -import dev.ltms.bridged.placement.PlacementException; -import dev.ltms.bridged.placement.PlacementPolicies; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.Agent; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.CharterReceipt; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.PeerHandle; +import dev.ltms.fleet.peer.PeerLauncher; +import dev.ltms.fleet.peer.PeerUnreachableException; +import dev.ltms.fleet.peer.SpawnRequest; +import dev.ltms.fleet.placement.BackendQuarantine; +import dev.ltms.fleet.placement.PlacementException; +import dev.ltms.fleet.placement.PlacementPolicies; import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; @@ -43,7 +43,7 @@ class CompositePeerLauncherTest { private ClaudeCodeLauncher claudeAdapter(FakeHerdr herdr) { // 12-arg back-compat Worker ctor → kind defaults to claude-code. - BridgedConfig.Profile claude = new BridgedConfig.Profile("claude", "http://gx00.gw:8000", "coder", + FleetConfig.Profile claude = new FleetConfig.Profile("claude", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null); return new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), @@ -51,9 +51,9 @@ class CompositePeerLauncherTest { } private OpenCodeLauncher opencodeAdapter(FakeHerdr herdr) { - BridgedConfig.Profile gemini = new BridgedConfig.Profile("gemini", null, "google/gemini-2.5-pro", + FleetConfig.Profile gemini = new FleetConfig.Profile("gemini", null, "google/gemini-2.5-pro", null, "BRIDGED_WORKER_TOKEN", List.of("opencode"), "tab", "bridged-workers", "w #{n}", - null, null, null, "GITEA_ACCESS_TOKEN", null, BridgedConfig.Profile.KIND_OPENCODE); + null, null, null, "GITEA_ACCESS_TOKEN", null, FleetConfig.Profile.KIND_OPENCODE); return new OpenCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), Map.of("gemini", gemini), "gemini", _ -> "tok"); } @@ -73,7 +73,7 @@ class CompositePeerLauncherTest { private final Map spawnCounts = new HashMap<>(); StubLauncher(String prefix, FakeHerdr herdr, - Map profiles, String defaultProfile, + Map profiles, String defaultProfile, Set failProfiles) { super(prefix, new AgentControl(herdr), new WorkspaceControl(herdr), profiles, defaultProfile, _ -> null, 0L, System::currentTimeMillis, () -> { }); @@ -81,7 +81,7 @@ class CompositePeerLauncherTest { } @Override - protected Launch buildLaunch(BridgedConfig.Profile cfg, LaunchSpec spec) { + protected Launch buildLaunch(FleetConfig.Profile cfg, LaunchSpec spec) { return new Launch(Map.of(), List.of()); } @@ -119,21 +119,21 @@ class CompositePeerLauncherTest { } } - private static BridgedConfig.Profile stubWorker(String profile) { - return new BridgedConfig.Profile(profile, "http://gx00.gw:8000", "coder", + private static FleetConfig.Profile stubWorker(String profile) { + return new FleetConfig.Profile(profile, "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, null, null, null); } - private static BridgedConfig.Profile stubWorker(String profile, float weight, Integer maxLoad) { - return new BridgedConfig.Profile(profile, "http://gx00.gw:8000", "coder", + private static FleetConfig.Profile stubWorker(String profile, float weight, Integer maxLoad) { + return new FleetConfig.Profile(profile, "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, null, weight, maxLoad); } - private static BridgedConfig.Profile stubWorker(String profile, String credentialId) { - return new BridgedConfig.Profile(profile, "http://gx00.gw:8000", "coder", + private static FleetConfig.Profile stubWorker(String profile, String credentialId) { + return new FleetConfig.Profile(profile, "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("claude"), "tab", "bridged-workers", "w #{n}", null, null, null, null, null, null, null, null, null, null, null, credentialId); @@ -145,9 +145,9 @@ class CompositePeerLauncherTest { * so a {@code Map.of} would make "which profile is tried first" a coin flip per run and any * assertion about the first attempt intermittently false. */ - private static Map ordered(String first, BridgedConfig.Profile a, - String second, BridgedConfig.Profile b) { - Map m = new LinkedHashMap<>(); + private static Map ordered(String first, FleetConfig.Profile a, + String second, FleetConfig.Profile b) { + Map m = new LinkedHashMap<>(); m.put(first, a); m.put(second, b); return m; @@ -304,7 +304,7 @@ class CompositePeerLauncherTest { @Test void weightedPolicyGatesProfileAtMaxLoad() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 1.0f, 1), "b", stubWorker("b", 1.0f, null)); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of()); @@ -320,7 +320,7 @@ class CompositePeerLauncherTest { @Test void weightedPolicyDistributesAccordingToWeightRatio() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 0.75f, null), "b", stubWorker("b", 0.25f, null)); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of()); @@ -341,7 +341,7 @@ class CompositePeerLauncherTest { void weightedPolicySkipsWeightZeroProfileOnUnqualifiedSpawn() { // CB-554: weight: 0 must exclude a profile from automatic placement, not coerce to 1.0. FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 0.0f, null), "b", stubWorker("b", 1.0f, null)); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of()); @@ -361,7 +361,7 @@ class CompositePeerLauncherTest { // fleet_spawn{profile:"a"} must still work exactly as today (e.g. `opus` on the // operator's own subscription, kept weight-0 so it is never picked automatically). FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 0.0f, null), "b", stubWorker("b", 1.0f, null)); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "b", Set.of()); @@ -376,7 +376,7 @@ class CompositePeerLauncherTest { @Test void failoverRetriesNextCandidateWhenProfileIsUnreachable() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a"), "b", stubWorker("b")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of("a")); @@ -397,7 +397,7 @@ class CompositePeerLauncherTest { @Test void reversingDefinitionOrderReversesWhichProfileIsTriedFirst() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "b", stubWorker("b"), "a", stubWorker("a")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of("b")); @@ -412,7 +412,7 @@ class CompositePeerLauncherTest { @Test void failoverBoundedByCandidateCount() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a"), "b", stubWorker("b")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of("a", "b")); @@ -429,7 +429,7 @@ class CompositePeerLauncherTest { @Test void explicitSpawnAtMaxLoadThrowsPlacementExceptionNamingProfileLiveAndCap() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 1.0f, 2), "b", stubWorker("b")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of()); @@ -447,7 +447,7 @@ class CompositePeerLauncherTest { @Test void explicitSpawnUnderMaxLoadStillSucceeds() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 1.0f, 2), "b", stubWorker("b")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of()); @@ -462,7 +462,7 @@ class CompositePeerLauncherTest { @Test void explicitSpawnWithNullMaxLoadIsNeverCapped() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 1.0f, null), "b", stubWorker("b")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of()); @@ -481,7 +481,7 @@ class CompositePeerLauncherTest { // live on it yet — would have spawned instead of refusing. "at most zero members" must // hold even when the profile is named directly, not only against automatic placement. FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 1.0f, 0), "b", stubWorker("b")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of()); @@ -498,7 +498,7 @@ class CompositePeerLauncherTest { @Test void emptyCandidateSetThrowsClearException() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "a", stubWorker("a", 1.0f, 1), "b", stubWorker("b", 1.0f, 1)); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "a", Set.of()); @@ -513,24 +513,24 @@ class CompositePeerLauncherTest { // ── CB-557: an unqualified spawn is placed inside its role's pool ───────────────────────── /** Three profiles in definition order — pools are carved out of this set. */ - private static Map threeProfiles() { - Map m = new LinkedHashMap<>(); + private static Map threeProfiles() { + Map m = new LinkedHashMap<>(); m.put("opus", stubWorker("opus", 1.0f, null)); m.put("sonnet", stubWorker("sonnet", 1.0f, null)); m.put("terra", stubWorker("terra", 1.0f, null)); return m; } - private static Map pool(String... names) { - Map m = new LinkedHashMap<>(); + private static Map pool(String... names) { + Map m = new LinkedHashMap<>(); for (String n : names) { - m.put(n, new BridgedConfig.Slot(n)); + m.put(n, new FleetConfig.Slot(n)); } return m; } - private static CompositePeerLauncher withPools(FakeHerdr herdr, BridgedConfig.Fleet fleet) { - Map profiles = threeProfiles(); + private static CompositePeerLauncher withPools(FakeHerdr herdr, FleetConfig.Fleet fleet) { + Map profiles = threeProfiles(); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "opus", Set.of()); return new CompositePeerLauncher(List.of(adapter), "opus", profiles, PlacementPolicies.fixed(), _ -> 0, fleet); @@ -544,7 +544,7 @@ class CompositePeerLauncherTest { @Test void anUnqualifiedSpawnIsPlacedInsideItsRolePool() { FakeHerdr herdr = new FakeHerdr(); - CompositePeerLauncher composite = withPools(herdr, new BridgedConfig.Fleet( + CompositePeerLauncher composite = withPools(herdr, new FleetConfig.Fleet( Map.of(), pool("opus"), pool("terra"), pool("sonnet"), null)); assertEquals("opus", composite.spawn( @@ -559,7 +559,7 @@ class CompositePeerLauncherTest { @Test void theRolePoolOutranksTheGlobalDefaultProfile() { FakeHerdr herdr = new FakeHerdr(); - CompositePeerLauncher composite = withPools(herdr, new BridgedConfig.Fleet( + CompositePeerLauncher composite = withPools(herdr, new FleetConfig.Fleet( Map.of(), Map.of(), pool("sonnet", "terra"), Map.of(), null)); assertEquals("sonnet", composite.spawn( @@ -574,7 +574,7 @@ class CompositePeerLauncherTest { @Test void aRoleWithNoPoolFallsBackToEveryProfile() { FakeHerdr herdr = new FakeHerdr(); - CompositePeerLauncher composite = withPools(herdr, new BridgedConfig.Fleet( + CompositePeerLauncher composite = withPools(herdr, new FleetConfig.Fleet( Map.of(), pool("sonnet"), Map.of(), Map.of(), null)); assertEquals("opus", composite.spawn( @@ -599,7 +599,7 @@ class CompositePeerLauncherTest { @Test void anExplicitProfileIsNotConfinedToTheRolePool() { FakeHerdr herdr = new FakeHerdr(); - CompositePeerLauncher composite = withPools(herdr, new BridgedConfig.Fleet( + CompositePeerLauncher composite = withPools(herdr, new FleetConfig.Fleet( Map.of(), pool("opus"), pool("terra"), Map.of(), null)); assertEquals("opus", composite.spawn(new SpawnRequest("opus", null, null)).profile(), @@ -610,13 +610,13 @@ class CompositePeerLauncherTest { @Test void aFullPoolIsRefusedRatherThanSpilledOntoAnotherRolesProfile() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = new LinkedHashMap<>(); + Map profiles = new LinkedHashMap<>(); profiles.put("opus", stubWorker("opus", 1.0f, null)); // architect-only, uncapped profiles.put("terra", stubWorker("terra", 1.0f, 1)); // the sole dev, capped at 1 StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "opus", Set.of()); CompositePeerLauncher composite = new CompositePeerLauncher(List.of(adapter), "opus", profiles, PlacementPolicies.weighted(), name -> "terra".equals(name) ? 1 : 0, - new BridgedConfig.Fleet(Map.of(), pool("opus"), pool("terra"), Map.of(), null)); + new FleetConfig.Fleet(Map.of(), pool("opus"), pool("terra"), Map.of(), null)); PlacementException e = assertThrows(PlacementException.class, () -> composite.spawn( new SpawnRequest(null, null, null, null, null, MemberRole.DEV))); @@ -628,7 +628,7 @@ class CompositePeerLauncherTest { @Test void explicitSpawnOntoAQuarantinedProfileIsRefusedNamingTheCredentialAndRemainingTime() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "sol", stubWorker("sol", "shared-openai"), "terra", stubWorker("terra", "shared-openai")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "sol", Set.of()); @@ -654,7 +654,7 @@ class CompositePeerLauncherTest { @Test void twoProfilesSharingACredentialAreBothQuarantinedByOneExhaustionEvent() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "sol", stubWorker("sol", "shared-openai"), "terra", stubWorker("terra", "shared-openai")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "sol", Set.of()); @@ -675,7 +675,7 @@ class CompositePeerLauncherTest { @Test void placementSkipsAQuarantinedProfileAndRoutesToAnUnquarantinedOne() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "sol", stubWorker("sol", "shared-openai"), "b", stubWorker("b")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "sol", Set.of()); @@ -692,7 +692,7 @@ class CompositePeerLauncherTest { @Test void aQuarantineLiftsOnTheInjectedClockAndTheProfileBecomesSpawnableAgain() { FakeHerdr herdr = new FakeHerdr(); - Map profiles = ordered( + Map profiles = ordered( "sol", stubWorker("sol", "shared-openai"), "b", stubWorker("b")); StubLauncher adapter = new StubLauncher("claude", herdr, profiles, "sol", Set.of()); diff --git a/bridged/src/test/java/dev/ltms/bridged/member/HerdrPeerLauncherCharterTest.java b/bridged/src/test/java/dev/ltms/fleet/member/HerdrPeerLauncherCharterTest.java similarity index 80% rename from bridged/src/test/java/dev/ltms/bridged/member/HerdrPeerLauncherCharterTest.java rename to bridged/src/test/java/dev/ltms/fleet/member/HerdrPeerLauncherCharterTest.java index c657744..af2c011 100644 --- a/bridged/src/test/java/dev/ltms/bridged/member/HerdrPeerLauncherCharterTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/member/HerdrPeerLauncherCharterTest.java @@ -1,17 +1,17 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.CharterReceipt; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.SpawnRequest; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.CharterReceipt; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.SpawnRequest; import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; @@ -30,7 +30,7 @@ class HerdrPeerLauncherCharterTest { @Test void readsAndComposesTheFleetCharterForEachSpawn() { - AtomicReference fleet = new AtomicReference<>(fleet(Map.of())); + AtomicReference fleet = new AtomicReference<>(fleet(Map.of())); CapturingLauncher launcher = new CapturingLauncher(fleet::get); launcher.spawn(new SpawnRequest("mcp", null, null, null, null, MemberRole.DEV)); @@ -52,7 +52,7 @@ class HerdrPeerLauncherCharterTest { // inside argv — so the charter text leaked to the daemon log. Prove the legacy pane path // now redacts it to its digest. String secret = "TOP SECRET charter marker 99x"; // distinctive, so a leak is unambiguous - AtomicReference fleet = new AtomicReference<>(fleet(Map.of("dev", secret))); + AtomicReference fleet = new AtomicReference<>(fleet(Map.of("dev", secret))); CharterArgLauncher launcher = new CharterArgLauncher(fleet::get); Logger logger = (Logger) LoggerFactory.getLogger(HerdrPeerLauncher.class); @@ -60,7 +60,7 @@ class HerdrPeerLauncherCharterTest { ListAppender appender = new ListAppender<>(); appender.start(); logger.addAppender(appender); - logger.setLevel(Level.INFO); // the test logback sets dev.ltms.bridged to WARN; a leak lives at INFO + logger.setLevel(Level.INFO); // the test logback sets dev.ltms.fleet to WARN; a leak lives at INFO try { launcher.spawn(new SpawnRequest("mcp", null, null, null, null, MemberRole.DEV)); @@ -79,12 +79,12 @@ class HerdrPeerLauncherCharterTest { } } - private static BridgedConfig.Fleet fleet(Map charters) { - return new BridgedConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), charters, null); + private static FleetConfig.Fleet fleet(Map charters) { + return new FleetConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), charters, null); } - private static BridgedConfig.Profile profile(String name, String mcpUrl) { - return new BridgedConfig.Profile(name, "http://gx00.gw:8000", null, null, + private static FleetConfig.Profile profile(String name, String mcpUrl) { + return new FleetConfig.Profile(name, "http://gx00.gw:8000", null, null, "BRIDGED_WORKER_TOKEN", List.of("test"), "pane", null, null, mcpUrl, null, null); } @@ -95,14 +95,14 @@ class HerdrPeerLauncherCharterTest { */ private static final class CharterArgLauncher extends HerdrPeerLauncher { - CharterArgLauncher(Supplier fleet) { + CharterArgLauncher(Supplier fleet) { super("test", new AgentControl(new FakeHerdr()), new WorkspaceControl(new FakeHerdr()), Map.of("mcp", profile("mcp", "http://bridge")), "mcp", _ -> null, 0, () -> 0L, () -> { }, fleet); } @Override - protected Launch buildLaunch(BridgedConfig.Profile cfg, LaunchSpec spec) { + protected Launch buildLaunch(FleetConfig.Profile cfg, LaunchSpec spec) { return new Launch(Map.of(), List.of("test", spec.charter() == null ? "none" : spec.charter())); } @@ -115,7 +115,7 @@ class HerdrPeerLauncherCharterTest { private static final class CapturingLauncher extends HerdrPeerLauncher { private final List specs = new ArrayList<>(); - CapturingLauncher(Supplier fleet) { + CapturingLauncher(Supplier fleet) { super("test", new AgentControl(new FakeHerdr()), new WorkspaceControl(new FakeHerdr()), Map.of("mcp", profile("mcp", "http://bridge"), "no-mcp", profile("no-mcp", null)), @@ -123,7 +123,7 @@ class HerdrPeerLauncherCharterTest { } @Override - protected Launch buildLaunch(BridgedConfig.Profile cfg, LaunchSpec spec) { + protected Launch buildLaunch(FleetConfig.Profile cfg, LaunchSpec spec) { specs.add(spec); return new Launch(Map.of(), List.of("test")); } diff --git a/bridged/src/test/java/dev/ltms/bridged/member/OpenCodeLauncherTest.java b/bridged/src/test/java/dev/ltms/fleet/member/OpenCodeLauncherTest.java similarity index 91% rename from bridged/src/test/java/dev/ltms/bridged/member/OpenCodeLauncherTest.java rename to bridged/src/test/java/dev/ltms/fleet/member/OpenCodeLauncherTest.java index c1b50ec..c52b751 100644 --- a/bridged/src/test/java/dev/ltms/bridged/member/OpenCodeLauncherTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/member/OpenCodeLauncherTest.java @@ -1,17 +1,17 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.CharterReceipt; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.PeerHandle; -import dev.ltms.bridged.peer.PeerUnreachableException; -import dev.ltms.bridged.peer.SpawnRequest; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.CharterReceipt; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.PeerHandle; +import dev.ltms.fleet.peer.PeerUnreachableException; +import dev.ltms.fleet.peer.SpawnRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -33,29 +33,29 @@ import static org.junit.jupiter.api.Assertions.*; */ class OpenCodeLauncherTest { - private static BridgedConfig.Profile opencodeCfg(String model, String mcpUrl, String gitTokenEnv) { - return new BridgedConfig.Profile("gemini", null, model, null, "BRIDGED_WORKER_TOKEN", + private static FleetConfig.Profile opencodeCfg(String model, String mcpUrl, String gitTokenEnv) { + return new FleetConfig.Profile("gemini", null, model, null, "BRIDGED_WORKER_TOKEN", List.of("opencode"), "tab", "bridged-workers", "opencode: {model} #{n}", mcpUrl, - null, null, gitTokenEnv, null, BridgedConfig.Profile.KIND_OPENCODE); + null, null, gitTokenEnv, null, FleetConfig.Profile.KIND_OPENCODE); } /** Gate-disabled launcher whose per-spawn config dirs land under an inspectable temp root. */ - private static OpenCodeLauncher service(FakeHerdr herdr, Path configRoot, BridgedConfig.Profile cfg) { + private static OpenCodeLauncher service(FakeHerdr herdr, Path configRoot, FleetConfig.Profile cfg) { return new OpenCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), Map.of(cfg.profile(), cfg), cfg.profile(), k -> "GITEA_ACCESS_TOKEN".equals(k) ? "tok" : null, 0, System::currentTimeMillis, () -> { }, configRoot, configRoot); } - private static OpenCodeLauncher service(FakeHerdr herdr, Path configRoot, BridgedConfig.Profile cfg, - Supplier fleet) { + private static OpenCodeLauncher service(FakeHerdr herdr, Path configRoot, FleetConfig.Profile cfg, + Supplier fleet) { return new OpenCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), Map.of(cfg.profile(), cfg), cfg.profile(), _ -> null, 0, System::currentTimeMillis, () -> { }, configRoot, configRoot, fleet); } private static OpenCodeLauncher serviceWithCredentials(FakeHerdr herdr, Path configRoot, - BridgedConfig.Profile cfg, - BridgedConfig.MemberCredentials creds) { + FleetConfig.Profile cfg, + FleetConfig.MemberCredentials creds) { return new OpenCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), Map.of(cfg.profile(), cfg), cfg.profile(), k -> "GITEA_ACCESS_TOKEN".equals(k) ? "tok" : null, 0, System::currentTimeMillis, () -> { }, configRoot, configRoot, null, () -> creds); @@ -83,7 +83,7 @@ class OpenCodeLauncherTest { @Test void writesRemoteMcpConfigAndCharterInstructionsWhenMcpUrlSet(@TempDir Path root) throws Exception { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Fleet fleet = new BridgedConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), + FleetConfig.Fleet fleet = new FleetConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), Map.of("dev", "role rule"), null); service(herdr, root, opencodeCfg("google/gemini-2.5-pro", "http://127.0.0.1:8765/mcp", null), () -> fleet).spawn(); @@ -128,7 +128,7 @@ class OpenCodeLauncherTest { @Test void roleCharterWithoutMcpOrCustomProviderStillWritesAConfig(@TempDir Path root) throws Exception { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Fleet fleet = new BridgedConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), + FleetConfig.Fleet fleet = new FleetConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), Map.of("dev", "role rule"), null); Path configRoot = Files.createDirectory(root.resolve("configs")); Path checkout = Files.createDirectory(root.resolve("checkout")); @@ -151,7 +151,7 @@ class OpenCodeLauncherTest { void nullCharterWritesNoCharterFileOrInstructions(@TempDir Path root) throws Exception { FakeHerdr herdr = new FakeHerdr(); service(herdr, root, pinnedCfg("local-vllm/model", "http://127.0.0.1:8000", null), - () -> new BridgedConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), Map.of(), null)).spawn(); + () -> new FleetConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), Map.of(), null)).spawn(); String config = startEnv(herdr).get("OPENCODE_CONFIG"); assertNotNull(config, "the custom provider still needs a config"); @@ -165,7 +165,7 @@ class OpenCodeLauncherTest { @Test void concurrentSpawnsWriteSeparateCharterDirectories(@TempDir Path root) throws Exception { - BridgedConfig.Profile cfg = opencodeCfg("google/gemini-2.5-pro", "http://127.0.0.1:8765/mcp", null); + FleetConfig.Profile cfg = opencodeCfg("google/gemini-2.5-pro", "http://127.0.0.1:8765/mcp", null); ExecutorService executor = Executors.newFixedThreadPool(2); try { Future first = executor.submit(() -> spawnConfigPath(root, cfg)); @@ -182,7 +182,7 @@ class OpenCodeLauncherTest { } } - private static String spawnConfigPath(Path root, BridgedConfig.Profile cfg) { + private static String spawnConfigPath(Path root, FleetConfig.Profile cfg) { FakeHerdr herdr = new FakeHerdr(); service(herdr, root, cfg).spawn(); return startEnv(herdr).get("OPENCODE_CONFIG"); @@ -255,7 +255,7 @@ class OpenCodeLauncherTest { @Test void aKnownNameNotAllowedIsShadowedWithTheSentinel(@TempDir Path root) { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.MemberCredentials creds = new BridgedConfig.MemberCredentials( + FleetConfig.MemberCredentials creds = new FleetConfig.MemberCredentials( null, List.of("AI_GATEWAY_TOKEN"), List.of("AI_GATEWAY_TOKEN", "GITEA_ACCESS_TOKEN")); serviceWithCredentials(herdr, root, opencodeCfg(null, null, null), creds).spawn(); @@ -352,7 +352,7 @@ class OpenCodeLauncherTest { @Test void productionConstructorsWireThroughToTheBase() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = opencodeCfg(null, null, null); + FleetConfig.Profile cfg = opencodeCfg(null, null, null); // 5-arg (gate disabled) and 7-arg (gate enabled) production constructors both expose the profile. OpenCodeLauncher disabled = new OpenCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr), Map.of(cfg.profile(), cfg), cfg.profile(), _ -> null); @@ -398,7 +398,7 @@ class OpenCodeLauncherTest { // did not override charterReceipt(), so it silently inherited PeerHandle's `null` default // and the real receipt sitting on its delegate was lost. FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Fleet fleet = new BridgedConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), + FleetConfig.Fleet fleet = new FleetConfig.Fleet(Map.of(), Map.of(), Map.of(), Map.of(), Map.of("dev", "role rule"), null); PeerHandle handle = service(herdr, root, opencodeCfg("google/gemini-2.5-pro", "http://127.0.0.1:8765/mcp", null), () -> fleet) @@ -414,10 +414,10 @@ class OpenCodeLauncherTest { // --- CB-508: pinned OpenAI-compatible endpoint (e.g. a local vLLM) --------------------------- /** A profile with a baseUrl but no model provider prefix cannot be resolved — fail loudly. */ - private static BridgedConfig.Profile pinnedCfg(String model, String baseUrl, String mcpUrl) { - return new BridgedConfig.Profile("local", baseUrl, model, null, "BRIDGED_WORKER_TOKEN", + private static FleetConfig.Profile pinnedCfg(String model, String baseUrl, String mcpUrl) { + return new FleetConfig.Profile("local", baseUrl, model, null, "BRIDGED_WORKER_TOKEN", List.of("opencode"), "tab", "bridged-workers", "opencode: {model} #{n}", mcpUrl, - null, null, null, null, BridgedConfig.Profile.KIND_OPENCODE); + null, null, null, null, FleetConfig.Profile.KIND_OPENCODE); } @Test @@ -466,7 +466,7 @@ class OpenCodeLauncherTest { } @Test - void aPinnedEndpointAndTheBridgeMcpCoexistInOneConfig(@TempDir Path root) throws Exception { + void aPinnedEndpointAndTheFleetMcpCoexistInOneConfig(@TempDir Path root) throws Exception { FakeHerdr herdr = new FakeHerdr(); service(herdr, root, pinnedCfg("local-vllm/deepseek-v4-flash", "http://127.0.0.1:8000", "http://127.0.0.1:8766/mcp")).spawn(); diff --git a/bridged/src/test/java/dev/ltms/bridged/member/OpenCodeSessionDiscoveryTest.java b/bridged/src/test/java/dev/ltms/fleet/member/OpenCodeSessionDiscoveryTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/member/OpenCodeSessionDiscoveryTest.java rename to bridged/src/test/java/dev/ltms/fleet/member/OpenCodeSessionDiscoveryTest.java index 63f1aa8..1c29a35 100644 --- a/bridged/src/test/java/dev/ltms/bridged/member/OpenCodeSessionDiscoveryTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/member/OpenCodeSessionDiscoveryTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.member; +package dev.ltms.fleet.member; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; diff --git a/bridged/src/test/java/dev/ltms/bridged/metrics/MetricsTest.java b/bridged/src/test/java/dev/ltms/fleet/metrics/MetricsTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/metrics/MetricsTest.java rename to bridged/src/test/java/dev/ltms/fleet/metrics/MetricsTest.java index 6611cc1..c2f062b 100644 --- a/bridged/src/test/java/dev/ltms/bridged/metrics/MetricsTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/metrics/MetricsTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.metrics; +package dev.ltms.fleet.metrics; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/msg/AmqpReplyInboxContractTest.java b/bridged/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxContractTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/msg/AmqpReplyInboxContractTest.java rename to bridged/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxContractTest.java index 1c28a54..865d7d5 100644 --- a/bridged/src/test/java/dev/ltms/bridged/msg/AmqpReplyInboxContractTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxContractTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/bridged/src/test/java/dev/ltms/bridged/msg/AmqpReplyInboxRecoveryRaceTest.java b/bridged/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxRecoveryRaceTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/msg/AmqpReplyInboxRecoveryRaceTest.java rename to bridged/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxRecoveryRaceTest.java index 97d0387..5f7896d 100644 --- a/bridged/src/test/java/dev/ltms/bridged/msg/AmqpReplyInboxRecoveryRaceTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxRecoveryRaceTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/bridged/src/test/java/dev/ltms/bridged/msg/InMemoryReplyInboxTest.java b/bridged/src/test/java/dev/ltms/fleet/msg/InMemoryReplyInboxTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/msg/InMemoryReplyInboxTest.java rename to bridged/src/test/java/dev/ltms/fleet/msg/InMemoryReplyInboxTest.java index 676337b..f48e4c8 100644 --- a/bridged/src/test/java/dev/ltms/bridged/msg/InMemoryReplyInboxTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/msg/InMemoryReplyInboxTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/msg/LeadHeartbeatLoopTest.java b/bridged/src/test/java/dev/ltms/fleet/msg/LeadHeartbeatLoopTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/msg/LeadHeartbeatLoopTest.java rename to bridged/src/test/java/dev/ltms/fleet/msg/LeadHeartbeatLoopTest.java index 218fa62..1e7dc29 100644 --- a/bridged/src/test/java/dev/ltms/bridged/msg/LeadHeartbeatLoopTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/msg/LeadHeartbeatLoopTest.java @@ -1,9 +1,9 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.mcp.PrimaryRegistry; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.session.MemberSession; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.mcp.PrimaryRegistry; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.session.MemberSession; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/msg/MessageServiceTest.java b/bridged/src/test/java/dev/ltms/fleet/msg/MessageServiceTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/msg/MessageServiceTest.java rename to bridged/src/test/java/dev/ltms/fleet/msg/MessageServiceTest.java index 13a9431..166a0c8 100644 --- a/bridged/src/test/java/dev/ltms/bridged/msg/MessageServiceTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/msg/MessageServiceTest.java @@ -1,14 +1,14 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.AgentStatus; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.HerdrException; -import dev.ltms.bridged.inject.CompletionResolver; -import dev.ltms.bridged.inject.ExhaustedPatternLookup; -import dev.ltms.bridged.inject.ExhaustionSink; -import dev.ltms.bridged.mcp.PrimaryRegistry; -import dev.ltms.bridged.inject.Injector; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.AgentStatus; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.HerdrException; +import dev.ltms.fleet.inject.CompletionResolver; +import dev.ltms.fleet.inject.ExhaustedPatternLookup; +import dev.ltms.fleet.inject.ExhaustionSink; +import dev.ltms.fleet.mcp.PrimaryRegistry; +import dev.ltms.fleet.inject.Injector; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -60,7 +60,7 @@ class MessageServiceTest { } @Test - void completionFallbackResolvesATurnThatNeverCalledBridgeReply() throws Exception { + void completionFallbackResolvesATurnThatNeverCalledFleetReply() throws Exception { CompletableFuture send = sendAsync(); awaitWaiting(); @@ -78,7 +78,7 @@ class MessageServiceTest { } @Test - void explicitBridgeReplyResolvesAsReplied() throws Exception { + void explicitFleetReplyResolvesAsReplied() throws Exception { CompletableFuture send = sendAsync(); awaitWaiting(); diff --git a/bridged/src/test/java/dev/ltms/bridged/msg/RendezvousTest.java b/bridged/src/test/java/dev/ltms/fleet/msg/RendezvousTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/msg/RendezvousTest.java rename to bridged/src/test/java/dev/ltms/fleet/msg/RendezvousTest.java index 6d56e5a..f659b31 100644 --- a/bridged/src/test/java/dev/ltms/bridged/msg/RendezvousTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/msg/RendezvousTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/msg/ReplyPushLoopTest.java b/bridged/src/test/java/dev/ltms/fleet/msg/ReplyPushLoopTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/msg/ReplyPushLoopTest.java rename to bridged/src/test/java/dev/ltms/fleet/msg/ReplyPushLoopTest.java index 00064be..f449665 100644 --- a/bridged/src/test/java/dev/ltms/bridged/msg/ReplyPushLoopTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/msg/ReplyPushLoopTest.java @@ -1,12 +1,12 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.HerdrClient; -import dev.ltms.bridged.mcp.PrimaryRegistry; -import dev.ltms.bridged.metrics.BridgedMetrics; -import dev.ltms.bridged.metrics.Metrics; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.HerdrClient; +import dev.ltms.fleet.mcp.PrimaryRegistry; +import dev.ltms.fleet.metrics.FleetMetrics; +import dev.ltms.fleet.metrics.Metrics; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -799,7 +799,7 @@ class ReplyPushLoopTest { // The delivered count is bumped on the scheduler thread right after the send that releases // the latch — settle briefly so the counter is published before we read it. Thread.sleep(200); - assertEquals(1, metrics.count(BridgedMetrics.PUSH_NUDGES, "outcome", "delivered"), + assertEquals(1, metrics.count(FleetMetrics.PUSH_NUDGES, "outcome", "delivered"), "a successfully sent nudge must count as delivered"); } @@ -813,9 +813,9 @@ class ReplyPushLoopTest { assertEquals(ReplyPushLoop.Action.STOP, loop.decide(PRIMARY, 2, 0)); - assertEquals(1, metrics.count(BridgedMetrics.PUSH_NUDGES, "outcome", "exhausted"), + assertEquals(1, metrics.count(FleetMetrics.PUSH_NUDGES, "outcome", "exhausted"), "hitting the reminder cap must count as exhausted"); - assertEquals(0, metrics.count(BridgedMetrics.PUSH_NUDGES, "outcome", "delivered")); + assertEquals(0, metrics.count(FleetMetrics.PUSH_NUDGES, "outcome", "delivered")); } @Test @@ -828,7 +828,7 @@ class ReplyPushLoopTest { assertTrue(rec.sendLatch.await(3, TimeUnit.SECONDS), "one ticket nudge should have been sent"); Thread.sleep(200); - assertEquals(1, metrics.count(BridgedMetrics.PUSH_NUDGES, "outcome", "delivered"), + assertEquals(1, metrics.count(FleetMetrics.PUSH_NUDGES, "outcome", "delivered"), "a successfully sent ticket nudge must count as delivered, same metric as CB-307"); } @@ -841,7 +841,7 @@ class ReplyPushLoopTest { assertEquals(ReplyPushLoop.Action.STOP, loop.decide(PRIMARY, 0, 2)); - assertEquals(1, metrics.count(BridgedMetrics.PUSH_NUDGES, "outcome", "exhausted"), + assertEquals(1, metrics.count(FleetMetrics.PUSH_NUDGES, "outcome", "exhausted"), "hitting the ticket reminder cap must count as exhausted"); } diff --git a/bridged/src/test/java/dev/ltms/bridged/msg/TestTurnTokens.java b/bridged/src/test/java/dev/ltms/fleet/msg/TestTurnTokens.java similarity index 96% rename from bridged/src/test/java/dev/ltms/bridged/msg/TestTurnTokens.java rename to bridged/src/test/java/dev/ltms/fleet/msg/TestTurnTokens.java index 35bee6b..d07a88b 100644 --- a/bridged/src/test/java/dev/ltms/bridged/msg/TestTurnTokens.java +++ b/bridged/src/test/java/dev/ltms/fleet/msg/TestTurnTokens.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.msg; +package dev.ltms.fleet.msg; /** * Explicit unbound tokens for tests that exercise delivery without an accepted send. diff --git a/bridged/src/test/java/dev/ltms/bridged/peer/CharterReceiptTest.java b/bridged/src/test/java/dev/ltms/fleet/peer/CharterReceiptTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/peer/CharterReceiptTest.java rename to bridged/src/test/java/dev/ltms/fleet/peer/CharterReceiptTest.java index 5d7e976..2c42210 100644 --- a/bridged/src/test/java/dev/ltms/bridged/peer/CharterReceiptTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/peer/CharterReceiptTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/peer/MemberRoleTest.java b/bridged/src/test/java/dev/ltms/fleet/peer/MemberRoleTest.java similarity index 98% rename from bridged/src/test/java/dev/ltms/bridged/peer/MemberRoleTest.java rename to bridged/src/test/java/dev/ltms/fleet/peer/MemberRoleTest.java index 0924580..19879ee 100644 --- a/bridged/src/test/java/dev/ltms/bridged/peer/MemberRoleTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/peer/MemberRoleTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.peer; +package dev.ltms.fleet.peer; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/placement/BackendQuarantineTest.java b/bridged/src/test/java/dev/ltms/fleet/placement/BackendQuarantineTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/placement/BackendQuarantineTest.java rename to bridged/src/test/java/dev/ltms/fleet/placement/BackendQuarantineTest.java index 5403f9e..4a38d01 100644 --- a/bridged/src/test/java/dev/ltms/bridged/placement/BackendQuarantineTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/placement/BackendQuarantineTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/placement/PlacementPolicyTest.java b/bridged/src/test/java/dev/ltms/fleet/placement/PlacementPolicyTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/placement/PlacementPolicyTest.java rename to bridged/src/test/java/dev/ltms/fleet/placement/PlacementPolicyTest.java index c5dc42f..b377ec7 100644 --- a/bridged/src/test/java/dev/ltms/bridged/placement/PlacementPolicyTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/placement/PlacementPolicyTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.placement; +package dev.ltms.fleet.placement; import org.junit.jupiter.api.Test; diff --git a/bridged/src/test/java/dev/ltms/bridged/rest/BridgedAppAuthTest.java b/bridged/src/test/java/dev/ltms/fleet/rest/FleetAppAuthTest.java similarity index 86% rename from bridged/src/test/java/dev/ltms/bridged/rest/BridgedAppAuthTest.java rename to bridged/src/test/java/dev/ltms/fleet/rest/FleetAppAuthTest.java index 91ca023..33c9479 100644 --- a/bridged/src/test/java/dev/ltms/bridged/rest/BridgedAppAuthTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/rest/FleetAppAuthTest.java @@ -1,22 +1,22 @@ -package dev.ltms.bridged.rest; +package dev.ltms.fleet.rest; -import dev.ltms.bridged.auth.CallerResolver; -import dev.ltms.bridged.auth.MemberRegistry; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.PaneLocator; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.inject.Injector; -import dev.ltms.bridged.mcp.ConnectionIdentity; -import dev.ltms.bridged.metrics.BridgedMetrics; -import dev.ltms.bridged.metrics.Metrics; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.session.FakeWorktrees; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.member.ClaudeCodeLauncher; +import dev.ltms.fleet.auth.CallerResolver; +import dev.ltms.fleet.auth.MemberRegistry; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.PaneLocator; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.inject.Injector; +import dev.ltms.fleet.mcp.ConnectionIdentity; +import dev.ltms.fleet.metrics.FleetMetrics; +import dev.ltms.fleet.metrics.Metrics; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.session.FakeWorktrees; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.member.ClaudeCodeLauncher; import io.javalin.Javalin; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -34,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.*; * CB-501/505 enforcement over real HTTP. The unit tests pin the policy; these pin that the policy * is actually reached from a request — a rule enforced nowhere is not a control. */ -class BridgedAppAuthTest { +class FleetAppAuthTest { private final HttpClient http = HttpClient.newHttpClient(); private Javalin app; @@ -53,7 +53,7 @@ class BridgedAppAuthTest { */ private int start(long pid, boolean tokenMode, String token) { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile wcfg = new BridgedConfig.Profile( + FleetConfig.Profile wcfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", null, "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); AgentControl agents = new AgentControl(herdr); @@ -68,9 +68,9 @@ class BridgedAppAuthTest { ConnectionIdentity identity = new ConnectionIdentity(new PaneLocator(herdr), _ -> pid); CallerResolver callers = CallerResolver.withLeadsAndMembers(identity, tokenMode, token, Map::of, new MemberRegistry(null)); - metrics = BridgedMetrics.create(sessions, new dev.ltms.bridged.msg.InMemoryReplyInbox()); + metrics = FleetMetrics.create(sessions, new dev.ltms.fleet.msg.InMemoryReplyInbox()); - app = new BridgedApp(herdr, workers, sessions, messages, sessions.asPresence(), null, + app = new FleetApp(herdr, workers, sessions, messages, sessions.asPresence(), null, callers, metrics).build().start("127.0.0.1", 0); return app.port(); } @@ -195,8 +195,8 @@ class BridgedAppAuthTest { send(port, "GET", "/profiles", null, null); // 401 send(port, "POST", "/sessions/term_a/reply", "{}", "Bearer s3cret"); // 403 - assertEquals(1, metrics.count(BridgedMetrics.AUTH_FAILURES, "reason", "unauthenticated")); - assertEquals(1, metrics.count(BridgedMetrics.AUTH_FAILURES, "reason", "forbidden")); + assertEquals(1, metrics.count(FleetMetrics.AUTH_FAILURES, "reason", "unauthenticated")); + assertEquals(1, metrics.count(FleetMetrics.AUTH_FAILURES, "reason", "forbidden")); } // --- legacy constructor ------------------------------------------------------------------- @@ -206,7 +206,7 @@ class BridgedAppAuthTest { // The 29 pre-existing acceptance tests rely on this: no auth fixture, no enforcement. FakeHerdr herdr = new FakeHerdr(); AgentControl agents = new AgentControl(herdr); - BridgedConfig.Profile wcfg = new BridgedConfig.Profile( + FleetConfig.Profile wcfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", null, "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); ClaudeCodeLauncher workers = new ClaudeCodeLauncher( @@ -214,7 +214,7 @@ class BridgedAppAuthTest { Map.of(wcfg.profile(), wcfg), wcfg.profile(), _ -> "tok"); SessionManager sessions = new SessionManager(workers, new FakeWorktrees()); MessageService messages = new MessageService(agents, new Injector(agents), new Rendezvous()); - app = new BridgedApp(herdr, workers, sessions, messages, sessions.asPresence(), null) + app = new FleetApp(herdr, workers, sessions, messages, sessions.asPresence(), null) .build().start("127.0.0.1", 0); assertEquals(200, send(app.port(), "POST", "/sessions/term_a/reply", diff --git a/bridged/src/test/java/dev/ltms/bridged/rest/BridgedAppTest.java b/bridged/src/test/java/dev/ltms/fleet/rest/FleetAppTest.java similarity index 95% rename from bridged/src/test/java/dev/ltms/bridged/rest/BridgedAppTest.java rename to bridged/src/test/java/dev/ltms/fleet/rest/FleetAppTest.java index d7497f3..be58c7c 100644 --- a/bridged/src/test/java/dev/ltms/bridged/rest/BridgedAppTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/rest/FleetAppTest.java @@ -1,25 +1,25 @@ -package dev.ltms.bridged.rest; +package dev.ltms.fleet.rest; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.inject.Injector; -import dev.ltms.bridged.inject.StatusPoller; -import dev.ltms.bridged.inject.MemberPresence; -import dev.ltms.bridged.msg.InMemoryReplyInbox; -import dev.ltms.bridged.msg.MessageService; -import dev.ltms.bridged.msg.Rendezvous; -import dev.ltms.bridged.session.FakeWorktrees; -import dev.ltms.bridged.session.GitWorktrees; -import dev.ltms.bridged.session.SessionManager; -import dev.ltms.bridged.session.Worktrees; -import dev.ltms.bridged.member.ClaudeCodeLauncher; -import dev.ltms.bridged.member.CompositePeerLauncher; -import dev.ltms.bridged.placement.PlacementPolicies; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.inject.Injector; +import dev.ltms.fleet.inject.StatusPoller; +import dev.ltms.fleet.inject.MemberPresence; +import dev.ltms.fleet.msg.InMemoryReplyInbox; +import dev.ltms.fleet.msg.MessageService; +import dev.ltms.fleet.msg.Rendezvous; +import dev.ltms.fleet.session.FakeWorktrees; +import dev.ltms.fleet.session.GitWorktrees; +import dev.ltms.fleet.session.SessionManager; +import dev.ltms.fleet.session.Worktrees; +import dev.ltms.fleet.member.ClaudeCodeLauncher; +import dev.ltms.fleet.member.CompositePeerLauncher; +import dev.ltms.fleet.placement.PlacementPolicies; import io.javalin.Javalin; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -41,7 +41,7 @@ import static org.junit.jupiter.api.Assertions.*; * parity, and where the subscription boundary and worker placement are proven at the * API edge. */ -class BridgedAppTest { +class FleetAppTest { private final ObjectMapper mapper = new ObjectMapper(); private final HttpClient http = HttpClient.newHttpClient(); @@ -64,7 +64,7 @@ class BridgedAppTest { } private int start(FakeHerdr herdr, String workerBaseUrl, Set allow, String placement, Worktrees worktrees) { - BridgedConfig.Profile wcfg = new BridgedConfig.Profile( + FleetConfig.Profile wcfg = new FleetConfig.Profile( "ltms-local", workerBaseUrl, "coder", null, "BRIDGED_WORKER_TOKEN", null, placement, "bridged-workers", "worker: {profile} #{n}", null, null, null); AgentControl agents = new AgentControl(herdr); @@ -84,7 +84,7 @@ class BridgedAppTest { // it directly so the inbox contract holds for those endpoints. inbox.own("term_a"); MessageService messages = new MessageService(agents, injector, rendezvous, inbox); - app = new BridgedApp(herdr, workers, sessions, messages, this.presence, null) + app = new FleetApp(herdr, workers, sessions, messages, this.presence, null) .build().start("127.0.0.1", 0); return app.port(); } @@ -249,11 +249,11 @@ class BridgedAppTest { @Test void spawnAtMaxLoadIs503WithTheCapacityReasonNotABare500() throws Exception { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile wcfg = new BridgedConfig.Profile( + FleetConfig.Profile wcfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", null, "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null, null, null, null, null, null, 0, null, null, null); - Map profiles = Map.of(wcfg.profile(), wcfg); + Map profiles = Map.of(wcfg.profile(), wcfg); ClaudeCodeLauncher delegate = new ClaudeCodeLauncher( new AgentControl(herdr), new WorkspaceControl(herdr), new SubscriptionGuard(Set.of("gx00.gw")), profiles, wcfg.profile(), k -> "BRIDGED_WORKER_TOKEN".equals(k) ? "tok-abc" : null); @@ -265,7 +265,7 @@ class BridgedAppTest { InMemoryReplyInbox inbox = new InMemoryReplyInbox(); sessions.onAcquire(inbox::own); MessageService messages = new MessageService(new AgentControl(herdr), injector, new Rendezvous(), inbox); - app = new BridgedApp(herdr, workers, sessions, messages, this.presence, null).build().start("127.0.0.1", 0); + app = new FleetApp(herdr, workers, sessions, messages, this.presence, null).build().start("127.0.0.1", 0); int port = app.port(); HttpResponse res = req(port, "POST", "/members?profile=ltms-local"); diff --git a/bridged/src/test/java/dev/ltms/bridged/session/FakeWorktrees.java b/bridged/src/test/java/dev/ltms/fleet/session/FakeWorktrees.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/session/FakeWorktrees.java rename to bridged/src/test/java/dev/ltms/fleet/session/FakeWorktrees.java index 4aba71e..3f1ac5a 100644 --- a/bridged/src/test/java/dev/ltms/bridged/session/FakeWorktrees.java +++ b/bridged/src/test/java/dev/ltms/fleet/session/FakeWorktrees.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; import java.util.Collections; import java.util.List; diff --git a/bridged/src/test/java/dev/ltms/bridged/session/GitWorktreesTest.java b/bridged/src/test/java/dev/ltms/fleet/session/GitWorktreesTest.java similarity index 99% rename from bridged/src/test/java/dev/ltms/bridged/session/GitWorktreesTest.java rename to bridged/src/test/java/dev/ltms/fleet/session/GitWorktreesTest.java index 370c5bd..3b40911 100644 --- a/bridged/src/test/java/dev/ltms/bridged/session/GitWorktreesTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/session/GitWorktreesTest.java @@ -1,4 +1,4 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; diff --git a/bridged/src/test/java/dev/ltms/bridged/session/SessionManagerTest.java b/bridged/src/test/java/dev/ltms/fleet/session/SessionManagerTest.java similarity index 97% rename from bridged/src/test/java/dev/ltms/bridged/session/SessionManagerTest.java rename to bridged/src/test/java/dev/ltms/fleet/session/SessionManagerTest.java index 0dc9314..e49cb8b 100644 --- a/bridged/src/test/java/dev/ltms/bridged/session/SessionManagerTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/session/SessionManagerTest.java @@ -1,23 +1,23 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.member.ClaudeCodeLauncher; -import dev.ltms.bridged.msg.TestTurnTokens; -import dev.ltms.bridged.peer.Capability; -import dev.ltms.bridged.peer.CharterReceipt; -import dev.ltms.bridged.peer.MemberRole; -import dev.ltms.bridged.peer.PeerHandle; -import dev.ltms.bridged.peer.PeerLauncher; -import dev.ltms.bridged.peer.PeerUnreachableException; -import dev.ltms.bridged.peer.SpawnRequest; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.member.ClaudeCodeLauncher; +import dev.ltms.fleet.msg.TestTurnTokens; +import dev.ltms.fleet.peer.Capability; +import dev.ltms.fleet.peer.CharterReceipt; +import dev.ltms.fleet.peer.MemberRole; +import dev.ltms.fleet.peer.PeerHandle; +import dev.ltms.fleet.peer.PeerLauncher; +import dev.ltms.fleet.peer.PeerUnreachableException; +import dev.ltms.fleet.peer.SpawnRequest; import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; @@ -37,7 +37,7 @@ import static org.junit.jupiter.api.Assertions.*; class SessionManagerTest { private SessionManager sessionManager(FakeHerdr herdr) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); @@ -55,7 +55,7 @@ class SessionManagerTest { } private SessionManager sessionManager(FakeHerdr herdr, Worktrees worktrees, LongSupplier clock) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); @@ -163,7 +163,7 @@ class SessionManagerTest { private SessionManager sessionManager(FakeHerdr herdr, LongSupplier clock, int contextCap, boolean clearAfterTurn) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); @@ -224,7 +224,7 @@ class SessionManagerTest { @Test void aNullTerminalFromThePrimaryIsANoOpEvenWithSessionsRegistered() { - // The primary resolves to a Principal with no terminal, and BridgeMcp's context extractor + // The primary resolves to a Principal with no terminal, and FleetMcp's context extractor // forwards that null into markPresent on EVERY MCP call. It only reached the registry scan // once a session existed, so this NPE'd the primary's second spawn while the first passed. FakeHerdr herdr = new FakeHerdr(); @@ -575,7 +575,7 @@ class SessionManagerTest { long[] clock = {0}; // Gate-enabled launcher (1 ms timeout + no-op sleeper that advances clock past deadline) - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); diff --git a/bridged/src/test/java/dev/ltms/bridged/session/SessionReaperTest.java b/bridged/src/test/java/dev/ltms/fleet/session/SessionReaperTest.java similarity index 95% rename from bridged/src/test/java/dev/ltms/bridged/session/SessionReaperTest.java rename to bridged/src/test/java/dev/ltms/fleet/session/SessionReaperTest.java index 5220055..db61c3b 100644 --- a/bridged/src/test/java/dev/ltms/bridged/session/SessionReaperTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/session/SessionReaperTest.java @@ -1,11 +1,11 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; -import dev.ltms.bridged.member.ClaudeCodeLauncher; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; +import dev.ltms.fleet.member.ClaudeCodeLauncher; import org.junit.jupiter.api.Test; import java.util.List; @@ -31,7 +31,7 @@ class SessionReaperTest { private static ClaudeCodeLauncher launcher() { FakeHerdr herdr = new FakeHerdr(); - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); @@ -137,7 +137,7 @@ class SessionReaperTest { /** As {@link #launcher()}, on a caller-supplied herdr so the test can inspect it. */ private static ClaudeCodeLauncher launcher(FakeHerdr herdr) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); diff --git a/bridged/src/test/java/dev/ltms/bridged/session/WorktreeSessionManagerTest.java b/bridged/src/test/java/dev/ltms/fleet/session/WorktreeSessionManagerTest.java similarity index 96% rename from bridged/src/test/java/dev/ltms/bridged/session/WorktreeSessionManagerTest.java rename to bridged/src/test/java/dev/ltms/fleet/session/WorktreeSessionManagerTest.java index 466cbd7..5d2a1e1 100644 --- a/bridged/src/test/java/dev/ltms/bridged/session/WorktreeSessionManagerTest.java +++ b/bridged/src/test/java/dev/ltms/fleet/session/WorktreeSessionManagerTest.java @@ -1,18 +1,18 @@ -package dev.ltms.bridged.session; +package dev.ltms.fleet.session; -import dev.ltms.bridged.auth.MemberRegistry; -import dev.ltms.bridged.config.BridgedConfig; -import dev.ltms.bridged.guard.SubscriptionGuard; -import dev.ltms.bridged.herdr.AgentControl; -import dev.ltms.bridged.herdr.FakeHerdr; -import dev.ltms.bridged.herdr.WorkspaceControl; +import dev.ltms.fleet.auth.MemberRegistry; +import dev.ltms.fleet.config.FleetConfig; +import dev.ltms.fleet.guard.SubscriptionGuard; +import dev.ltms.fleet.herdr.AgentControl; +import dev.ltms.fleet.herdr.FakeHerdr; +import dev.ltms.fleet.herdr.WorkspaceControl; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; -import dev.ltms.bridged.member.ClaudeCodeLauncher; -import dev.ltms.bridged.msg.TestTurnTokens; -import dev.ltms.bridged.peer.MemberRole; +import dev.ltms.fleet.member.ClaudeCodeLauncher; +import dev.ltms.fleet.msg.TestTurnTokens; +import dev.ltms.fleet.peer.MemberRole; import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; @@ -31,14 +31,14 @@ import static org.junit.jupiter.api.Assertions.*; class WorktreeSessionManagerTest { private static MemberRegistry members() { - return new MemberRegistry(new BridgedConfig.Fleet(Map.of(), - Map.of("architect", new BridgedConfig.Slot("ltms-local")), - Map.of("dev", new BridgedConfig.Slot("ltms-local")), - Map.of("reviewer", new BridgedConfig.Slot("ltms-local")), null)); + return new MemberRegistry(new FleetConfig.Fleet(Map.of(), + Map.of("architect", new FleetConfig.Slot("ltms-local")), + Map.of("dev", new FleetConfig.Slot("ltms-local")), + Map.of("reviewer", new FleetConfig.Slot("ltms-local")), null)); } private static ClaudeCodeLauncher workerService(FakeHerdr herdr) { - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "worker: {profile} #{n}", null, null, null); @@ -310,7 +310,7 @@ class WorktreeSessionManagerTest { /** * CB-507 regression. A plain REST spawn supplies neither a requested nor a caller cwd - * ({@code BridgedApp} hardcodes {@code callerCwd = null}), and the worktree branch used to + * ({@code FleetApp} hardcodes {@code callerCwd = null}), and the worktree branch used to * resolve the repo root from just those two — yielding {@code null}, which the real * {@code GitWorktrees} turns into {@code git -C null} and an NPE out of {@code ProcessBuilder} * (HTTP 500). @@ -346,7 +346,7 @@ class WorktreeSessionManagerTest { FakeHerdr herdr = new FakeHerdr(); FakeWorktrees worktrees = new FakeWorktrees().withRepoRoot("/repo").withPrefix("/wt"); // Argument order matters: configDir is the 4th parameter, cwd the 11th (after mcpUrl). - BridgedConfig.Profile cfg = new BridgedConfig.Profile( + FleetConfig.Profile cfg = new FleetConfig.Profile( "ltms-local", "http://gx00.gw:8000", "coder", null, "BRIDGED_WORKER_TOKEN", List.of("ccs", "ltms-local"), "tab", "bridged-workers", "worker: {profile} #{n}", null, "/pinned/dir", null); diff --git a/bridged/src/test/resources/logback-test.xml b/bridged/src/test/resources/logback-test.xml index 85f49d4..ddb5324 100644 --- a/bridged/src/test/resources/logback-test.xml +++ b/bridged/src/test/resources/logback-test.xml @@ -4,7 +4,7 @@ out of the CB-505 audit trail. main/resources/logback.xml routes the `audit` logger to a RollingFileAppender at - logs/audit.log. AuditLogTest and BridgedAppAuthTest exercise that same logger, so without + logs/audit.log. AuditLogTest and FleetAppAuthTest exercise that same logger, so without this file `mvn test` appends fabricated records — denied/forbidden SPAWN/STOP/SEND from worker:term_a — to the production security log, byte-identical to real ones. An investigator could not tell a test fixture from a genuine intrusion attempt. Logback prefers @@ -17,7 +17,7 @@ --> - + @@ -29,7 +29,7 @@ - +