Skip to content

Commit dc8a51d

Browse files
committed
PR_26175_CHARLIE_012-runtime-health
1 parent 250b32f commit dc8a51d

14 files changed

Lines changed: 700 additions & 208 deletions

admin/system-health.html

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ <h2>Admin</h2>
4343
<p>Local API Startup</p>
4444
<p>Database Health</p>
4545
<p>Storage Health</p>
46+
<p>Runtime Health</p>
4647
<p>Health Check History</p>
4748
<p>Runtime Environment</p>
4849
<p>Limits &amp; Capacity</p>
@@ -153,6 +154,27 @@ <h2 id="admin-system-health-title">System Health Tables</h2>
153154
</tbody>
154155
</table>
155156
</div>
157+
<div class="table-wrapper">
158+
<table class="data-table" aria-label="Runtime health">
159+
<caption>Runtime Health</caption>
160+
<thead>
161+
<tr>
162+
<th scope="col">Field</th>
163+
<th scope="col">Current Deployment</th>
164+
<th scope="col">Status</th>
165+
</tr>
166+
</thead>
167+
<tbody>
168+
<tr><td>Environment</td><td data-admin-system-health-runtime-health-value="environment">Loading</td><td data-health-status="PENDING" data-admin-system-health-runtime-health-status="environment" title="Reason: runtime health has not loaded yet." aria-label="PENDING: runtime health has not loaded yet.">PENDING</td></tr>
169+
<tr><td>App/runtime version</td><td data-admin-system-health-runtime-health-value="appVersion">Loading</td><td data-health-status="PENDING" data-admin-system-health-runtime-health-status="appVersion" title="Reason: runtime health has not loaded yet." aria-label="PENDING: runtime health has not loaded yet.">PENDING</td></tr>
170+
<tr><td>API version</td><td data-admin-system-health-runtime-health-value="apiVersion">Loading</td><td data-health-status="PENDING" data-admin-system-health-runtime-health-status="apiVersion" title="Reason: runtime health has not loaded yet." aria-label="PENDING: runtime health has not loaded yet.">PENDING</td></tr>
171+
<tr><td>Node version</td><td data-admin-system-health-runtime-health-value="nodeVersion">Loading</td><td data-health-status="PENDING" data-admin-system-health-runtime-health-status="nodeVersion" title="Reason: runtime health has not loaded yet." aria-label="PENDING: runtime health has not loaded yet.">PENDING</td></tr>
172+
<tr><td>Server start time</td><td data-admin-system-health-runtime-health-value="serverStartTime">Loading</td><td data-health-status="PENDING" data-admin-system-health-runtime-health-status="serverStartTime" title="Reason: runtime health has not loaded yet." aria-label="PENDING: runtime health has not loaded yet.">PENDING</td></tr>
173+
<tr><td>Uptime</td><td data-admin-system-health-runtime-health-value="uptime">Loading</td><td data-health-status="PENDING" data-admin-system-health-runtime-health-status="uptime" title="Reason: runtime health has not loaded yet." aria-label="PENDING: runtime health has not loaded yet.">PENDING</td></tr>
174+
<tr><td>Last checked</td><td data-admin-system-health-runtime-health-value="lastChecked">Loading</td><td data-health-status="PENDING" data-admin-system-health-runtime-health-status="lastChecked" title="Reason: runtime health has not loaded yet." aria-label="PENDING: runtime health has not loaded yet.">PENDING</td></tr>
175+
</tbody>
176+
</table>
177+
</div>
156178
<div class="table-wrapper">
157179
<table class="data-table" aria-label="Health check history">
158180
<caption>Health Check History</caption>

assets/theme-v2/js/admin-system-health.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ function asText(value, fallback = "not available") {
2020
return statusText(value, fallback);
2121
}
2222

