Skip to content

Commit 5cf6a87

Browse files
committed
Clean up startup runtime diagnostics
1 parent 83c19bc commit 5cf6a87

13 files changed

Lines changed: 772 additions & 29 deletions
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# PR_26177_CHARLIE_034-startup-runtime-report-cleanup
2+
3+
Team: Charlie
4+
Branch: pr/26177-CHARLIE-034-startup-runtime-report-cleanup
5+
Base: pr/26177-CHARLIE-032-runtime-health-json-endpoints
6+
Lifecycle: Build / Validation
7+
Repair: Rebased onto repaired PR_26177_CHARLIE_032 branch on 2026-06-25.
8+
9+
## Scope
10+
- Polished Local API startup diagnostics with explicit Local API URL, local site URL, local site URL port, database mode, and storage status.
11+
- Kept runtime environment variable output deterministic and alphabetized.
12+
- Confirmed secret-like environment keys containing PASSWORD, SECRET, TOKEN, KEY, SERVICE_ROLE, or JWT remain masked.
13+
- Mirrored the safe diagnostics through the System Health API payload so the browser renders service-owned status.
14+
15+
## Changed Files
16+
- scripts/start-local-api-server.mjs
17+
- src/dev-runtime/server/local-api-router.mjs
18+
- tests/dev-runtime/LocalApiStartupLogging.test.mjs
19+
- tests/dev-runtime/AdminHealthOperations.test.mjs
20+
- tests/api/admin-system-health/contract.test.mjs
21+
- tests/playwright/tools/AdminHealthOperationsPage.spec.mjs
22+
- docs_build/dev/reports/coverage_changed_js_guardrail.txt
23+
- docs_build/dev/reports/playwright_v8_coverage_report.txt
24+
25+
## Validation
26+
- PASS: node --check scripts/start-local-api-server.mjs
27+
- PASS: node --check src/dev-runtime/server/local-api-router.mjs
28+
- PASS: node --test tests/dev-runtime/LocalApiStartupLogging.test.mjs
29+
- PASS: node --test tests/api/admin-system-health/contract.test.mjs
30+
- PASS: node --test tests/dev-runtime/AdminHealthOperations.test.mjs
31+
- PASS: npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line
32+
- PASS: git diff --check
33+
34+
## ZIP
35+
- Generated after repair: C:\Users\DavidQ\Documents\GitHub\HTML-JavaScript-Gaming\tmp\PR_26177_CHARLIE_034-startup-runtime-report-cleanup_delta.zip
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# PR_26177_CHARLIE_034 Branch Validation
2+
3+
Branch: pr/26177-CHARLIE-034-startup-runtime-report-cleanup
4+
Base: pr/26177-CHARLIE-032-runtime-health-json-endpoints
5+
6+
## Results
7+
- PASS: Continued the stacked Charlie workstream from PR_26177_CHARLIE_032.
8+
- PASS: Branch is based on repaired PR_26177_CHARLIE_032 branch.
9+
- PASS: Rebase conflict scope was generated report artifacts only.
10+
- PASS: Worktree was clean before edits.
11+
- PASS: Runtime changes are limited to Local API startup/runtime diagnostics.
12+
- PASS: No start_of_day files were modified.
13+
- PASS: No direct commit to main was made.
14+
- PASS: PR branch will be pushed for draft PR creation.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# PR_26177_CHARLIE_034 Manual Validation Notes
2+
3+
- Confirmed startup log output now prints Local API URL, local site URL, local site URL port, database mode, and storage status.
4+
- Confirmed `.env` diagnostic lines remain alphabetized by key.
5+
- Confirmed secret-like values are masked, including KEY and SERVICE_ROLE variables.
6+
- Confirmed System Health renders the new Local API startup diagnostics from the Local API payload.
7+
- Confirmed no browser-owned infrastructure health state was introduced.
8+
- Confirmed branch repair conflict was limited to generated report artifacts.
9+
- Confirmed no start_of_day files changed.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# PR_26177_CHARLIE_034 Requirement Checklist
2+
3+
- PASS: Polish Local API startup/runtime diagnostics.
4+
- PASS: Keep environment variables alphabetized.
5+
- PASS: Mask secrets containing PASSWORD, SECRET, TOKEN, KEY, SERVICE_ROLE, or JWT.
6+
- PASS: Include clear Local API URL.
7+
- PASS: Include local site URL and port when available.
8+
- PASS: Include database mode without exposing connection credentials.
9+
- PASS: Include storage status without exposing secrets.
10+
- PASS: Preserve existing startup and System Health behavior.
11+
- PASS: Do not modify unrelated files.
12+
- PASS: Do not modify start_of_day folders.
13+
- PASS: Do not introduce MEM DB, fake-login, silent fallbacks, or browser-owned infrastructure state.
14+
- PASS: Rebased onto repaired PR_26177_CHARLIE_032 branch.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# PR_26177_CHARLIE_034 Validation Lane
2+
3+
## Commands
4+
- PASS: node --check scripts/start-local-api-server.mjs
5+
- PASS: node --check src/dev-runtime/server/local-api-router.mjs
6+
- PASS: node --test tests/dev-runtime/LocalApiStartupLogging.test.mjs
7+
- PASS: node --test tests/api/admin-system-health/contract.test.mjs
8+
- PASS: node --test tests/dev-runtime/AdminHealthOperations.test.mjs
9+
- PASS: npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line
10+
- PASS: git diff --check
11+
12+
## Notes
13+
- `git diff --check` reported only expected Windows LF-to-CRLF working-copy warnings.
14+
- Full samples smoke was not run because this PR is scoped to Local API startup diagnostics and System Health rendering.
Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
1-
# git diff --name-only pr/26177-CHARLIE-031-environment-health-comparison --
2-
docs_build/dev/reports/PR_26177_CHARLIE_032-runtime-health-json-endpoints.md
3-
docs_build/dev/reports/PR_26177_CHARLIE_032-runtime-health-json-endpoints_branch-validation.md
4-
docs_build/dev/reports/PR_26177_CHARLIE_032-runtime-health-json-endpoints_manual-validation-notes.md
5-
docs_build/dev/reports/PR_26177_CHARLIE_032-runtime-health-json-endpoints_requirements-checklist.md
6-
docs_build/dev/reports/PR_26177_CHARLIE_032-runtime-health-json-endpoints_validation-lane.md
1+
# git diff --name-only pr/26177-CHARLIE-032-runtime-health-json-endpoints --
2+
docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup.md
3+
docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup_branch-validation.md
4+
docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup_manual-validation-notes.md
5+
docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup_requirements-checklist.md
6+
docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup_validation-lane.md
77
docs_build/dev/reports/codex_changed_files.txt
88
docs_build/dev/reports/codex_review.diff
9-
docs_build/dev/reports/coverage_changed_js_guardrail.txt
109
docs_build/dev/reports/playwright_v8_coverage_report.txt
10+
scripts/start-local-api-server.mjs
1111
src/dev-runtime/server/local-api-router.mjs
12-
tests/api/admin-system-health/contract.test.mjs
1312
tests/dev-runtime/AdminHealthOperations.test.mjs
13+
tests/dev-runtime/LocalApiStartupLogging.test.mjs
1414
tests/playwright/tools/AdminHealthOperationsPage.spec.mjs
1515

