From 337f858a7a33fb4f33fd14dec48c5007af63137b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 18:08:40 +0000 Subject: [PATCH 1/3] Initial plan From 9c34eb06941680178a1aa19defcfea32748e6706 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 18:12:13 +0000 Subject: [PATCH 2/3] feat: add checking state for domain reachability on service tiles Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/3208f380-e8fe-4f12-b83c-723ecee6cd4c Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com> --- app/sovran_systemsos_web/server.py | 27 ++++++++++++++++++- app/sovran_systemsos_web/static/css/tiles.css | 1 + app/sovran_systemsos_web/static/js/helpers.js | 2 ++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/sovran_systemsos_web/server.py b/app/sovran_systemsos_web/server.py index 884df03..3b582ef 100644 --- a/app/sovran_systemsos_web/server.py +++ b/app/sovran_systemsos_web/server.py @@ -2400,6 +2400,7 @@ async def api_services(): has_port_issues = True break has_domain_issues = False + cached_reachable: bool | None = None if needs_domain: has_domain_issues = await loop.run_in_executor( None, @@ -2411,7 +2412,15 @@ async def api_services(): cached_reachable = _is_domain_reachable_cached(domain) if cached_reachable is False: has_domain_issues = True - health = "needs_attention" if (has_port_issues or has_domain_issues) else "healthy" + if has_port_issues or has_domain_issues: + health = "needs_attention" + else: + if needs_domain and domain: + if cached_reachable is None: + cached_reachable = _is_domain_reachable_cached(domain) + health = "checking_reachability" if cached_reachable is None else "healthy" + else: + health = "healthy" # Check Bitcoin IBD state if unit == "bitcoind.service" and enabled: sync = await loop.run_in_executor(None, _get_bitcoin_sync_info) @@ -2426,6 +2435,7 @@ async def api_services(): # still check domain/port health so status remains consistent with # other domain services when there are actionable issues. has_domain_issues = False + cached_reachable: bool | None = None if needs_domain: has_domain_issues = await loop.run_in_executor( None, @@ -2451,6 +2461,10 @@ async def api_services(): break if has_domain_issues or has_port_issues: health = "needs_attention" + elif needs_domain and domain: + if cached_reachable is None: + cached_reachable = _is_domain_reachable_cached(domain) + health = "checking_reachability" if cached_reachable is None else "inactive" else: health = "inactive" elif status == "failed": @@ -2458,6 +2472,16 @@ async def api_services(): else: health = status # loading states, etc. + domain_reachability = None + if needs_domain and domain and enabled: + cached = _is_domain_reachable_cached(domain) + if cached is None: + domain_reachability = "checking" + elif cached: + domain_reachability = "reachable" + else: + domain_reachability = "unreachable" + service_data: dict = { "name": entry.get("name", ""), "unit": unit, @@ -2471,6 +2495,7 @@ async def api_services(): "port_requirements": port_requirements, "needs_domain": needs_domain, "domain": domain, + "domain_reachability": domain_reachability, } if sync_ibd is not None: service_data["sync_ibd"] = sync_ibd diff --git a/app/sovran_systemsos_web/static/css/tiles.css b/app/sovran_systemsos_web/static/css/tiles.css index 8d12522..efc8d77 100644 --- a/app/sovran_systemsos_web/static/css/tiles.css +++ b/app/sovran_systemsos_web/static/css/tiles.css @@ -95,6 +95,7 @@ .status-dot.disabled { background-color: var(--grey); } .status-dot.needs-attention { background-color: var(--yellow); } .status-dot.syncing { background-color: #f5a623; animation: pulse-badge 1.5s infinite; } +.status-dot.checking-reachability { background-color: var(--accent-color); animation: pulse-badge 1s infinite; } /* ── Bitcoin IBD sync progress bar ──────────────────────────────── */ diff --git a/app/sovran_systemsos_web/static/js/helpers.js b/app/sovran_systemsos_web/static/js/helpers.js index 88774d0..470e711 100644 --- a/app/sovran_systemsos_web/static/js/helpers.js +++ b/app/sovran_systemsos_web/static/js/helpers.js @@ -14,6 +14,7 @@ function statusClass(health) { if (health === "disabled") return "disabled"; if (health === "syncing") return "syncing"; if (STATUS_LOADING_STATES.has(health)) return "loading"; + if (health === "checking_reachability") return "checking-reachability"; return "unknown"; } @@ -27,6 +28,7 @@ function statusText(health, enabled) { if (health === "syncing") return "Syncing\u2026"; if (!health || health === "unknown") return "Unknown"; if (STATUS_LOADING_STATES.has(health)) return health; + if (health === "checking_reachability") return "Checking\u2026"; return health; } From 5bb8af7a3e4090e625bf326a4610bb1580048a7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 18:15:30 +0000 Subject: [PATCH 3/3] refactor: reuse cached reachability lookup in service health Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/3208f380-e8fe-4f12-b83c-723ecee6cd4c Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com> --- app/sovran_systemsos_web/server.py | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/app/sovran_systemsos_web/server.py b/app/sovran_systemsos_web/server.py index 3b582ef..1e72d6d 100644 --- a/app/sovran_systemsos_web/server.py +++ b/app/sovran_systemsos_web/server.py @@ -2378,6 +2378,16 @@ async def api_services(): domain = val if val else None except OSError: domain = None + cached_reachable: bool | None = None + domain_reachability = None + if needs_domain and domain and enabled: + cached_reachable = _is_domain_reachable_cached(domain) + if cached_reachable is None: + domain_reachability = "checking" + elif cached_reachable: + domain_reachability = "reachable" + else: + domain_reachability = "unreachable" # Compute composite health sync_progress: float | None = None @@ -2400,7 +2410,6 @@ async def api_services(): has_port_issues = True break has_domain_issues = False - cached_reachable: bool | None = None if needs_domain: has_domain_issues = await loop.run_in_executor( None, @@ -2409,15 +2418,12 @@ async def api_services(): _cached_external_ip, ) if not has_domain_issues and domain: - cached_reachable = _is_domain_reachable_cached(domain) if cached_reachable is False: has_domain_issues = True if has_port_issues or has_domain_issues: health = "needs_attention" else: if needs_domain and domain: - if cached_reachable is None: - cached_reachable = _is_domain_reachable_cached(domain) health = "checking_reachability" if cached_reachable is None else "healthy" else: health = "healthy" @@ -2435,7 +2441,6 @@ async def api_services(): # still check domain/port health so status remains consistent with # other domain services when there are actionable issues. has_domain_issues = False - cached_reachable: bool | None = None if needs_domain: has_domain_issues = await loop.run_in_executor( None, @@ -2444,7 +2449,6 @@ async def api_services(): _cached_external_ip, ) if not has_domain_issues and domain: - cached_reachable = _is_domain_reachable_cached(domain) if cached_reachable is False: has_domain_issues = True has_port_issues = False @@ -2462,8 +2466,6 @@ async def api_services(): if has_domain_issues or has_port_issues: health = "needs_attention" elif needs_domain and domain: - if cached_reachable is None: - cached_reachable = _is_domain_reachable_cached(domain) health = "checking_reachability" if cached_reachable is None else "inactive" else: health = "inactive" @@ -2472,16 +2474,6 @@ async def api_services(): else: health = status # loading states, etc. - domain_reachability = None - if needs_domain and domain and enabled: - cached = _is_domain_reachable_cached(domain) - if cached is None: - domain_reachability = "checking" - elif cached: - domain_reachability = "reachable" - else: - domain_reachability = "unreachable" - service_data: dict = { "name": entry.get("name", ""), "unit": unit,