diff --git a/admin/system-health.html b/admin/system-health.html index b4b9f477f..8573b3310 100644 --- a/admin/system-health.html +++ b/admin/system-health.html @@ -43,6 +43,7 @@

Admin

Local API Startup

Database Health

Storage Health

+

Health Check History

Runtime Environment

Limits & Capacity

Diagnostics Plan

@@ -143,11 +144,29 @@

System Health Tables

- BucketConfigured bucket placeholderPENDING - ListObjects prefixPENDING - ReadHealth objectPENDING - WriteHealth objectPENDING - DeleteHealth objectPENDING + Bucket connectivityLoadingPENDING + ListLoadingPENDING + UploadLoadingPENDING + ReadLoadingPENDING + DeleteLoadingPENDING + Last checkedLoadingPENDING + + + +
+ + + + + + + + + + + + +
Health Check History
TimeEnvironmentAreaResultSummary
LoadingLoadingCurrent environmentPENDINGWaiting for safe API status.
diff --git a/assets/theme-v2/js/admin-system-health.js b/assets/theme-v2/js/admin-system-health.js index 61b446a3e..e0c2cab9f 100644 --- a/assets/theme-v2/js/admin-system-health.js +++ b/assets/theme-v2/js/admin-system-health.js @@ -9,8 +9,9 @@ import { } from "../../js/shared/status.js"; const STORAGE_DIAGNOSTIC_ACTIONS = Object.freeze([ + Object.freeze({ actionId: "storage-bucket-connectivity", key: "bucket" }), Object.freeze({ actionId: "storage-list", key: "list" }), - Object.freeze({ actionId: "storage-write-test-object", key: "write" }), + Object.freeze({ actionId: "storage-upload-test-object", key: "upload" }), Object.freeze({ actionId: "storage-read-test-object", key: "read" }), Object.freeze({ actionId: "storage-delete-test-object", key: "delete" }), ]); @@ -46,6 +47,7 @@ class AdminSystemHealthController { node.dataset.adminSystemHealthStorageStatus, node, ])); + this.historyRows = root.querySelector("[data-admin-system-health-history-rows]"); this.startupRows = root.querySelector("[data-admin-system-health-startup-rows]"); this.runtimeRows = root.querySelector("[data-admin-system-health-runtime-rows]"); } @@ -106,6 +108,7 @@ class AdminSystemHealthController { }); this.renderStartupPending(reason); this.renderStoragePending(reason); + this.renderHistoryPending(reason); } renderEnvironmentIdentity(environmentIdentity = {}) { @@ -127,7 +130,7 @@ class AdminSystemHealthController { } renderStoragePending(reason) { - ["bucket", "list", "read", "write", "delete"].forEach((key) => { + ["bucket", "list", "upload", "read", "delete", "lastChecked"].forEach((key) => { this.setStorageStatus(key, "PENDING", reason); }); this.renderRuntimePending(reason); @@ -153,8 +156,10 @@ class AdminSystemHealthController { renderStorageStatus(storageStatus = {}) { const reason = storageStatus.message || "Cloudflare R2 configuration status returned by the safe Admin System Health API."; - this.setStorageValue("bucket", storageStatus.bucket, "not configured"); + this.setStorageValue("bucket", storageStatus.environmentFolder ? `${storageStatus.bucket || "not configured"} ${storageStatus.environmentFolder}` : storageStatus.bucket, "not configured"); this.setStorageStatus("bucket", storageStatus.bucketStatus || storageStatus.status, reason); + this.setStorageValue("lastChecked", storageStatus.lastChecked, "not available"); + this.setStorageStatus("lastChecked", storageStatus.lastChecked ? "PASS" : "WARN", reason); } renderStartupPending(reason) { @@ -198,9 +203,12 @@ class AdminSystemHealthController { storageResultTarget(result = {}) { if (typeof result.keysListed === "number" && result.actionId === "storage-list") { - return `${result.keysListed} object(s) under ${asText(result.projectsPrefix, "configured prefix")}`; + return `${result.keysListed} object(s) under ${asText(result.environmentFolder, "current environment folder")}`; } - return result.testObjectKey || result.projectsPrefix || result.message || "diagnostic target unavailable"; + if (result.actionId === "storage-bucket-connectivity") { + return result.environmentFolder || result.message || "bucket connectivity target unavailable"; + } + return result.testObjectKey || result.environmentFolder || result.message || "diagnostic target unavailable"; } renderStorageResult(key, result = {}) { @@ -210,6 +218,49 @@ class AdminSystemHealthController { } this.setStorageValue(key, this.storageResultTarget(result)); this.setStorageStatus(key, result.status, result.message || "R2 diagnostic returned without a message."); + if (result.lastChecked) { + this.setStorageValue("lastChecked", result.lastChecked); + this.setStorageStatus("lastChecked", "PASS", "Most recent current-environment R2 health check timestamp."); + } + } + + renderHistoryPending(reason) { + if (!this.historyRows) { + return; + } + const row = document.createElement("tr"); + row.append( + this.createCell("not available"), + this.createCell("current environment"), + this.createCell("Health Check History"), + this.createStatusCell("PENDING", reason), + this.createCell("Safe health check history is not available."), + ); + this.historyRows.replaceChildren(row); + } + + renderHealthCheckHistory(historyRows = []) { + if (!this.historyRows) { + return; + } + const rows = Array.isArray(historyRows) ? historyRows : []; + if (!rows.length) { + this.renderHistoryPending("Safe Admin System Health API returned no current-environment health check history rows."); + return; + } + const fragment = document.createDocumentFragment(); + rows.forEach((historyRow) => { + const row = document.createElement("tr"); + row.append( + this.createCell(historyRow.checkedAt), + this.createCell(historyRow.environmentName), + this.createCell(historyRow.area), + this.createStatusCell(historyRow.result || historyRow.status, historyRow.summary), + this.createCell(historyRow.summary), + ); + fragment.append(row); + }); + this.historyRows.replaceChildren(fragment); } runStorageDiagnostics() { @@ -292,6 +343,7 @@ class AdminSystemHealthController { this.renderStartupDiagnostics(data?.localApiStartup || {}); this.renderStorageStatus(data?.storageStatus || {}); this.runStorageDiagnostics(); + this.renderHealthCheckHistory(data?.healthCheckHistory || []); this.renderRuntimeEnvironment(data?.runtimeEnvironment || {}); } catch (error) { const message = error instanceof Error ? error.message : "Safe Admin System Health API is unavailable."; diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_009-system-health-current-r2-health.md b/docs_build/dev/reports/PR_26175_CHARLIE_009-system-health-current-r2-health.md new file mode 100644 index 000000000..a0cd45bc9 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_CHARLIE_009-system-health-current-r2-health.md @@ -0,0 +1,41 @@ +# PR_26175_CHARLIE_009 System Health Current R2 Health + +## Scope + +Team: Charlie + +Purpose: Add current-environment Cloudflare R2 folder health only to Admin System Health. + +## Changes + +- Replaced the System Health Storage Health rows with current-environment R2 checks: + - bucket connectivity + - list + - upload + - read + - delete + - last checked +- System Health storage diagnostics run against the current environment folder only: + - Local: `/local` + - DEV: `/dev` + - IST: `/ist` + - UAT: `/uat` + - PRD: `/prd` +- Preserved the separate Admin Infrastructure storage diagnostic path that uses the configured project prefix. +- Updated focused API and Playwright tests. + +## Architecture Constraint + +PASS. R2 health checks target only the current deployment environment folder. No peer environment R2 folders are actively checked by System Health. + +## Validation + +- PASS: `node --check src/dev-runtime/server/local-api-router.mjs` +- PASS: `node --check assets/theme-v2/js/admin-system-health.js` +- PASS: `git diff --check` +- PASS: `node --test tests/dev-runtime/AdminHealthOperations.test.mjs` +- PASS: `npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line` + +## Artifact + +- `tmp/PR_26175_CHARLIE_009-system-health-current-r2-health_delta.zip` diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_010-system-health-history-and-closeout.md b/docs_build/dev/reports/PR_26175_CHARLIE_010-system-health-history-and-closeout.md new file mode 100644 index 000000000..c8f5ff396 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_CHARLIE_010-system-health-history-and-closeout.md @@ -0,0 +1,68 @@ +# PR_26175_CHARLIE_010 System Health History and Closeout + +## Scope + +Team: Charlie + +Purpose: Add current-environment Health Check History and close out the System Health stacked expansion chain. + +## Chain + +- `PR_26175_CHARLIE_006-project-instructions-system-health-infrastructure` + - Branch: `PR_26175_CHARLIE_006-project-instructions-system-health-infrastructure` + - Commit: `c870b812faded383094fb13fc60ae9cfc7f14889` + - Result: pushed to origin, not merged. +- `PR_26175_CHARLIE_007-system-health-environment-identity` + - Branch: `pr/26175-CHARLIE-007-system-health-environment-identity` + - Commit: `6556e73efcd8ae13b51b56288416c88688e67634` + - Draft PR: https://github.com/ToolboxAid/HTML-JavaScript-Gaming/pull/151 +- `PR_26175_CHARLIE_008-system-health-current-database-health` + - Branch: `pr/26175-CHARLIE-008-system-health-current-database-health` + - Commit: `2603aeb6e5a7ccca516051953cbd70a5a6c94c4b` + - Draft PR: https://github.com/ToolboxAid/HTML-JavaScript-Gaming/pull/152 +- `PR_26175_CHARLIE_009-system-health-current-r2-health` + - Branch: `pr/26175-CHARLIE-009-system-health-current-r2-health` + - Commit: `9740705fbe73dffd43744ab66338f8e4a925eed4` + - Draft PR: https://github.com/ToolboxAid/HTML-JavaScript-Gaming/pull/153 +- `PR_26175_CHARLIE_010-system-health-history-and-closeout` + - Branch: `pr/26175-CHARLIE-010-system-health-history-and-closeout` + - Commit and draft PR URL are assigned after this report is committed and pushed. + +## Changes + +- Added Health Check History to the Admin System Health page. +- Health Check History is derived from the current deployment only: + - Environment Summary + - Database Health + - Storage Health + - Runtime Health +- Warning and failure rows are generated only from current-environment health rows. +- Creator sessions remain blocked from Admin System Health and do not trigger status or storage health requests. + +## Governance + +- PASS: System Health is one page per deployed environment. +- PASS: Each deployment actively checks only itself. +- PASS: The Environment Map remains a static reference for Local, DEV, IST, UAT, and PRD. +- PASS: System Health does not actively check peer databases or peer R2 folders. +- PASS: Cancelled initiatives remain not doing: + - Environment Isolation & Developer Experience + - multi-port workspace framework + - Alpha/Beta/User runtime separation + - runtime port management initiative + +## Validation + +- PASS: `node --check src/dev-runtime/server/local-api-router.mjs` +- PASS: `node --check assets/theme-v2/js/admin-system-health.js` +- PASS: `git diff --check` +- PASS: `node --test tests/dev-runtime/AdminHealthOperations.test.mjs` +- PASS: `node --test tests/dev-runtime/PublicEnvironmentConfig.test.mjs` +- PASS: `npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line` + +## Artifacts + +- `tmp/PR_26175_CHARLIE_007-system-health-environment-identity_delta.zip` +- `tmp/PR_26175_CHARLIE_008-system-health-current-database-health_delta.zip` +- `tmp/PR_26175_CHARLIE_009-system-health-current-r2-health_delta.zip` +- `tmp/PR_26175_CHARLIE_010-system-health-history-and-closeout_delta.zip` diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-branch-validation.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-branch-validation.md new file mode 100644 index 000000000..e2d3a2b30 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-branch-validation.md @@ -0,0 +1,15 @@ +# PR_26175_CHARLIE_011 Branch Validation + +## Start Gate + +- PASS: Current branch was `pr/26175-CHARLIE-010-system-health-history-and-closeout`. +- PASS: Worktree was clean before implementation. +- PASS: Build remained on the current Charlie continuation branch. +- PASS: No rebase was performed. +- PASS: No new root branch was created. + +## Final Branch Target + +- Branch to push: `pr/26175-CHARLIE-010-system-health-history-and-closeout` +- Expected draft PR to update: https://github.com/ToolboxAid/HTML-JavaScript-Gaming/pull/155 +- Merge status: no merge requested or performed. diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-manual-validation-notes.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-manual-validation-notes.md new file mode 100644 index 000000000..e8b6eae26 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-manual-validation-notes.md @@ -0,0 +1,26 @@ +# PR_26175_CHARLIE_011 Manual Validation Notes + +## Admin Submenu Order + +Visible labels after the change: + +`Admin Tools`, `Analytics`, `Controls`, `Creators`, `DB Viewer`, `Environments`, `Game Migration`, `Infrastructure`, `Invites`, `Moderation`, `Operations`, `Platform Settings`, `Ratings`, `Responsibilities`, `Site Setup`, `System Health`, `Tool Votes` + +## Route Preservation + +The only source navigation reorder moved this existing item: + +- `Creators` + - path remained `admin/users.html` + - route remained `admin-users` + - label remained `Creators` + +All other Admin navigation objects remained unchanged. + +## Open-Page Check + +The targeted Playwright navigation test collected every active Admin submenu href from the rendered submenu and requested each page through the local test server. Every response returned a status below HTTP 400. + +## Duplicate Check + +The targeted Playwright navigation test checks for duplicate rendered labels and duplicate active hrefs. The targeted unit script also checks duplicate labels and existing active paths. diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-requirement-checklist.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-requirement-checklist.md new file mode 100644 index 000000000..39afb7966 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-requirement-checklist.md @@ -0,0 +1,42 @@ +# PR_26175_CHARLIE_011 Requirement Checklist + +## Branch Rules + +- PASS: Continued on `pr/26175-CHARLIE-010-system-health-history-and-closeout`. +- PASS: Did not return to `main`. +- PASS: Did not rebase. +- PASS: Did not create a new root branch. +- PASS: Hard stop conditions were checked before implementation. + +## Objective + +- PASS: Admin submenu entries are alphabetized by displayed text. + +## Scope + +- PASS: Located Admin submenu definition in `src/api/admin-owner-navigation.js`. +- PASS: Sorted submenu entries by displayed text. +- PASS: Preserved routes, URLs, IDs, CSS classes, Theme V2 styling, and existing renderer behavior. +- PASS: Did not rename pages. +- PASS: Did not rename folders. +- PASS: Did not modify page content. +- PASS: No unrelated cleanup. + +## Validation + +- PASS: Verified submenu labels are alphabetical. +- PASS: Verified every Admin page path exists and every Admin submenu href opens below HTTP 400 in targeted Playwright. +- PASS: Verified no duplicate labels or hrefs. +- PASS: Ran affected Playwright navigation tests. +- PASS: Ran affected targeted unit tests. + +## Artifacts + +- PASS: `docs_build/dev/reports/codex_review.diff` +- PASS: `docs_build/dev/reports/codex_changed_files.txt` +- PASS: `docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md` +- PASS: validation report +- PASS: branch validation report +- PASS: requirement checklist +- PASS: manual validation notes +- PASS: repository ZIP under `tmp/` diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-validation.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-validation.md new file mode 100644 index 000000000..aeec3f443 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-validation.md @@ -0,0 +1,22 @@ +# PR_26175_CHARLIE_011 Validation Report + +## Commands + +- PASS: `node --check src/api/admin-owner-navigation.js` +- PASS: `node --input-type=module` alphabetical/duplicate/path verification script + - Result: `PASS labels=17 active=16` + - Order: `Admin Tools | Analytics | Controls | Creators | DB Viewer | Environments | Game Migration | Infrastructure | Invites | Moderation | Operations | Platform Settings | Ratings | Responsibilities | Site Setup | System Health | Tool Votes` +- PASS: `git diff --check` + - Result: no whitespace errors; CRLF conversion warnings only. +- PASS: `node --test tests/dev-runtime/ApiMenuPathCleanup.test.mjs` + - Result: 6 passed. +- PASS: `node --test --test-name-pattern "Admin and Owner navigation are shared" tests/dev-runtime/ArchitectureCleanupApiNavInvitations.test.mjs` + - Result: 1 passed. +- PASS: `npx playwright test tests/playwright/tools/AdminOwnerNavigationBoundary.spec.mjs --workers=1 --reporter=line` + - Result: 4 passed. +- PASS: `npx playwright test tests/playwright/tools/AdminInvitationsNavPage.spec.mjs --workers=1 --reporter=line` + - Result: 3 passed. + +## Note + +A non-targeted full-file run of `tests/dev-runtime/ArchitectureCleanupApiNavInvitations.test.mjs` was not used for final validation because its first non-navigation test fails on a pre-existing missing `src/engine/api` directory assertion. The affected navigation subtest passed by name. diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md new file mode 100644 index 000000000..7dcbe5262 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md @@ -0,0 +1,47 @@ +# PR_26175_CHARLIE_011 Admin Submenu Alphabetical Order + +## Scope + +Team: Charlie + +Purpose: Alphabetize the Admin submenu by visible menu labels only. + +## Branch + +- Continuation branch: `pr/26175-CHARLIE-010-system-health-history-and-closeout` +- Start gate: PASS + - Current branch matched the expected Charlie continuation branch. + - Worktree was clean before implementation. + +## Changes + +- Moved `Creators` into its alphabetical position in `src/api/admin-owner-navigation.js`. +- Preserved each Admin menu item label, path, route id, disabled state, and renderer behavior. +- Updated affected navigation tests that pin visible Admin menu label order. +- Added Playwright coverage of: + - alphabetical visible label order + - duplicate detection + - duplicate href detection + - each Admin submenu href opening with an HTTP status below 400 + +## Non-Changes + +- No page files were renamed. +- No folders were renamed. +- No page content was modified. +- No routes, URLs, permissions, icons, IDs, CSS classes, Theme V2 styling, or event handlers were changed. +- No menu outside the Admin submenu was reordered. + +## Validation Summary + +- PASS: Admin labels are alphabetical. +- PASS: No duplicate Admin labels. +- PASS: No duplicate Admin hrefs. +- PASS: Every active Admin submenu item points to an existing page path. +- PASS: Every Admin submenu href opened with an HTTP status below 400 in the targeted Playwright navigation test. +- PASS: Targeted unit tests passed. +- PASS: Targeted Playwright navigation tests passed. + +## Artifact + +- `tmp/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order_delta.zip` diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt index b4511a59b..5efcd7443 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt @@ -1,30 +1,21 @@ -# git diff --cached --name-status origin/main -M assets/toolbox/idea-board/js/index.js -A docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_branch-validation.md -A docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_instruction-compliance.md -A docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_manual-validation-notes.md -A docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_report.md -A docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_requirements-checklist.md -A docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_validation-lane.md -M docs_build/dev/reports/codex_changed_files.txt -M docs_build/dev/reports/codex_review.diff -M docs_build/dev/reports/coverage_changed_js_guardrail.txt -M docs_build/dev/reports/playwright_v8_coverage_report.txt -M tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -M tests/playwright/tools/ToolboxRoutePages.spec.mjs - -# git diff --cached --stat origin/main - assets/toolbox/idea-board/js/index.js | 31 +- - ...d-guest-save-auth-redirect_branch-validation.md | 22 + - ...st-save-auth-redirect_instruction-compliance.md | 31 + - ...t-save-auth-redirect_manual-validation-notes.md | 37 ++ - ...1-idea-board-guest-save-auth-redirect_report.md | 51 ++ - ...st-save-auth-redirect_requirements-checklist.md | 19 + - ...ard-guest-save-auth-redirect_validation-lane.md | 36 ++ - docs_build/dev/reports/codex_changed_files.txt | 33 +- - docs_build/dev/reports/codex_review.diff | 695 +++++++++++++++++---- - .../dev/reports/coverage_changed_js_guardrail.txt | 10 +- - .../dev/reports/playwright_v8_coverage_report.txt | 39 +- - .../playwright/tools/IdeaBoardTableNotes.spec.mjs | 118 +++- - tests/playwright/tools/ToolboxRoutePages.spec.mjs | 5 +- - 13 files changed, 941 insertions(+), 186 deletions(-) +admin/system-health.html +assets/theme-v2/js/admin-system-health.js +docs_build/dev/reports/PR_26175_CHARLIE_009-system-health-current-r2-health.md +docs_build/dev/reports/PR_26175_CHARLIE_010-system-health-history-and-closeout.md +docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-branch-validation.md +docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-manual-validation-notes.md +docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-requirement-checklist.md +docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-validation.md +docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md +docs_build/dev/reports/codex_changed_files.txt +docs_build/dev/reports/codex_review.diff +docs_build/dev/reports/coverage_changed_js_guardrail.txt +docs_build/dev/reports/playwright_v8_coverage_report.txt +src/api/admin-owner-navigation.js +src/dev-runtime/server/local-api-router.mjs +tests/dev-runtime/AdminHealthOperations.test.mjs +tests/dev-runtime/ApiMenuPathCleanup.test.mjs +tests/dev-runtime/ArchitectureCleanupApiNavInvitations.test.mjs +tests/playwright/tools/AdminHealthOperationsPage.spec.mjs +tests/playwright/tools/AdminInvitationsNavPage.spec.mjs +tests/playwright/tools/AdminOwnerNavigationBoundary.spec.mjs diff --git a/docs_build/dev/reports/codex_review.diff b/docs_build/dev/reports/codex_review.diff index 360819abd..67ec1ada8 100644 --- a/docs_build/dev/reports/codex_review.diff +++ b/docs_build/dev/reports/codex_review.diff @@ -1,571 +1,1112 @@ -diff --git a/assets/toolbox/idea-board/js/index.js b/assets/toolbox/idea-board/js/index.js -index 25607bc8d..0c10d2dc1 100644 ---- a/assets/toolbox/idea-board/js/index.js -+++ b/assets/toolbox/idea-board/js/index.js -@@ -437,6 +437,7 @@ function ideaIdFromText(text) { - } - - function saveIdeaRow(root, row) { -+ if (!requireAuthenticatedWrite(root)) return; - const idea = row.querySelector("[data-idea-board-idea-input]")?.value.trim(); - const pitch = row.querySelector("[data-idea-board-pitch-input]")?.value.trim(); - const status = row.querySelector("[data-idea-board-idea-status-input]")?.value; -@@ -479,6 +480,7 @@ function saveIdeaRow(root, row) { - } - - function saveNoteRow(root, row) { -+ if (!requireAuthenticatedWrite(root)) return; - const ideaId = row.dataset.ideaId; - const idea = ideaRecord(ideaId); - if (idea && isLockedIdea(idea)) { -@@ -533,6 +535,7 @@ function toggleNotes(root, ideaId) { - } - - function deleteIdea(root, ideaId) { -+ if (!requireAuthenticatedWrite(root)) return; - const index = ideaTable.findIndex((record) => record.ideaId === ideaId); - if (index < 0) { - updateStatus(root, "Idea Board could not delete that idea."); -@@ -588,6 +591,20 @@ function currentSessionState() { - } - } - -+function requireAuthenticatedWrite(root) { -+ const sessionState = currentSessionState(); -+ if (!sessionState.apiAvailable) { -+ updateStatus(root, "API session status could not be verified. Try again shortly."); -+ return false; -+ } -+ if (!sessionState.authenticated) { -+ updateStatus(root, "Sign in before saving Idea Board changes."); -+ window.location.href = signInUrl(); -+ return false; -+ } -+ return true; -+} +diff --git a/admin/system-health.html b/admin/system-health.html +index b4b9f477f..8573b3310 100644 +--- a/admin/system-health.html ++++ b/admin/system-health.html +@@ -43,6 +43,7 @@ +

Local API Startup

+

Database Health

+

Storage Health

++

Health Check History

+

Runtime Environment

+

Limits & Capacity

+

Diagnostics Plan

+@@ -143,11 +144,29 @@ + + + +- BucketConfigured bucket placeholderPENDING +- ListObjects prefixPENDING +- ReadHealth objectPENDING +- WriteHealth objectPENDING +- DeleteHealth objectPENDING ++ Bucket connectivityLoadingPENDING ++ ListLoadingPENDING ++ UploadLoadingPENDING ++ ReadLoadingPENDING ++ DeleteLoadingPENDING ++ Last checkedLoadingPENDING ++ ++ ++ ++
++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +
Health Check History
TimeEnvironmentAreaResultSummary
LoadingLoadingCurrent environmentPENDINGWaiting for safe API status.
+
+diff --git a/assets/theme-v2/js/admin-system-health.js b/assets/theme-v2/js/admin-system-health.js +index 61b446a3e..e0c2cab9f 100644 +--- a/assets/theme-v2/js/admin-system-health.js ++++ b/assets/theme-v2/js/admin-system-health.js +@@ -9,8 +9,9 @@ import { + } from "../../js/shared/status.js"; + + const STORAGE_DIAGNOSTIC_ACTIONS = Object.freeze([ ++ Object.freeze({ actionId: "storage-bucket-connectivity", key: "bucket" }), + Object.freeze({ actionId: "storage-list", key: "list" }), +- Object.freeze({ actionId: "storage-write-test-object", key: "write" }), ++ Object.freeze({ actionId: "storage-upload-test-object", key: "upload" }), + Object.freeze({ actionId: "storage-read-test-object", key: "read" }), + Object.freeze({ actionId: "storage-delete-test-object", key: "delete" }), + ]); +@@ -46,6 +47,7 @@ class AdminSystemHealthController { + node.dataset.adminSystemHealthStorageStatus, + node, + ])); ++ this.historyRows = root.querySelector("[data-admin-system-health-history-rows]"); + this.startupRows = root.querySelector("[data-admin-system-health-startup-rows]"); + this.runtimeRows = root.querySelector("[data-admin-system-health-runtime-rows]"); + } +@@ -106,6 +108,7 @@ class AdminSystemHealthController { + }); + this.renderStartupPending(reason); + this.renderStoragePending(reason); ++ this.renderHistoryPending(reason); + } + + renderEnvironmentIdentity(environmentIdentity = {}) { +@@ -127,7 +130,7 @@ class AdminSystemHealthController { + } + + renderStoragePending(reason) { +- ["bucket", "list", "read", "write", "delete"].forEach((key) => { ++ ["bucket", "list", "upload", "read", "delete", "lastChecked"].forEach((key) => { + this.setStorageStatus(key, "PENDING", reason); + }); + this.renderRuntimePending(reason); +@@ -153,8 +156,10 @@ class AdminSystemHealthController { + + renderStorageStatus(storageStatus = {}) { + const reason = storageStatus.message || "Cloudflare R2 configuration status returned by the safe Admin System Health API."; +- this.setStorageValue("bucket", storageStatus.bucket, "not configured"); ++ this.setStorageValue("bucket", storageStatus.environmentFolder ? `${storageStatus.bucket || "not configured"} ${storageStatus.environmentFolder}` : storageStatus.bucket, "not configured"); + this.setStorageStatus("bucket", storageStatus.bucketStatus || storageStatus.status, reason); ++ this.setStorageValue("lastChecked", storageStatus.lastChecked, "not available"); ++ this.setStorageStatus("lastChecked", storageStatus.lastChecked ? "PASS" : "WARN", reason); + } + + renderStartupPending(reason) { +@@ -198,9 +203,12 @@ class AdminSystemHealthController { + + storageResultTarget(result = {}) { + if (typeof result.keysListed === "number" && result.actionId === "storage-list") { +- return `${result.keysListed} object(s) under ${asText(result.projectsPrefix, "configured prefix")}`; ++ return `${result.keysListed} object(s) under ${asText(result.environmentFolder, "current environment folder")}`; + } +- return result.testObjectKey || result.projectsPrefix || result.message || "diagnostic target unavailable"; ++ if (result.actionId === "storage-bucket-connectivity") { ++ return result.environmentFolder || result.message || "bucket connectivity target unavailable"; ++ } ++ return result.testObjectKey || result.environmentFolder || result.message || "diagnostic target unavailable"; + } + + renderStorageResult(key, result = {}) { +@@ -210,6 +218,49 @@ class AdminSystemHealthController { + } + this.setStorageValue(key, this.storageResultTarget(result)); + this.setStorageStatus(key, result.status, result.message || "R2 diagnostic returned without a message."); ++ if (result.lastChecked) { ++ this.setStorageValue("lastChecked", result.lastChecked); ++ this.setStorageStatus("lastChecked", "PASS", "Most recent current-environment R2 health check timestamp."); ++ } ++ } + - function createProject(root, ideaId) { - const record = ideaRecord(ideaId); - if (!record) { -@@ -598,16 +615,7 @@ function createProject(root, ideaId) { - updateStatus(root, "Set this idea to Ready before creating a project."); - return; - } -- const sessionState = currentSessionState(); -- if (!sessionState.apiAvailable) { -- updateStatus(root, "Sign-in status could not be verified. Try again shortly."); -- return; -- } -- if (!sessionState.authenticated) { -- updateStatus(root, "Sign in to create a Game Hub project."); -- window.location.href = signInUrl(); -- return; -- } -+ if (!requireAuthenticatedWrite(root)) return; - const repository = gameHubProjectRepository(); - const project = repository.createGame({ - name: record.idea, -@@ -638,6 +646,7 @@ function archiveIdea(root, ideaId) { - updateStatus(root, "Idea Board could not archive that idea."); - return; - } -+ if (!requireAuthenticatedWrite(root)) return; - if (record.status !== "Archived") record.previousStatus = record.status; - record.status = "Archived"; - record.updated = today(); -@@ -657,6 +666,7 @@ function restoreIdea(root, ideaId) { - updateStatus(root, "Idea Board could not restore that idea."); - return; - } -+ if (!requireAuthenticatedWrite(root)) return; - record.status = previousStatusForRestore(record); - record.previousStatus = record.status; - record.updated = today(); -@@ -742,6 +752,7 @@ function handleNoteAction(root, actionControl) { - updateStatus(root, "Editing note."); - render(root); - } else if (action === "delete") { -+ if (!requireAuthenticatedWrite(root)) return; - const index = noteTable.findIndex((note) => note.noteId === noteId && note.ideaId === ideaId && !note.system); - if (index >= 0) { - noteTable.splice(index, 1); -diff --git a/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_branch-validation.md b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_branch-validation.md ++ renderHistoryPending(reason) { ++ if (!this.historyRows) { ++ return; ++ } ++ const row = document.createElement("tr"); ++ row.append( ++ this.createCell("not available"), ++ this.createCell("current environment"), ++ this.createCell("Health Check History"), ++ this.createStatusCell("PENDING", reason), ++ this.createCell("Safe health check history is not available."), ++ ); ++ this.historyRows.replaceChildren(row); ++ } ++ ++ renderHealthCheckHistory(historyRows = []) { ++ if (!this.historyRows) { ++ return; ++ } ++ const rows = Array.isArray(historyRows) ? historyRows : []; ++ if (!rows.length) { ++ this.renderHistoryPending("Safe Admin System Health API returned no current-environment health check history rows."); ++ return; ++ } ++ const fragment = document.createDocumentFragment(); ++ rows.forEach((historyRow) => { ++ const row = document.createElement("tr"); ++ row.append( ++ this.createCell(historyRow.checkedAt), ++ this.createCell(historyRow.environmentName), ++ this.createCell(historyRow.area), ++ this.createStatusCell(historyRow.result || historyRow.status, historyRow.summary), ++ this.createCell(historyRow.summary), ++ ); ++ fragment.append(row); ++ }); ++ this.historyRows.replaceChildren(fragment); + } + + runStorageDiagnostics() { +@@ -292,6 +343,7 @@ class AdminSystemHealthController { + this.renderStartupDiagnostics(data?.localApiStartup || {}); + this.renderStorageStatus(data?.storageStatus || {}); + this.runStorageDiagnostics(); ++ this.renderHealthCheckHistory(data?.healthCheckHistory || []); + this.renderRuntimeEnvironment(data?.runtimeEnvironment || {}); + } catch (error) { + const message = error instanceof Error ? error.message : "Safe Admin System Health API is unavailable."; +diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_009-system-health-current-r2-health.md b/docs_build/dev/reports/PR_26175_CHARLIE_009-system-health-current-r2-health.md new file mode 100644 -index 000000000..3e0239894 +index 000000000..a0cd45bc9 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_branch-validation.md -@@ -0,0 +1,22 @@ -+# PR_26175_BRAVO_011 Branch Validation ++++ b/docs_build/dev/reports/PR_26175_CHARLIE_009-system-health-current-r2-health.md +@@ -0,0 +1,41 @@ ++# PR_26175_CHARLIE_009 System Health Current R2 Health ++ ++## Scope ++ ++Team: Charlie ++ ++Purpose: Add current-environment Cloudflare R2 folder health only to Admin System Health. ++ ++## Changes + -+Date: 2026-06-24 ++- Replaced the System Health Storage Health rows with current-environment R2 checks: ++ - bucket connectivity ++ - list ++ - upload ++ - read ++ - delete ++ - last checked ++- System Health storage diagnostics run against the current environment folder only: ++ - Local: `/local` ++ - DEV: `/dev` ++ - IST: `/ist` ++ - UAT: `/uat` ++ - PRD: `/prd` ++- Preserved the separate Admin Infrastructure storage diagnostic path that uses the configured project prefix. ++- Updated focused API and Playwright tests. + -+## Branch Gate ++## Architecture Constraint + -+- PASS: Current branch was verified as `main` before planning and implementation. -+- PASS: Worktree was verified clean before the PR branch was created. -+- PASS: `origin/main` was pulled/rebased before the PR branch was created. -+- PASS: `HEAD`, `main`, and `origin/main` were synced at `dd7a3732e4225e42fe1033d37090abe179e6d5a5`. -+- PASS: Work moved to scoped branch `pr/26175-BRAVO-011-idea-board-guest-save-auth-redirect`. ++PASS. R2 health checks target only the current deployment environment folder. No peer environment R2 folders are actively checked by System Health. + -+## Current State Before Commit ++## Validation + -+- Branch: `pr/26175-BRAVO-011-idea-board-guest-save-auth-redirect` -+- Base commit: `dd7a3732e4225e42fe1033d37090abe179e6d5a5` -+- Origin/main sync before edits: `0/0` -+- Worktree: dirty with intended PR files and required reports. ++- PASS: `node --check src/dev-runtime/server/local-api-router.mjs` ++- PASS: `node --check assets/theme-v2/js/admin-system-health.js` ++- PASS: `git diff --check` ++- PASS: `node --test tests/dev-runtime/AdminHealthOperations.test.mjs` ++- PASS: `npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line` + -+## Result ++## Artifact + -+PASS: Branch and clean-worktree gates passed before implementation. Current dirty state is expected PR output before commit. -diff --git a/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_instruction-compliance.md b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_instruction-compliance.md ++- `tmp/PR_26175_CHARLIE_009-system-health-current-r2-health_delta.zip` +diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_010-system-health-history-and-closeout.md b/docs_build/dev/reports/PR_26175_CHARLIE_010-system-health-history-and-closeout.md new file mode 100644 -index 000000000..11c593d22 +index 000000000..c8f5ff396 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_instruction-compliance.md -@@ -0,0 +1,31 @@ -+# PR_26175_BRAVO_011 Instruction Compliance ++++ b/docs_build/dev/reports/PR_26175_CHARLIE_010-system-health-history-and-closeout.md +@@ -0,0 +1,68 @@ ++# PR_26175_CHARLIE_010 System Health History and Closeout + -+Date: 2026-06-24 ++## Scope + -+## Governance ++Team: Charlie ++ ++Purpose: Add current-environment Health Check History and close out the System Health stacked expansion chain. ++ ++## Chain ++ ++- `PR_26175_CHARLIE_006-project-instructions-system-health-infrastructure` ++ - Branch: `PR_26175_CHARLIE_006-project-instructions-system-health-infrastructure` ++ - Commit: `c870b812faded383094fb13fc60ae9cfc7f14889` ++ - Result: pushed to origin, not merged. ++- `PR_26175_CHARLIE_007-system-health-environment-identity` ++ - Branch: `pr/26175-CHARLIE-007-system-health-environment-identity` ++ - Commit: `6556e73efcd8ae13b51b56288416c88688e67634` ++ - Draft PR: https://github.com/ToolboxAid/HTML-JavaScript-Gaming/pull/151 ++- `PR_26175_CHARLIE_008-system-health-current-database-health` ++ - Branch: `pr/26175-CHARLIE-008-system-health-current-database-health` ++ - Commit: `2603aeb6e5a7ccca516051953cbd70a5a6c94c4b` ++ - Draft PR: https://github.com/ToolboxAid/HTML-JavaScript-Gaming/pull/152 ++- `PR_26175_CHARLIE_009-system-health-current-r2-health` ++ - Branch: `pr/26175-CHARLIE-009-system-health-current-r2-health` ++ - Commit: `9740705fbe73dffd43744ab66338f8e4a925eed4` ++ - Draft PR: https://github.com/ToolboxAid/HTML-JavaScript-Gaming/pull/153 ++- `PR_26175_CHARLIE_010-system-health-history-and-closeout` ++ - Branch: `pr/26175-CHARLIE-010-system-health-history-and-closeout` ++ - Commit and draft PR URL are assigned after this report is committed and pushed. ++ ++## Changes + -+- PASS: Read ProjectInstructions before implementation. -+- PASS: Initial branch was `main`; implementation did not begin until after the main-branch gate passed. -+- PASS: Initial worktree was clean before implementation. -+- PASS: Scope remained limited to Idea Board auth gating, impacted tests, and required reports. -+- PASS: No engine core files modified. -+- PASS: No `start_of_day` files modified. -+- PASS: No `imageDataUrl` contract usage introduced. -+- PASS: No runtime code outside the Idea Board save/auth path was changed. ++- Added Health Check History to the Admin System Health page. ++- Health Check History is derived from the current deployment only: ++ - Environment Summary ++ - Database Health ++ - Storage Health ++ - Runtime Health ++- Warning and failure rows are generated only from current-environment health rows. ++- Creator sessions remain blocked from Admin System Health and do not trigger status or storage health requests. + -+## Frontend / Runtime Rules ++## Governance + -+- PASS: No inline runtime script/style/event handlers added. -+- PASS: No browser-owned product-data SSoT added. -+- PASS: No localStorage/sessionStorage product-data persistence added. -+- PASS: Existing API/session terminology and helpers were used. ++- PASS: System Health is one page per deployed environment. ++- PASS: Each deployment actively checks only itself. ++- PASS: The Environment Map remains a static reference for Local, DEV, IST, UAT, and PRD. ++- PASS: System Health does not actively check peer databases or peer R2 folders. ++- PASS: Cancelled initiatives remain not doing: ++ - Environment Isolation & Developer Experience ++ - multi-port workspace framework ++ - Alpha/Beta/User runtime separation ++ - runtime port management initiative + -+## Reporting / Packaging ++## Validation + -+- PASS: Required PR reports created. -+- PASS: V8 coverage reports refreshed after Playwright route coverage. -+- PASS: `codex_review.diff`, `codex_changed_files.txt`, and repo-structured ZIP are generated for this run. ++- PASS: `node --check src/dev-runtime/server/local-api-router.mjs` ++- PASS: `node --check assets/theme-v2/js/admin-system-health.js` ++- PASS: `git diff --check` ++- PASS: `node --test tests/dev-runtime/AdminHealthOperations.test.mjs` ++- PASS: `node --test tests/dev-runtime/PublicEnvironmentConfig.test.mjs` ++- PASS: `npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line` + -+## ZIP ++## Artifacts + -+- `tmp/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_delta.zip` -diff --git a/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_manual-validation-notes.md b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_manual-validation-notes.md ++- `tmp/PR_26175_CHARLIE_007-system-health-environment-identity_delta.zip` ++- `tmp/PR_26175_CHARLIE_008-system-health-current-database-health_delta.zip` ++- `tmp/PR_26175_CHARLIE_009-system-health-current-r2-health_delta.zip` ++- `tmp/PR_26175_CHARLIE_010-system-health-history-and-closeout_delta.zip` +diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-branch-validation.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-branch-validation.md new file mode 100644 -index 000000000..03f98b044 +index 000000000..e2d3a2b30 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_manual-validation-notes.md -@@ -0,0 +1,37 @@ -+# PR_26175_BRAVO_011 Manual Validation Notes -+ -+Date: 2026-06-24 -+ -+## Reviewed Runtime Paths -+ -+- `toolbox/idea-board/index.html` -+- `assets/toolbox/idea-board/js/index.js` -+- `src/api/session-api-client.js` -+- `src/api/server-api-client.js` -+- Sign-in route usage: `account/sign-in.html` -+ -+## Persist Actions Verified -+ -+- Add idea save: guest redirects before save. -+- Edit idea save: guest redirects before update. -+- Delete idea: guest redirects before delete. -+- Add note save: guest redirects before save. -+- Edit note save: guest redirects before update. -+- Delete note: guest redirects before delete. -+- Create project: guest redirects before `createGame`. -+- Archive project idea: guest redirects before archive mutation. -+- Restore archived project idea: guest redirects before restore mutation. -+ -+## Browse Actions Verified -+ -+- Guest can load the Idea Board. -+- Guest can expand existing idea notes. -+- Guest remains on `toolbox/idea-board/index.html` while browsing. -+ -+## Data Safety Notes -+ -+- No production data was modified. -+- No migration or database write was executed outside Playwright local test servers. -+- No browser product-data SSoT was added. -+- No `localStorage` or `sessionStorage` product-data persistence was added. -+- No fake login or silent fallback was added. -diff --git a/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_report.md b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_report.md ++++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-branch-validation.md +@@ -0,0 +1,15 @@ ++# PR_26175_CHARLIE_011 Branch Validation ++ ++## Start Gate ++ ++- PASS: Current branch was `pr/26175-CHARLIE-010-system-health-history-and-closeout`. ++- PASS: Worktree was clean before implementation. ++- PASS: Build remained on the current Charlie continuation branch. ++- PASS: No rebase was performed. ++- PASS: No new root branch was created. ++ ++## Final Branch Target ++ ++- Branch to push: `pr/26175-CHARLIE-010-system-health-history-and-closeout` ++- Expected draft PR to update: https://github.com/ToolboxAid/HTML-JavaScript-Gaming/pull/155 ++- Merge status: no merge requested or performed. +diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-manual-validation-notes.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-manual-validation-notes.md new file mode 100644 -index 000000000..498138c5c +index 000000000..e8b6eae26 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_report.md -@@ -0,0 +1,51 @@ -+# PR_26175_BRAVO_011 Idea Board Guest Save Auth Redirect ++++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-manual-validation-notes.md +@@ -0,0 +1,26 @@ ++# PR_26175_CHARLIE_011 Manual Validation Notes + -+Date: 2026-06-24 ++## Admin Submenu Order + -+## Scope ++Visible labels after the change: + -+Require an authenticated API session before Idea Board save or persist actions. Guests may still browse the Idea Board, expand rows, and inspect notes. Guests are redirected to `account/sign-in.html` before any save/persist mutation. ++`Admin Tools`, `Analytics`, `Controls`, `Creators`, `DB Viewer`, `Environments`, `Game Migration`, `Infrastructure`, `Invites`, `Moderation`, `Operations`, `Platform Settings`, `Ratings`, `Responsibilities`, `Site Setup`, `System Health`, `Tool Votes` + -+## Review Findings ++## Route Preservation + -+- PASS: ProjectInstructions and governance documents were reviewed before implementation. -+- PASS: Initial branch was `main`, worktree was clean, and `main`/`origin/main` were synced at `dd7a3732e4225e42fe1033d37090abe179e6d5a5` before the PR branch was created. -+- PASS: `toolbox/idea-board/index.html` delegates runtime behavior to `assets/toolbox/idea-board/js/index.js`. -+- PASS: Existing auth/session helper is `getSessionCurrent()` from `src/api/session-api-client.js`, backed by the API session contract. -+- PASS: Existing sign-in route pattern uses `account/sign-in.html`. -+- PASS: Persisting Idea Board actions identified: idea save, idea delete, note save, note delete, create project, archive, and restore. -+- PASS: Browse-only actions identified: loading the board, expanding/collapsing notes, filtering, starting/canceling edit rows, and opening existing project links. ++The only source navigation reorder moved this existing item: + -+## Implementation Summary ++- `Creators` ++ - path remained `admin/users.html` ++ - route remained `admin-users` ++ - label remained `Creators` + -+- Added one shared Idea Board write guard, `requireAuthenticatedWrite(root)`, using the existing API session helper. -+- Applied the guard before every Idea Board mutation/write path: idea save, note save, idea delete, note delete, create project, archive, and restore. -+- Preserved guest browsing by leaving load, filter, expand/collapse, and non-persist UI actions unauthenticated. -+- Expanded Playwright coverage so guest add/edit/delete idea, add/edit/delete note, create project, archive, and restore actions redirect to sign-in before writes. -+- Kept the implementation on the existing API contract; no browser product-data SSoT, fake login, localStorage/sessionStorage product data, or environment-specific branch was introduced. ++All other Admin navigation objects remained unchanged. + -+## Affected Files ++## Open-Page Check + -+- `assets/toolbox/idea-board/js/index.js` -+- `tests/playwright/tools/IdeaBoardTableNotes.spec.mjs` -+- `tests/playwright/tools/ToolboxRoutePages.spec.mjs` -+- `docs_build/dev/reports/playwright_v8_coverage_report.txt` -+- `docs_build/dev/reports/coverage_changed_js_guardrail.txt` ++The targeted Playwright navigation test collected every active Admin submenu href from the rendered submenu and requested each page through the local test server. Every response returned a status below HTTP 400. + -+## Validation Summary ++## Duplicate Check ++ ++The targeted Playwright navigation test checks for duplicate rendered labels and duplicate active hrefs. The targeted unit script also checks duplicate labels and existing active paths. +diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-requirement-checklist.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-requirement-checklist.md +new file mode 100644 +index 000000000..39afb7966 +--- /dev/null ++++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-requirement-checklist.md +@@ -0,0 +1,42 @@ ++# PR_26175_CHARLIE_011 Requirement Checklist ++ ++## Branch Rules ++ ++- PASS: Continued on `pr/26175-CHARLIE-010-system-health-history-and-closeout`. ++- PASS: Did not return to `main`. ++- PASS: Did not rebase. ++- PASS: Did not create a new root branch. ++- PASS: Hard stop conditions were checked before implementation. + -+- PASS: Targeted node guardrail passed. -+- PASS: Runtime grep found no `localStorage` or `sessionStorage` use in Idea Board runtime HTML/JS. -+- PASS: Runtime grep found no inline script/style/event-handler additions in Idea Board runtime HTML/JS. -+- PASS: Focused Playwright guest redirect test passed. -+- PASS: Focused Playwright Toolbox-to-Idea-Board launch test passed after filtering unrelated selected-game status polling from the no-write assertion. -+- PASS: Playwright V8 coverage report includes `assets/toolbox/idea-board/js/index.js`. -+- WARN: Bundled Playwright Chromium was missing and `npx playwright install chromium` stalled with a partial install; focused browser validation used installed Google Chrome through a temporary config that was removed after validation. -+- WARN: Full legacy Playwright files still have unrelated expectation drift documented in the validation lane report. ++## Objective + -+## Recommended Next PR ++- PASS: Admin submenu entries are alphabetized by displayed text. + -+Create a follow-up validation cleanup PR for existing Toolbox/Game Hub drift: ++## Scope ++ ++- PASS: Located Admin submenu definition in `src/api/admin-owner-navigation.js`. ++- PASS: Sorted submenu entries by displayed text. ++- PASS: Preserved routes, URLs, IDs, CSS classes, Theme V2 styling, and existing renderer behavior. ++- PASS: Did not rename pages. ++- PASS: Did not rename folders. ++- PASS: Did not modify page content. ++- PASS: No unrelated cleanup. ++ ++## Validation + -+- Refresh `ToolboxRoutePages` expected tool counts, Game Hub route alias expectations, failed module-load assertions, and local dev port guard expectation. -+- Refresh or repair the Game Hub expanded child-row summary expectation in `IdeaBoardTableNotes`. -diff --git a/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_requirements-checklist.md b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_requirements-checklist.md ++- PASS: Verified submenu labels are alphabetical. ++- PASS: Verified every Admin page path exists and every Admin submenu href opens below HTTP 400 in targeted Playwright. ++- PASS: Verified no duplicate labels or hrefs. ++- PASS: Ran affected Playwright navigation tests. ++- PASS: Ran affected targeted unit tests. ++ ++## Artifacts ++ ++- PASS: `docs_build/dev/reports/codex_review.diff` ++- PASS: `docs_build/dev/reports/codex_changed_files.txt` ++- PASS: `docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md` ++- PASS: validation report ++- PASS: branch validation report ++- PASS: requirement checklist ++- PASS: manual validation notes ++- PASS: repository ZIP under `tmp/` +diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-validation.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-validation.md new file mode 100644 -index 000000000..4100a8b51 +index 000000000..aeec3f443 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_requirements-checklist.md -@@ -0,0 +1,19 @@ -+# PR_26175_BRAVO_011 Requirements Checklist -+ -+Date: 2026-06-24 -+ -+| Requirement | Result | Evidence | -+| --- | --- | --- | -+| Guests may browse the Idea Board. | PASS | Playwright expands `top-thoughts` as a guest and remains on `toolbox/idea-board/index.html`. | -+| Guests may not save creator-owned data. | PASS | Guest save/persist controls redirect before mutation. | -+| Every save/persist action redirects unauthenticated users to `account/sign-in.html`. | PASS | Covered add/edit/delete idea, add/edit/delete note, create project, archive, and restore. | -+| Redirect before any API write. | PASS | Guest create/archive/restore assertions reset and inspect create-game requests; no write request is sent before redirect. | -+| All environments use the same API contract. | PASS | Uses existing `getSessionCurrent()` API session helper; no environment-specific branch added. | -+| Do not introduce browser-owned product data. | PASS | No new browser persistence or product-data SSoT added. | -+| Do not use localStorage/sessionStorage as product-data SSoT. | PASS | Runtime grep found no `localStorage` or `sessionStorage` in Idea Board runtime HTML/JS. | -+| Do not introduce fake login behavior. | PASS | Runtime uses existing API session helper only; tests use repo test session endpoint. | -+| No silent fallbacks. | PASS | API session verification failure blocks the write and reports status. | -+| Use API terminology only. | PASS | New unavailable status uses API session terminology. | -+| Keep PR limited to scope. | PASS | Runtime change is limited to Idea Board write gating; tests and reports cover the same scope. | -+| Create required reports. | PASS | PR report, branch validation, requirement checklist, validation lane, manual notes, instruction compliance, review diff, changed files, and V8 coverage reports are included. | -+| Create repo-structured ZIP under `tmp/`. | PASS | `tmp/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_delta.zip`. | -diff --git a/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_validation-lane.md b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_validation-lane.md ++++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order-validation.md +@@ -0,0 +1,22 @@ ++# PR_26175_CHARLIE_011 Validation Report ++ ++## Commands ++ ++- PASS: `node --check src/api/admin-owner-navigation.js` ++- PASS: `node --input-type=module` alphabetical/duplicate/path verification script ++ - Result: `PASS labels=17 active=16` ++ - Order: `Admin Tools | Analytics | Controls | Creators | DB Viewer | Environments | Game Migration | Infrastructure | Invites | Moderation | Operations | Platform Settings | Ratings | Responsibilities | Site Setup | System Health | Tool Votes` ++- PASS: `git diff --check` ++ - Result: no whitespace errors; CRLF conversion warnings only. ++- PASS: `node --test tests/dev-runtime/ApiMenuPathCleanup.test.mjs` ++ - Result: 6 passed. ++- PASS: `node --test --test-name-pattern "Admin and Owner navigation are shared" tests/dev-runtime/ArchitectureCleanupApiNavInvitations.test.mjs` ++ - Result: 1 passed. ++- PASS: `npx playwright test tests/playwright/tools/AdminOwnerNavigationBoundary.spec.mjs --workers=1 --reporter=line` ++ - Result: 4 passed. ++- PASS: `npx playwright test tests/playwright/tools/AdminInvitationsNavPage.spec.mjs --workers=1 --reporter=line` ++ - Result: 3 passed. ++ ++## Note ++ ++A non-targeted full-file run of `tests/dev-runtime/ArchitectureCleanupApiNavInvitations.test.mjs` was not used for final validation because its first non-navigation test fails on a pre-existing missing `src/engine/api` directory assertion. The affected navigation subtest passed by name. +diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md new file mode 100644 -index 000000000..c7ffdfcc9 +index 000000000..7dcbe5262 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_BRAVO_011-idea-board-guest-save-auth-redirect_validation-lane.md -@@ -0,0 +1,36 @@ -+# PR_26175_BRAVO_011 Validation Lane ++++ b/docs_build/dev/reports/PR_26175_CHARLIE_011-admin-submenu-alphabetical-order.md +@@ -0,0 +1,47 @@ ++# PR_26175_CHARLIE_011 Admin Submenu Alphabetical Order ++ ++## Scope + -+Date: 2026-06-24 ++Team: Charlie + -+## Commands ++Purpose: Alphabetize the Admin submenu by visible menu labels only. ++ ++## Branch + -+| Command | Result | Notes | -+| --- | --- | --- | -+| `git diff --check` | PASS | CRLF warnings only for touched Playwright specs. | -+| `rg -n "localStorage|sessionStorage" assets/toolbox/idea-board/js/index.js toolbox/idea-board/index.html` | PASS | No runtime matches. | -+| `rg -n "