23+
function formatUptimeSeconds(value) {
24+
const seconds = Number(value);
25+
return Number.isFinite(seconds) ? `${Math.max(0, Math.floor(seconds))} s` : "not available";
26+
}
27+
2328
class AdminSystemHealthController {
2429
constructor(root) {
2530
this.root = root;
@@ -47,6 +52,14 @@ class AdminSystemHealthController {
4752
node.dataset.adminSystemHealthStorageStatus,
4853
node,
4954
]));
55+
this.runtimeHealthValues = new Map(Array.from(root.querySelectorAll("[data-admin-system-health-runtime-health-value]")).map((node) => [
56+
node.dataset.adminSystemHealthRuntimeHealthValue,
57+
node,
58+
]));
59+
this.runtimeHealthStatuses = new Map(Array.from(root.querySelectorAll("[data-admin-system-health-runtime-health-status]")).map((node) => [
60+
node.dataset.adminSystemHealthRuntimeHealthStatus,
61+
node,
62+
]));
5063
this.historyRows = root.querySelector("[data-admin-system-health-history-rows]");
5164
this.startupRows = root.querySelector("[data-admin-system-health-startup-rows]");
5265
this.runtimeRows = root.querySelector("[data-admin-system-health-runtime-rows]");
@@ -95,6 +108,18 @@ class AdminSystemHealthController {
95108
this.setStatusNode(node, status, reason);
96109
}
97110

111+
setRuntimeHealthValue(key, value, fallback) {
112+
const node = this.runtimeHealthValues.get(key);
113+
if (node) {
114+
node.textContent = asText(value, fallback);
115+
}
116+
}
117+
118+
setRuntimeHealthStatus(key, status, reason = "") {
119+
const node = this.runtimeHealthStatuses.get(key);
120+
this.setStatusNode(node, status, reason);
121+
}
122+
98123
setStatusNode(node, status, reason = "") {
99124
applyStatusNode(node, status, { reason });
100125
}
@@ -108,6 +133,7 @@ class AdminSystemHealthController {
108133
});
109134
this.renderStartupPending(reason);
110135
this.renderStoragePending(reason);
136+
this.renderRuntimeHealthPending(reason);
111137
this.renderHistoryPending(reason);
112138
}
113139

@@ -162,6 +188,35 @@ class AdminSystemHealthController {
162188
this.setStorageStatus("lastChecked", storageStatus.lastChecked ? "PASS" : "WARN", reason);
163189
}
164190

