ios: add head-to-head subs query + app-state transition tracing

Reduce the number of device test cycles by capturing everything in one
reproduction:

- ServersSummaryView.getServersSummary: log the subs the detail view
  actually shows (allUsersSMP/currentUserSMP smpTotals), and additionally
  run getAgentSubsTotal() here UNGATED. The detail view fetches on
  .onAppear regardless of AppChatState (unlike the indicator, whose every
  poll tick is gated on == .active), so opening "servers info" once now
  shows both core queries head-to-head at the same moment/user — proving
  whether they disagree or whether only the gate differs.
- AppChatState: log the initial persisted value at process start and every
  set() transition. The indicator polls only when value == .active, so this
  shows whether/when the app reaches .active on cold launch vs returning
  from background.
This commit is contained in:
Narasimha-sc
2026-06-22 10:47:17 +00:00
parent becabb955d
commit 3faa077bd1
2 changed files with 28 additions and 0 deletions
+10
View File
@@ -191,11 +191,21 @@ class AppChatState {
static let shared = AppChatState()
private var value_ = appStateGroupDefault.get()
init() {
// SUBS_TRACE: the state this process starts at, read from the persisted group default.
// On cold launch this is whatever was saved when the app last backgrounded (often .suspended).
logger.debug("SUBS_TRACE appstate init: initial persisted value=\(value_.rawValue)")
}
var value: AppState {
value_
}
func set(_ state: AppState) {
// SUBS_TRACE: log every app-state transition. The chat-list subs indicator only polls when
// value == .active, so this shows whether/when the app actually reaches (or leaves) .active,
// e.g. on cold launch vs returning from background.
logger.debug("SUBS_TRACE appstate set: \(value_.rawValue) -> \(state.rawValue)")
appStateGroupDefault.set(state)
sendAppState(state)
value_ = state
@@ -68,9 +68,27 @@ struct ServersSummaryView: View {
private func getServersSummary() {
do {
serversSummary = try getAgentServersSummary()
if let summ = serversSummary {
// SUBS_TRACE: this detail view shows the real %. Log the subs it actually has,
// so they can be compared with what the chat-list indicator's getAgentSubsTotal returns.
let allS = summ.allUsersSMP.smpTotals
let curS = summ.currentUserSMP.smpTotals
logger.debug("SUBS_TRACE detail getAgentServersSummary: appState=\(AppChatState.shared.value.rawValue) allUsersSMP subs ssActive=\(allS.subs.ssActive) ssPending=\(allS.subs.ssPending) total=\(allS.subs.total) sessHasSess=\(allS.sessions.hasSess); currentUserSMP subs ssActive=\(curS.subs.ssActive) ssPending=\(curS.subs.ssPending) total=\(curS.subs.total) sessHasSess=\(curS.sessions.hasSess)")
}
} catch let error {
logger.error("getAgentServersSummary error: \(responseError(error))")
}
// SUBS_TRACE: run the chat-list indicator's own query (getAgentSubsTotal) here too, UNGATED,
// so a single open of this view shows both core queries head-to-head at the same moment / user,
// regardless of whether AppChatState gates the indicator's poll. Raw payload is logged in API.sendSimpleXCmd.
Task {
do {
let (subs, hasSess) = try await getAgentSubsTotal()
logger.debug("SUBS_TRACE detail getAgentSubsTotal (same query the indicator uses): ssActive=\(subs.ssActive) ssPending=\(subs.ssPending) total=\(subs.total) hasSess=\(hasSess)")
} catch let error {
logger.error("SUBS_TRACE detail getAgentSubsTotal error: \(responseError(error))")
}
}
}
private func stopTimer() {