1616
# git status --short
17-
(no output)
17+
M docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup.md
18+
M docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup_branch-validation.md
19+
M docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup_manual-validation-notes.md
20+
M docs_build/dev/reports/PR_26177_CHARLIE_034-startup-runtime-report-cleanup_requirements-checklist.md
21+
M docs_build/dev/reports/codex_review.diff
22+
M docs_build/dev/reports/playwright_v8_coverage_report.txt
1823

19-
# git diff --stat pr/26177-CHARLIE-031-environment-health-comparison --
20-
...77_CHARLIE_032-runtime-health-json-endpoints.md | 30 ++++++++++
21-
...time-health-json-endpoints_branch-validation.md | 17 ++++++
22-
...ealth-json-endpoints_manual-validation-notes.md | 8 +++
23-
...health-json-endpoints_requirements-checklist.md | 13 +++++
24-
...untime-health-json-endpoints_validation-lane.md | 20 +++++++
25-
docs_build/dev/reports/codex_changed_files.txt | 66 ++++++++--------------
26-
docs_build/dev/reports/codex_review.diff | 2 +-
27-
.../dev/reports/coverage_changed_js_guardrail.txt | 1 -
28-
.../dev/reports/playwright_v8_coverage_report.txt | 2 -
29-
src/dev-runtime/server/local-api-router.mjs | 48 ++++++++++++++++
30-
tests/api/admin-system-health/contract.test.mjs | 9 +++
31-
tests/dev-runtime/AdminHealthOperations.test.mjs | 12 ++++
32-
.../tools/AdminHealthOperationsPage.spec.mjs | 2 +
33-
13 files changed, 185 insertions(+), 45 deletions(-)
24+
# git diff --stat pr/26177-CHARLIE-032-runtime-health-json-endpoints --
25+
...7_CHARLIE_034-startup-runtime-report-cleanup.md | 35 ++
26+
...tup-runtime-report-cleanup_branch-validation.md | 14 +
27+
...ntime-report-cleanup_manual-validation-notes.md | 9 +
28+
...untime-report-cleanup_requirements-checklist.md | 14 +
29+
...artup-runtime-report-cleanup_validation-lane.md | 14 +
30+
docs_build/dev/reports/codex_changed_files.txt | 59 ++-
31+
docs_build/dev/reports/codex_review.diff | 479 ++++++++++++++++++++-
32+
.../dev/reports/playwright_v8_coverage_report.txt | 3 +-
33+
scripts/start-local-api-server.mjs | 34 +-
34+
src/dev-runtime/server/local-api-router.mjs | 101 ++++-
35+
tests/dev-runtime/AdminHealthOperations.test.mjs | 7 +
36+
tests/dev-runtime/LocalApiStartupLogging.test.mjs | 32 ++
37+
.../tools/AdminHealthOperationsPage.spec.mjs | 6 +
38+
13 files changed, 771 insertions(+), 36 deletions(-)

