Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 40 additions & 4 deletions SESSION_LOG_2026_07_18.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,11 @@ thread ID.
signals. They remain inactive rather than becoming supervisor children.
- Local relay TCP healthy; launchd daemon unit loaded; PATH/service binary
consistent; no reported MCP version skew.
- Doctor's aggregate `supervisor_fanout` check still counts old MCP-owned
workers and reports 53 live workers. The managed supervisor itself owns only
12 children. No broad process kill or extra service restart was used; old
MCP-owned workers age out with their Codex sessions.
- Doctor's aggregate `supervisor_fanout` check reported 53 live workers while
process ancestry showed only 12 managed children. That discrepancy was not
old MCP-owned workers; the post-merge audit below traced it to stale daemon
pidfiles whose numeric PIDs had been reused by unrelated live processes.
No broad process kill or extra service restart was used.

## Missed runtime-test caller

Expand All @@ -127,6 +128,41 @@ and 10 failures with uninitialized identities. Changing that caller to
XDG root. This one-line follow-up and this final rollout record are carried on
`fix/codex-thread-rollout-record` for a second protected merge.

PR #369 merged that follow-up through 14 green protected checks as
`80b271e90011a44eec3082fb9db1222acfebe91c`.

## Post-merge doctor topology correction

The final installed-binary audit found launchd and the local relay healthy but
`wire doctor` emitted two false daemon failures:

- `supervisor_fanout` counted 50 "live workers" from historical daemon
pidfiles by checking only whether each numeric PID existed. Exact command
roles and ancestry showed one launchd supervisor plus 11 child daemons; old
pidfile numbers had been reused by unrelated processes.
- The current inherited-literal session had been retired by the bounded
supervisor, leaving its per-session pidfile stale. The legacy single-session
doctor path then labeled every healthy supervisor child an orphan, even
though all 11 children had the supervisor as parent and no unmanaged daemon
existed.

GitNexus classified `check_daemon_health` and
`check_daemon_pid_consistency` LOW risk (doctor-only diagnostics, no indexed
upstream callers). `check_supervisor_fanout` was absent from the graph; direct
source inspection found only `cmd_doctor` as caller, so risk remained confined
to the diagnostic surface.

TDD added four topology regressions: actual daemon-role counting, isolation
from another WIRE_HOME, healthy-supervisor precedence over a retired session
pidfile, and unmanaged-daemon failure. RED failed on missing helpers/signature;
GREEN passed 27 doctor unit tests. Formatting, clippy, the 655-stale-home
restart test, and a live candidate doctor run passed. Candidate doctor reported
11 workers within cap 16 across 719 homes, supervisor + 11 children, no
unmanaged daemons, consistent retired pidfile handling, and zero FAIL results.
The canonical `test-env/run.sh` gate then passed end-to-end: 657 library tests,
all serial Rust targets, release build, demos, and 11/11 integration scripts.
No service mutation occurred during this audit.

## Artifacts

- `docs/superpowers/specs/2026-07-18-codex-thread-identity-design.md` — approved
Expand Down
169 changes: 164 additions & 5 deletions src/cli/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,110 @@ fn supervisor_fanout_verdict(
}
}

fn supervisor_worker_count(
supervisor_pid: Option<u32>,
daemon_pids: &[u32],
known_session_pids: &[u32],
) -> usize {
let known: std::collections::HashSet<u32> = known_session_pids.iter().copied().collect();
daemon_pids
.iter()
.copied()
.filter(|pid| match supervisor_pid {
Some(supervisor) => *pid != supervisor,
None => known.contains(pid),
})
.collect::<std::collections::HashSet<_>>()
.len()
}

