diff --git a/fleetd/src/main/java/dev/ltms/fleet/member/HerdrPeerLauncher.java b/fleetd/src/main/java/dev/ltms/fleet/member/HerdrPeerLauncher.java
index 8087d88..40e3cf6 100644
--- a/fleetd/src/main/java/dev/ltms/fleet/member/HerdrPeerLauncher.java
+++ b/fleetd/src/main/java/dev/ltms/fleet/member/HerdrPeerLauncher.java
@@ -1497,10 +1497,27 @@ public abstract class HerdrPeerLauncher implements PeerLauncher {
* survive {@code allowed} (including the {@code LC_*} prefix rule). Neither number is a constant:
* both come from the actual derived set and the actual environment this spawn sees. Never logs a
* variable NAME or VALUE — only the counts.
+ *
+ *
Under {@code memberHerdrSocket} the counts describe fleetd's own process, not the
+ * member's (fleetd #269 follow-up), so the message says so rather than leaving the
+ * reader to infer it from this javadoc, which the operator reading the log never sees.
*/
private void logAllowListCoverage(Set allowed) {
Set hostNames = hostEnvNames.get();
long kept = hostNames.stream().filter(name -> MemberEnvAllowList.keeps(allowed, name)).count();
+ if (memberHerdrSocketConfigured()) {
+ // fleetd #269 covered the sibling line below (logCredentialGap) and stopped there.
+ // This line has the same problem: read plainly, "allowed 7 of 39" is a statement about
+ // the member's pane, and under memberHerdrSocket it is not -- the pane is routed to a
+ // second herdr whose environment fleetd cannot inspect. The counts stay useful, so
+ // this is not a WARN and not a refusal; only the claim is narrowed to what is true.
+ log.info("member credentials: allowed {} of {} names in fleetd's OWN environment — "
+ + "memberHerdrSocket is configured, so member panes are routed to a "
+ + "second herdr whose environment fleetd has no channel to inspect. "
+ + "These counts describe fleetd's process, NOT the member pane's.",
+ kept, hostNames.size());
+ return;
+ }
log.info("member credentials: allowed {} of {}", kept, hostNames.size());
}
diff --git a/fleetd/src/test/java/dev/ltms/fleet/member/HerdrPeerLauncherAllowListWiringTest.java b/fleetd/src/test/java/dev/ltms/fleet/member/HerdrPeerLauncherAllowListWiringTest.java
index d0ab9a5..50611d3 100644
--- a/fleetd/src/test/java/dev/ltms/fleet/member/HerdrPeerLauncherAllowListWiringTest.java
+++ b/fleetd/src/test/java/dev/ltms/fleet/member/HerdrPeerLauncherAllowListWiringTest.java
@@ -250,6 +250,57 @@ class HerdrPeerLauncherAllowListWiringTest {
+ appender.list.stream().map(ILoggingEvent::getFormattedMessage).toList());
}
+ /**
+ * fleetd #269 follow-up: the same overclaim the WARN in {@code logCredentialGap} was fixed for,
+ * in the INFO line beside it. With {@code memberHerdrSocket} configured, member panes are routed
+ * to a second herdr whose environment fleetd has no channel to inspect, so the counts come from
+ * fleetd's OWN environment. The bare line "member credentials: allowed 1 of 3" reads as a fact
+ * about the member's pane, and there it is not one.
+ *
+ * #269 reworded four sites and stopped at the sibling below; this pins the pair together so
+ * a future edit cannot fix one and leave the other. Real path: asserted after a real {@link
+ * HerdrPeerLauncher#spawn}, reading the log production actually emits.
+ */
+ @Test
+ void theAllowedCountLineSaysWhoseEnvironmentItCountedWhenMemberHerdrSocketIsSet(@TempDir Path worktreeRoot)
+ throws IOException {
+ String group = currentUserGroup();
+ FakeHerdr herdr = new FakeHerdr();
+ Set hostEnvNames = Set.of(INJECTED, "SOME_UNRELATED_NAME", "ANOTHER_UNRELATED_NAME");
+ WiringLauncher launcher = new WiringLauncher(herdr, allowList(), "/bin/bash-should-be-ignored",
+ () -> hostEnvNames,
+ () -> configWithMemberHerdrSocketRootAndGroup("/tmp/other-user-herdr.sock", "/bin/zsh",
+ worktreeRoot.toString(), group));
+
+ Logger logger = (Logger) LoggerFactory.getLogger(HerdrPeerLauncher.class);
+ Level original = logger.getLevel();
+ logger.setLevel(Level.INFO);
+ ListAppender appender = new ListAppender<>();
+ appender.start();
+ logger.addAppender(appender);
+ try {
+ launcher.spawn(new SpawnRequest("test", null, null, null, null, MemberRole.DEV));
+ } finally {
+ logger.detachAppender(appender);
+ logger.setLevel(original);
+ }
+
+ List lines = appender.list.stream().map(ILoggingEvent::getFormattedMessage).toList();
+ String coverage = lines.stream()
+ .filter(l -> l.startsWith("member credentials: allowed "))
+ .findFirst()
+ .orElse(null);
+ assertNotNull(coverage, "the coverage line must still be logged — narrowing the claim must "
+ + "not silently delete the line: " + lines);
+ assertTrue(coverage.contains("fleetd's OWN environment"),
+ "the line must say whose environment it counted: " + coverage);
+ assertTrue(coverage.contains("NOT the member pane's"),
+ "and must say plainly that it is not the member's: " + coverage);
+ // The counts themselves stay real — narrowing the claim must not turn them into constants.
+ assertTrue(coverage.startsWith("member credentials: allowed 1 of 3"),
+ "the real counts must survive the rewording: " + coverage);
+ }
+
/**
* Lead-review fix: on a NON-zsh shell no scrub ever runs (bash ignores {@code ZDOTDIR}), so the
* "allowed N of M" line — which describes what the scrub does — must not be printed there either.