docs_build/dev/reports/codex_review.diff

Lines changed: 478 additions & 1 deletion
Large diffs are not rendered by default.

docs_build/dev/reports/playwright_v8_coverage_report.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ Uncovered or low-coverage changed JS files:
3636
(0%) src/dev-runtime/server/local-api-router.mjs - WARNING: uncovered changed runtime JS file; advisory only
3737

3838
Changed JS files considered:
39+
(0%) scripts/start-local-api-server.mjs - changed JS file not collected as browser runtime coverage
3940
(0%) src/dev-runtime/server/local-api-router.mjs - changed JS file not collected as browser runtime coverage
40-
(0%) tests/api/admin-system-health/contract.test.mjs - changed JS file not collected as browser runtime coverage
4141
(0%) tests/dev-runtime/AdminHealthOperations.test.mjs - changed JS file not collected as browser runtime coverage
42+
(0%) tests/dev-runtime/LocalApiStartupLogging.test.mjs - changed JS file not collected as browser runtime coverage
4243
(0%) tests/playwright/tools/AdminHealthOperationsPage.spec.mjs - changed JS file not collected as browser runtime coverage

scripts/start-local-api-server.mjs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from "node:path";
44
import { pathToFileURL } from "node:url";
55
import { databaseSslMode } from "../src/dev-runtime/persistence/postgres-connection-client.mjs";
66
import { startLocalApiServer } from "../src/dev-runtime/server/local-api-server.mjs";
7+
import { loadStorageConfig } from "../src/dev-runtime/storage/storage-config.mjs";
78

89
const RUNTIME_ENV_FILE = ".env";
910
const NOT_CONFIGURED = "(not configured)";
@@ -181,6 +182,28 @@ function formatRuntimePortLogLines({ env, localServer }) {
181182
];
182183
}
183184