191+
renderRuntimeHealthPending(reason) {
192+
["environment", "appVersion", "apiVersion", "nodeVersion", "serverStartTime", "uptime", "lastChecked"].forEach((key) => {
193+
this.setRuntimeHealthValue(key, "not available");
194+
this.setRuntimeHealthStatus(key, "PENDING", reason);
195+
});
196+
}
197+
198+
renderRuntimeHealth(runtimeHealth = {}) {
199+
const reason = runtimeHealth.message || "Current deployment runtime health returned by the safe Admin System Health API.";
200+
if (runtimeHealth?.secretsExposed === true || runtimeHealth?.secretEditingAllowed === true) {
201+
this.renderRuntimeHealthPending("Safe runtime health response was blocked because it exposed secret controls.");
202+
return;
203+
}
204+
this.setRuntimeHealthValue("environment", runtimeHealth.environmentName, "Unknown");
205+
this.setRuntimeHealthStatus("environment", runtimeHealth.environmentName ? runtimeHealth.status : "WARN", reason);
206+
this.setRuntimeHealthValue("appVersion", runtimeHealth.appVersion, "not available");
207+
this.setRuntimeHealthStatus("appVersion", runtimeHealth.appVersion ? "PASS" : "WARN", reason);
208+
this.setRuntimeHealthValue("apiVersion", runtimeHealth.apiVersion, "not available");
209+
this.setRuntimeHealthStatus("apiVersion", runtimeHealth.apiVersion ? "PASS" : "WARN", reason);
210+
this.setRuntimeHealthValue("nodeVersion", runtimeHealth.nodeVersion, "not available");
211+
this.setRuntimeHealthStatus("nodeVersion", runtimeHealth.nodeVersion ? "PASS" : "WARN", reason);
212+
this.setRuntimeHealthValue("serverStartTime", runtimeHealth.serverStartTime, "not available");
213+
this.setRuntimeHealthStatus("serverStartTime", runtimeHealth.serverStartTime ? "PASS" : "WARN", reason);
214+
this.setRuntimeHealthValue("uptime", formatUptimeSeconds(runtimeHealth.uptimeSeconds));
215+
this.setRuntimeHealthStatus("uptime", Number.isFinite(Number(runtimeHealth.uptimeSeconds)) ? "PASS" : "WARN", reason);
216+
this.setRuntimeHealthValue("lastChecked", runtimeHealth.lastChecked, "not available");
217+
this.setRuntimeHealthStatus("lastChecked", runtimeHealth.lastChecked ? "PASS" : "WARN", reason);
218+
}
219+
165220
renderStartupPending(reason) {
166221
if (!this.startupRows) {
167222
return;
@@ -343,6 +398,7 @@ class AdminSystemHealthController {
343398
this.renderStartupDiagnostics(data?.localApiStartup || {});
344399
this.renderStorageStatus(data?.storageStatus || {});
345400
this.runStorageDiagnostics();
401+
this.renderRuntimeHealth(data?.runtimeHealth || {});
346402
this.renderHealthCheckHistory(data?.healthCheckHistory || []);
347403
this.renderRuntimeEnvironment(data?.runtimeEnvironment || {});
348404
} catch (error) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# PR_26175_CHARLIE_012 Branch Validation
2+
3+
## Start Gate
4+
5+
- PASS: Worktree was clean before Phase 2 implementation started.
6+
- PASS: Current branch was `pr/26175-CHARLIE-010-system-health-history-and-closeout`.
7+
- PASS: Branch history contained Charlie PRs 007 through 011.
8+
9+
## Branch Rules
10+
11+
- PASS: Continued on the existing Charlie workstream branch.
12+
- PASS: No merge was performed.
13+
- PASS: No rebase was performed.
14+
- PASS: No new root branch was created.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# PR_26175_CHARLIE_012 Manual Validation Notes
2+
3+
- Verified the Runtime Health table is present on `admin/system-health.html`.
4+
- Verified Runtime Health values are rendered from `/api/admin/system-health/status`.
5+
- Verified the page still blocks Creator sessions before System Health API calls.
6+
- Verified Runtime Environment remains a masked variable table and was not repurposed as Runtime Health.
7+
- Verified no cross-environment health checks were introduced.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# PR_26175_CHARLIE_012 Requirement Checklist
2+
3+
- PASS: Added Runtime Health section.
4+
- PASS: Shows current environment.
5+
- PASS: Shows app/runtime version when available.
6+
- PASS: Shows API version when available.
7+
- PASS: Shows Node version from the server.
8+
- PASS: Shows server start time from the server.
9+
- PASS: Shows uptime from the server.
10+
- PASS: Shows last checked from the server.
11+
- PASS: Uses API/service contract data.
12+
- PASS: Browser does not own runtime health state.
13+
- PASS: Does not actively check other environments.
14+
- PASS: Tests were updated.
15+
- PASS: Required reports were generated.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# PR_26175_CHARLIE_012 Validation Report
2+
3+
## Commands
4+
5+
- PASS: `node --check src/dev-runtime/server/local-api-router.mjs`
6+
- PASS: `node --check assets/theme-v2/js/admin-system-health.js`
7+
- PASS: `git diff --check`
8+
- Result: no whitespace errors; CRLF conversion warnings only.
9+
- PASS: `node --test tests/dev-runtime/AdminHealthOperations.test.mjs`
10+
- Result: 4 passed.
11+
- PASS: `npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line`
12+
- Result: 3 passed.
13+
14+
## Validation Lane
15+
16+
- Targeted System Health API/unit lane: PASS.
17+
- Targeted System Health Playwright lane: PASS.
18+
- Full samples smoke: not run; not required for this System Health-only slice.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# PR_26175_CHARLIE_012 Runtime Health
2+
3+
## Scope
4+
5+
Team: Charlie
6+
7+
Purpose: Add current-deployment Runtime Health to Admin System Health Phase 2.
8+
9+
## Changes
10+
11+
- Added server-owned `runtimeHealth` to the Admin System Health status API.
12+
- Added Runtime Health UI table for environment, app/runtime version, API version, Node version, server start time, uptime, and last checked.
13+
- Kept Runtime Environment masking as a separate existing section.
14+
- Updated API and Playwright System Health tests for the Runtime Health contract.
15+
16+
## Architecture Notes
17+
18+
- PASS: Current deployment only.
19+
- PASS: Environment Map remains reference-only.
20+
- PASS: Browser renders API-owned runtime health state.
21+
- PASS: No cross-environment runtime checks were added.
22+
- PASS: No secrets are exposed.
23+
24+
## Artifact
25+
26+
- `tmp/PR_26175_CHARLIE_012-runtime-health_delta.zip`
Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1-
docs_build/dev/reports/codex_changed_files.txt
2-
docs_build/dev/reports/codex_review.diff
3-
docs_build/dev/reports/coverage_changed_js_guardrail.txt
4-
docs_build/dev/reports/playwright_v8_coverage_report.txt
5-
docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md
6-
docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-branch-validation.md
7-
docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-manual-validation-notes.md
8-
docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-requirement-checklist.md
9-
docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-validation.md
10-
src/api/admin-owner-navigation.js
11-
tests/dev-runtime/ApiMenuPathCleanup.test.mjs
12-
tests/dev-runtime/ArchitectureCleanupApiNavInvitations.test.mjs
13-
tests/playwright/tools/AdminInvitationsNavPage.spec.mjs
14-
tests/playwright/tools/AdminOwnerNavigationBoundary.spec.mjs
1+
# git status --short
2+
M admin/system-health.html
3+
M assets/theme-v2/js/admin-system-health.js
4+
M docs_build/dev/reports/coverage_changed_js_guardrail.txt
5+
M docs_build/dev/reports/playwright_v8_coverage_report.txt
6+
M src/dev-runtime/server/local-api-router.mjs
7+
M tests/dev-runtime/AdminHealthOperations.test.mjs
8+
M tests/playwright/tools/AdminHealthOperationsPage.spec.mjs
9+
?? docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health-branch-validation.md
10+
?? docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health-manual-validation-notes.md
11+
?? docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health-requirement-checklist.md
12+
?? docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health-validation.md
13+
?? docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health.md
14+
15+
# git ls-files --others --exclude-standard
16+
docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health-branch-validation.md
17+
docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health-manual-validation-notes.md
18+
docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health-requirement-checklist.md
19+
docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health-validation.md
20+
docs_build/dev/reports/PR_26175_CHARLIE_012-runtime-health.md
21+
22+
# git diff --stat
23+
admin/system-health.html | 22 +++++++++
24+
assets/theme-v2/js/admin-system-health.js | 56 ++++++++++++++++++++++
25+
.../dev/reports/coverage_changed_js_guardrail.txt | 5 +-
26+
.../dev/reports/playwright_v8_coverage_report.txt | 30 +++++-------
27+
src/dev-runtime/server/local-api-router.mjs | 43 ++++++++++++++++-
28+
tests/dev-runtime/AdminHealthOperations.test.mjs | 7 +++
29+
.../tools/AdminHealthOperationsPage.spec.mjs | 9 ++++
30+
7 files changed, 150 insertions(+), 22 deletions(-)

0 commit comments

Comments
 (0)