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
20 changes: 20 additions & 0 deletions SESSION_LOG_2026_07_18.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,26 @@ 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.

PR #370 merged the topology correction through 14 green protected checks as
`b6a6d490610705d98a6d9a40c878ca46726df192`. The merged and reviewed trees
matched. Installed release SHA-256
`569ae2eb7b8ce356bc05d43930d4459a88c19221a58935ad368ca42d1991e28b`
atomically and preserved the prior adapter binary at
`~/.cargo/bin/wire.pre-doctor-topology-20260718`; launchd was not restarted.

The installed audit then exposed one last lifecycle-policy mismatch:
`sync_freshness` warned that an intentionally inactive identity's loop might be
wedged and recommended reactivation. The supervisor correctly had no worker
for that home, no lease was live, and no event was queued. GitNexus rated the
doctor-only change MEDIUM (five direct diagnostic/test callers, no execution
flows). TDD added an inactive-identity verdict: stale sync now PASSes only when
the supervisor is healthy, the current registered home has no cwd binding or
live lease, and nothing is queued. Queued work and explicitly live identities
retain the existing stale-sync WARN/FAIL behavior. The live candidate changed
that warning to: `identity inactive with no queued events; supervisor correctly
leaves its worker retired`. Final `test-env/run.sh` passed 659 library tests,
all serial Rust targets, the release demos, and 11/11 integration scripts.

## Artifacts

- `docs/superpowers/specs/2026-07-18-codex-thread-identity-design.md` — approved
Expand Down
52 changes: 51 additions & 1 deletion src/cli/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,47 @@ fn sync_freshness_verdict(last_sync_age: Option<u64>, pending_total: u64) -> Doc
}
}

fn sync_freshness_verdict_for_lifecycle(
last_sync_age: Option<u64>,
pending_total: u64,
worker_expected: bool,
) -> DoctorCheck {
if !worker_expected && pending_total == 0 {
DoctorCheck::pass(
"sync_freshness",
"identity inactive with no queued events; supervisor correctly leaves its worker retired",
)
} else {
sync_freshness_verdict(last_sync_age, pending_total)
}
}

fn current_session_worker_expected(pending_total: u64) -> bool {
if pending_total > 0 {
return true;
}
let Some(home) = std::env::var_os("WIRE_HOME").map(std::path::PathBuf::from) else {
return true;
};
let Some(session) = crate::session::list_sessions()
.unwrap_or_default()
.into_iter()
.find(|session| session.home_dir == home)
else {
return true;
};
if crate::retire::is_retired(&home) {
return false;
}
session.cwd.is_some()
|| !crate::session_lifecycle::active_leases_at(
&home,
time::OffsetDateTime::now_utc(),
crate::platform::process_alive,
)
.is_empty()
}

/// Check: the daemon's sync loop is actually advancing, not just alive.
/// Reuses the same shared helpers `wire status` surfaces (last_sync age +
/// pending-push breakdown) so the two agree by construction.
Expand All @@ -1497,7 +1538,9 @@ fn check_sync_freshness() -> DoctorCheck {
.iter()
.map(|p| p.count)
.sum();
sync_freshness_verdict(last_sync_age, pending_total)
let (_, supervisor_alive, _, _, _) = supervisor_runtime_topology();
let worker_expected = !supervisor_alive || current_session_worker_expected(pending_total);
sync_freshness_verdict_for_lifecycle(last_sync_age, pending_total, worker_expected)
}

/// Check: daemon running, exactly one instance, no orphans.
Expand Down Expand Up @@ -2354,6 +2397,13 @@ mod doctor_tests {
assert_eq!(c.status, "WARN");
}

#[test]
fn sync_freshness_passes_for_intentionally_inactive_identity() {
let c = sync_freshness_verdict_for_lifecycle(Some(3600), 0, false);
assert_eq!(c.status, "PASS");
assert!(c.detail.contains("inactive"));
}

#[test]
fn sync_freshness_passes_when_recent() {
let c = sync_freshness_verdict(Some(5), 0);
Expand Down