185+
function databaseMode(env) {
186+
const rawValue = String(env.GAMEFOUNDRY_DATABASE_URL || "").trim();
187+
if (!rawValue) {
188+
return "not configured";
189+
}
190+
try {
191+
const parsedUrl = new URL(rawValue);
192+
return ["postgres:", "postgresql:"].includes(parsedUrl.protocol) ? "Postgres" : "invalid database URL";
193+
} catch {
194+
return "invalid database URL";
195+
}
196+
}
197+
198+
function storageStatus(env) {
199+
const storageConfig = loadStorageConfig(env);
200+
if (storageConfig.configured) {
201+
return `configured (bucket ${storageConfig.safe.bucket}; prefix ${storageConfig.safe.projectsPrefix})`;
202+
}
203+
const issue = storageConfig.validationError || `missing ${storageConfig.missingKeys?.join(", ") || "storage configuration"}`;
204+
return `not configured (${issue})`;
205+
}
206+
184207
export function formatStartupLogLines({
185208
accountConnection,
186209
configuredDatabaseSslMode,
@@ -190,14 +213,21 @@ export function formatStartupLogLines({
190213
localServer,
191214
runtimeEnv,
192215
}) {
216+
const configuredApiUrl = String(env.GAMEFOUNDRY_API_URL || "").trim() || defaultApiUrl(localServer.baseUrl);
217+
const configuredSiteUrl = configuredValue(env.GAMEFOUNDRY_SITE_URL);
193218
return [
194219
`GameFoundry API runtime server running at ${localServer.baseUrl}`,
195-
`Configured site URL: ${configuredValue(env.GAMEFOUNDRY_SITE_URL)}`,
196-
`Configured API URL: ${String(env.GAMEFOUNDRY_API_URL || "").trim() || defaultApiUrl(localServer.baseUrl)}`,
220+
`Configured site URL: ${configuredSiteUrl}`,
221+
`Configured API URL: ${configuredApiUrl}`,
222+
`Local API URL: ${configuredApiUrl}`,
223+
`Local site URL: ${configuredSiteUrl}`,
224+
`Local site URL port: ${portFromUrl(env.GAMEFOUNDRY_SITE_URL)}`,
197225
...formatEnvironmentVariableLogLines(runtimeEnv),
198226
...formatRuntimePortLogLines({ env, localServer }),
199227
connectionStatusLine("auth", accountConnection),
200228
connectionStatusLine("database", databaseConnection),
229+
`Database mode: ${databaseMode(env)}`,
230+
`Storage status: ${storageStatus(env)}`,
201231
`Database SSL mode: ${configuredDatabaseSslMode || `invalid (${databaseSslModeError})`}`,
202232
"Press Ctrl+C to stop.",
203233
];

src/dev-runtime/server/local-api-router.mjs

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,13 @@ function localApiStartupUrlDisplay(value, fallback = "not configured") {
904904
}
905905
}
906906

907+
function localApiStartupPortStatus(port) {
908+
if (port === "invalid URL") {
909+
return "FAIL";
910+
}
911+
return port === "not configured" ? "WARN" : "PASS";
912+
}
913+
907914
function localApiStartupBindTarget(env = process.env) {
908915
const host = String(env.GAMEFOUNDRY_LOCAL_API_HOST || LOCAL_API_STARTUP_DEFAULT_HOST).trim() || LOCAL_API_STARTUP_DEFAULT_HOST;
909916
const port = String(env.GAMEFOUNDRY_LOCAL_API_PORT || LOCAL_API_STARTUP_DEFAULT_PORT).trim() || LOCAL_API_STARTUP_DEFAULT_PORT;
@@ -916,11 +923,57 @@ function localApiStartupBindTarget(env = process.env) {
916923
};
917924
}
918925

926+
function localApiStartupDatabaseMode(env = process.env) {
927+
const databaseStatus = databaseConfigStatus(env);
928+
if (databaseStatus.hostStatus === "FAIL" || databaseStatus.databaseNameStatus === "FAIL") {
929+
return {
930+
reason: "GAMEFOUNDRY_DATABASE_URL is present but is not a valid Postgres URL.",
931+
status: "FAIL",
932+
value: "invalid database URL",
933+
};
934+
}
935+
if (!databaseStatus.configured) {
936+
return {
937+
reason: "GAMEFOUNDRY_DATABASE_URL is not configured for the Local API startup report.",
938+
status: "WARN",
939+
value: "not configured",
940+
};
941+
}
942+
return {
943+
reason: "GAMEFOUNDRY_DATABASE_URL is configured with a Postgres protocol; credentials remain hidden.",
944+
status: "PASS",
945+
value: "Postgres",
946+
};
947+
}
948+
949+
function localApiStartupStorageStatus(env = process.env) {
950+
const storageConfig = loadStorageConfig(env);
951+
if (storageConfig.configured) {
952+
return {
953+
reason: `Cloudflare R2 configuration is present for bucket ${storageConfig.safe.bucket} and prefix ${storageConfig.safe.projectsPrefix}; credential values remain hidden.`,
954+
status: "PASS",
955+
value: "configured",
956+
};
957+
}
958+
const issue = storageConfig.validationError
959+
|| `missing ${storageConfig.missingKeys?.join(", ") || "storage configuration"}`;
960+
return {
961+
reason: `Cloudflare R2 storage is not fully configured: ${issue}.`,
962+
status: "WARN",
963+
value: "not configured",
964+
};
965+
}
966+
919967
function systemHealthLocalApiStartupDiagnostics(env = process.env) {
920968
const bindTarget = localApiStartupBindTarget(env);
921969
const configuredApiUrl = String(env.GAMEFOUNDRY_API_URL || "").trim();
922970
const derivedApiUrl = `http://${bindTarget.value}/api`;
923971
const siteUrl = String(env.GAMEFOUNDRY_SITE_URL || "").trim();
972+
const apiUrlDisplay = localApiStartupUrlDisplay(configuredApiUrl || derivedApiUrl);
973+
const siteUrlDisplay = localApiStartupUrlDisplay(siteUrl);
974+
const siteUrlPort = localApiStartupPortFromUrl(siteUrl);
975+
const databaseMode = localApiStartupDatabaseMode(env);
976+
const storageStatus = localApiStartupStorageStatus(env);
924977
const rows = [
925978
{
926979
field: "Approved diagnostics format",
@@ -934,6 +987,18 @@ function systemHealthLocalApiStartupDiagnostics(env = process.env) {
934987
status: "PASS",
935988
value: "masked and redacted",
936989
},
990+
{
991+
field: "Environment variable order",
992+
reason: "Runtime .env keys are sorted alphabetically before startup diagnostics are printed.",
993+
status: "PASS",
994+
value: "alphabetical",
995+
},
996+
{
997+
field: "Secret masking markers",
998+
reason: "Startup diagnostics mask variables whose keys contain PASSWORD, SECRET, TOKEN, KEY, SERVICE_ROLE, or JWT.",
999+
status: "PASS",
1000+
value: "PASSWORD, SECRET, TOKEN, KEY, SERVICE_ROLE, JWT",
1001+
},
9371002
{
9381003
field: "Configured startup bind target",
9391004
reason: bindTarget.status === "PASS"
@@ -942,6 +1007,28 @@ function systemHealthLocalApiStartupDiagnostics(env = process.env) {
9421007
status: bindTarget.status,
9431008
value: bindTarget.value,
9441009
},
1010+
{
1011+
field: "Local API URL",
1012+
reason: configuredApiUrl
1013+
? "GAMEFOUNDRY_API_URL is configured and displayed without URL credentials."
1014+
: "GAMEFOUNDRY_API_URL is not configured; startup diagnostics derive /api from the bind target.",
1015+
status: apiUrlDisplay === "invalid URL" ? "FAIL" : "PASS",
1016+
value: apiUrlDisplay,
1017+
},
1018+
{
1019+
field: "Local site URL",
1020+
reason: siteUrl
1021+
? "GAMEFOUNDRY_SITE_URL is available for startup diagnostics."
1022+
: "GAMEFOUNDRY_SITE_URL is not configured for the Local API startup report.",
1023+
status: siteUrl ? (siteUrlDisplay === "invalid URL" ? "FAIL" : "PASS") : "WARN",
1024+
value: siteUrlDisplay,
1025+
},
1026+
{
1027+
field: "Local site URL port",
1028+
reason: "Port is derived from GAMEFOUNDRY_SITE_URL for display only.",
1029+
status: localApiStartupPortStatus(siteUrlPort),
1030+
value: siteUrlPort,
1031+
},
9451032
{
9461033
field: "Configured site URL",
9471034
reason: siteUrl
@@ -956,14 +1043,26 @@ function systemHealthLocalApiStartupDiagnostics(env = process.env) {
9561043
? "GAMEFOUNDRY_API_URL is configured and displayed without URL credentials."
9571044
: "GAMEFOUNDRY_API_URL is not configured; startup diagnostics derive /api from the bind target.",
9581045
status: "PASS",
959-
value: localApiStartupUrlDisplay(configuredApiUrl || derivedApiUrl),
1046+
value: apiUrlDisplay,
9601047
},
9611048
{
9621049
field: "Configured API URL port",
9631050
reason: "Port is derived from the configured or startup-derived API URL for display only.",
9641051
status: "PASS",
9651052
value: localApiStartupPortFromUrl(configuredApiUrl || derivedApiUrl),
9661053
},
1054+
{
1055+
field: "Database mode",
1056+
reason: databaseMode.reason,
1057+
status: databaseMode.status,
1058+
value: databaseMode.value,
1059+
},
1060+
{
1061+
field: "Storage status",
1062+
reason: storageStatus.reason,
1063+
status: storageStatus.status,
1064+
value: storageStatus.value,
1065+
},
9671066
{
9681067
field: "Configurable multiple runtime ports",
9691068
reason: "Configurable multiple runtime ports are explicitly deferred/cancelled for this PR.",

0 commit comments

Comments
 (0)