fn supervisor_daemon_health_verdict(
supervisor_pid: Option<u32>,
supervisor_alive: bool,
daemon_pids: &[u32],
unmanaged_pids: &[u32],
) -> Option<DoctorCheck> {
let supervisor_pid =
supervisor_pid.filter(|pid| supervisor_alive && daemon_pids.contains(pid))?;
let workers = supervisor_worker_count(Some(supervisor_pid), daemon_pids, &[]);
if !unmanaged_pids.is_empty() {
let managed_workers = workers.saturating_sub(unmanaged_pids.len());
Comment on lines +1042 to +1069

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Exclude unmanaged daemon PIDs from the fanout count.

When a supervisor exists, Lines 1051-1053 count every daemon except the supervisor and ignore known_session_pids. An unmanaged daemon therefore inflates supervisor_fanout and may incorrectly classify it as a wire_defect.

Keep fanout restricted to known session PIDs, and calculate the health verdict’s total daemon count separately.

Proposed fix
     daemon_pids
         .iter()
         .copied()
-        .filter(|pid| match supervisor_pid {
-            Some(supervisor) => *pid != supervisor,
-            None => known.contains(pid),
-        })
+        .filter(|pid| Some(*pid) != supervisor_pid && known.contains(pid))
         .collect::<std::collections::HashSet<_>>()
         .len()
 }
 
 fn supervisor_daemon_health_verdict(
@@
-    let workers = supervisor_worker_count(Some(supervisor_pid), daemon_pids, &[]);
+    let workers = daemon_pids
+        .iter()
+        .copied()
+        .filter(|pid| *pid != supervisor_pid)
+        .collect::<std::collections::HashSet<_>>()
+        .len();

Also add a case asserting that PID 12 is excluded when only PID 11 is known.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn supervisor_worker_count(
supervisor_pid: Option<u32>,
daemon_pids: &[u32],
known_session_pids: &[u32],
) -> usize {
let known: std::collections::HashSet<u32> = known_session_pids.iter().copied().collect();
daemon_pids
.iter()
.copied()
.filter(|pid| match supervisor_pid {
Some(supervisor) => *pid != supervisor,
None => known.contains(pid),
})
.collect::<std::collections::HashSet<_>>()
.len()
}
fn supervisor_daemon_health_verdict(
supervisor_pid: Option<u32>,
supervisor_alive: bool,
daemon_pids: &[u32],
unmanaged_pids: &[u32],
) -> Option<DoctorCheck> {
let supervisor_pid =
supervisor_pid.filter(|pid| supervisor_alive && daemon_pids.contains(pid))?;
let workers = supervisor_worker_count(Some(supervisor_pid), daemon_pids, &[]);
if !unmanaged_pids.is_empty() {
let managed_workers = workers.saturating_sub(unmanaged_pids.len());
fn supervisor_worker_count(
supervisor_pid: Option<u32>,
daemon_pids: &[u32],
known_session_pids: &[u32],
) -> usize {
let known: std::collections::HashSet<u32> = known_session_pids.iter().copied().collect();
daemon_pids
.iter()
.copied()
.filter(|pid| Some(*pid) != supervisor_pid && known.contains(pid))
.collect::<std::collections::HashSet<_>>()
.len()
}
fn supervisor_daemon_health_verdict(
supervisor_pid: Option<u32>,
supervisor_alive: bool,
daemon_pids: &[u32],
unmanaged_pids: &[u32],
) -> Option<DoctorCheck> {
let supervisor_pid =
supervisor_pid.filter(|pid| supervisor_alive && daemon_pids.contains(pid))?;
let workers = daemon_pids
.iter()
.copied()
.filter(|pid| *pid != supervisor_pid)
.collect::<std::collections::HashSet<_>>()
.len();
if !unmanaged_pids.is_empty() {
let managed_workers = workers.saturating_sub(unmanaged_pids.len());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/status.rs` around lines 1042 - 1069, Update supervisor_worker_count
to restrict its fanout set to known_session_pids even when supervisor_pid is
present, excluding unmanaged daemon PIDs such as 12 when only 11 is known. In
supervisor_daemon_health_verdict, calculate the total daemon count separately
for health evaluation rather than reusing the restricted fanout count, and add
coverage for the specified PID case.

return Some(DoctorCheck::fail(
"daemon",
format!(
"supervisor (pid {supervisor_pid}) + {managed_workers} session child daemon(s), but {} unmanaged daemon(s) remain: {}",
unmanaged_pids.len(),
unmanaged_pids
.iter()
.map(u32::to_string)
.collect::<Vec<_>>()
.join(", ")
),
"inspect `wire supervisor` and process ancestry; recover through the existing service manager; do not wildcard-kill processes",
));
}
Some(DoctorCheck::pass(
"daemon",
format!(
"supervisor (pid {supervisor_pid}) + {workers} session child daemon(s); no unmanaged daemons"
),
))
}

fn supervisor_pid_consistency_verdict(
supervisor_pid: Option<u32>,
supervisor_alive: bool,
daemon_pids: &[u32],
unmanaged_pids: &[u32],
) -> Option<DoctorCheck> {
let health = supervisor_daemon_health_verdict(
supervisor_pid,
supervisor_alive,
daemon_pids,
unmanaged_pids,
)?;
(health.status == "PASS").then(|| {
DoctorCheck::pass(
"daemon_pid_consistency",
"supervisor owns session worker lifecycle; retired session pidfiles do not imply an orphan",
)
})
}

fn supervisor_runtime_topology() -> (Option<u32>, bool, Vec<u32>, Vec<u32>, usize) {
let daemon_pids = actual_wire_role_pids("daemon");
let supervisor_pid = crate::session::sessions_root()
.ok()
.map(|root| root.join("supervisor.pid"))
.and_then(|path| std::fs::read_to_string(path).ok())
.and_then(|body| body.trim().parse::<u32>().ok());
let supervisor_alive = supervisor_pid.is_some_and(|pid| daemon_pids.contains(&pid));
let known_session_pids: Vec<u32> = crate::session::list_sessions()
.unwrap_or_default()
.iter()
.filter_map(|session| crate::session::session_daemon_pid(&session.home_dir))
.collect();
let known_session_pid_set: std::collections::HashSet<u32> =
known_session_pids.iter().copied().collect();
let unmanaged_pids = daemon_pids
.iter()
.copied()
.filter(|pid| Some(*pid) != supervisor_pid && !known_session_pid_set.contains(pid))
.collect();
let workers = supervisor_worker_count(
supervisor_pid.filter(|_| supervisor_alive),
&daemon_pids,
&known_session_pids,
);
(
supervisor_pid,
supervisor_alive,
daemon_pids,
unmanaged_pids,
workers,
)
}

fn session_override_collision_verdict(processes: usize, distinct_homes: usize) -> DoctorCheck {
if processes > 1 && distinct_homes < processes {
DoctorCheck::warn(
Expand Down Expand Up @@ -1116,11 +1220,7 @@ fn local_relay_verdict(installed: bool, reachable: bool) -> DoctorCheck {

fn check_supervisor_fanout() -> DoctorCheck {
let sessions = crate::session::list_sessions().unwrap_or_default();
let workers = sessions
.iter()
.filter_map(|session| crate::session::session_daemon_pid(&session.home_dir))
.filter(|pid| crate::platform::process_alive(*pid))
.count();
let (_, _, _, _, workers) = supervisor_runtime_topology();
let inactive = sessions
.iter()
.filter(|session| {
Expand Down Expand Up @@ -1407,6 +1507,17 @@ fn check_sync_freshness() -> DoctorCheck {
/// `wire doctor` must catch THIS class: multiple daemons running, OR
/// pid-file claims daemon down while a process is actually up.
fn check_daemon_health() -> DoctorCheck {
let (supervisor_pid, supervisor_alive, daemon_pids, unmanaged_pids, _) =
supervisor_runtime_topology();
if let Some(verdict) = supervisor_daemon_health_verdict(
supervisor_pid,
supervisor_alive,
&daemon_pids,
&unmanaged_pids,
) {
return verdict;
}

// v0.5.13 (issue #2 bug A): doctor PASSed on orphan-only state while
// `wire status` reported DOWN, disagreeing for 25 min. v0.5.19 (#2
// hardening): every surface routes through ensure_up::daemon_liveness
Expand Down Expand Up @@ -1523,6 +1634,17 @@ fn check_daemon_health() -> DoctorCheck {
/// content, not liveness), letting `wire status: DOWN` and
/// `wire doctor: PASS` disagree for 25 min in incident #2.
fn check_daemon_pid_consistency() -> DoctorCheck {
let (supervisor_pid, supervisor_alive, daemon_pids, unmanaged_pids, _) =
supervisor_runtime_topology();
if let Some(verdict) = supervisor_pid_consistency_verdict(
supervisor_pid,
supervisor_alive,
&daemon_pids,
&unmanaged_pids,
) {
return verdict;
}

let snap = crate::ensure_up::daemon_liveness();
match &snap.record {
crate::ensure_up::PidRecord::Missing => DoctorCheck::pass(
Expand Down Expand Up @@ -2150,6 +2272,43 @@ mod doctor_tests {
assert!(c.detail.contains("566") && c.detail.contains("16"));
}

#[test]
fn supervisor_worker_count_uses_actual_daemon_roles_not_stale_pidfiles() {
assert_eq!(
supervisor_worker_count(Some(10), &[10, 11, 12], &[11, 12]),
2
);
assert_eq!(supervisor_worker_count(None, &[11, 12], &[11]), 1);
}

#[test]
fn doctor_prefers_healthy_supervisor_topology_over_stale_session_pidfile() {
let c = supervisor_daemon_health_verdict(Some(10), true, &[10, 11, 12], &[])
.expect("healthy supervisor should own the daemon verdict");
assert_eq!(c.status, "PASS");
assert!(c.detail.contains("2 session child"));
}

#[test]
fn supervisor_topology_surfaces_unmanaged_daemon() {
let c = supervisor_daemon_health_verdict(Some(10), true, &[10, 11, 12], &[12])
.expect("healthy supervisor should own the daemon verdict");
assert_eq!(c.status, "FAIL");
assert!(c.detail.contains("1 session child"));
assert!(c.detail.contains("unmanaged"));
}

#[test]
fn retired_session_pidfile_is_consistent_under_healthy_supervisor() {
let c = supervisor_pid_consistency_verdict(Some(10), true, &[10, 11, 12], &[])
.expect("healthy supervisor should own pid consistency");
assert_eq!(c.status, "PASS");
assert!(
c.detail
.contains("supervisor owns session worker lifecycle")
);
}

#[test]
fn duplicate_literal_override_is_operator_configuration() {
let c = session_override_collision_verdict(2, 1);
Expand Down