diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md new file mode 100644 index 000000000..833eb75aa --- /dev/null +++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md @@ -0,0 +1,22 @@ +# PR_26175_ALFA_051-alfa-end-of-day-closeout Branch Validation + +## Branch +`codex/pr-26175-alfa-051-alfa-end-of-day-closeout` + +## Base +- Base branch: `origin/main` +- Base commit at branch creation: `6a7a001b9` + +## Checks +- Branch created after ALFA_050 merge: PASS. +- Local `main` verified clean before branch creation: PASS. +- Branch delta limited to the ALFA_051 plan and required reports: PASS. +- No runtime files changed: PASS. +- No UI files changed: PASS. +- No test files changed: PASS. +- No roadmap files changed: PASS. +- No backlog files changed: PASS. +- No Project Instructions source files changed: PASS. + +## Result +PASS diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md new file mode 100644 index 000000000..77dd81396 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md @@ -0,0 +1,13 @@ +# PR_26175_ALFA_051-alfa-end-of-day-closeout Manual Validation Notes + +Manual validation was limited to documentation/governance review because this PR is report-only. + +## Notes +- Confirmed ALFA_050 merged to `main` before this closeout branch was created. +- Confirmed local `main` was synchronized with `origin/main` at `6a7a001b9` before branch work. +- Reviewed current Team Alfa assignment files; Team Alfa is listed as available with no active assignment or branch. +- Reviewed current backlog status without editing backlog source files. +- Audited GitHub for open Team Alfa PRs using connector searches for `ALFA` and `PR_26175_ALFA`; no open matching PRs were found. + +## Result +PASS diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md new file mode 100644 index 000000000..374efeda0 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md @@ -0,0 +1,47 @@ +# PR_26175_ALFA_051-alfa-end-of-day-closeout Report + +## Summary +- Scope: report-only Team Alfa end-of-day closeout for the current `PR_26175` Alfa stream. +- ALFA_050 status: merged to `main` as GitHub PR #169. +- ALFA_050 merge commit: `6a7a001b9d92a078fdfcfec50e26d533cf855d0d`. +- Main verification before this branch: PASS. Local `main` fast-forwarded to `origin/main` at `6a7a001b9` with a clean tracked worktree. +- Runtime/UI scope: no runtime code changes, no UI changes, no tests changed, no engine core changes, and no `start_of_day` changes. + +## Current Alfa Mainline Work +The current `main` branch includes the 26175 Alfa report trail for: + +- `PR_26175_ALFA_009-status-bar-single-row-rebuild` +- `PR_26175_ALFA_011-status-bar-journey-progress-context` +- `PR_26175_ALFA_015-alfa-foundation-consolidation` +- `PR_26175_ALFA_016-alfa-parent-child-table-consolidation` +- `PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation` +- `PR_26175_ALFA_018-alfa-idea-board-polish-consolidation` +- `PR_26175_ALFA_047-theme-v2-svg-icon-registry` +- `PR_26175_ALFA_048-theme-v2-chevron-conversion` +- `PR_26175_ALFA_049-theme-v2-status-action-icons` +- `PR_26175_ALFA_050-theme-v2-layout-utility-icons` +- `PR_26175_ALFA_051-idea-board-game-hub-row-expectation` + +## Duplicate Numbering Note +`PR_26175_ALFA_051-idea-board-game-hub-row-expectation` already exists on current `main` as a separate test-expectation closeout. This closeout uses the exact requested slug `PR_26175_ALFA_051-alfa-end-of-day-closeout` to preserve traceability without rewriting the prior report history. + +## Open Team Alfa PR Audit +- GitHub connector search for open PRs matching `ALFA`: no open PRs found. +- GitHub connector search for open PRs matching `PR_26175_ALFA`: no open PRs found. +- Project Instructions active-team files list Team Alfa as `Available` with no active assignment, branch, or PR. + +## Backlog Status Note +Current backlog source files still contain open Team Alfa backlog items. This closeout does not complete, reprioritize, remove, or edit backlog items. + +## Changed Files +- `docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md` +- `docs_build/dev/reports/codex_review.diff` +- `docs_build/dev/reports/codex_changed_files.txt` + +## Branch Validation +PASS diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md new file mode 100644 index 000000000..468917296 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md @@ -0,0 +1,20 @@ +# PR_26175_ALFA_051-alfa-end-of-day-closeout Requirements Checklist + +- [x] Confirm ALFA_050 was merged into `main`. +- [x] Confirm local `main` was verified clean before creating this branch. +- [x] Produce Team Alfa end-of-day closeout report. +- [x] Summarize current 26175 Alfa work present on `main`. +- [x] Document duplicate `PR_26175_ALFA_051` numbering note. +- [x] Audit open Team Alfa GitHub PRs. +- [x] Confirm no runtime code changes. +- [x] Confirm no UI changes. +- [x] Confirm no test expectation changes. +- [x] Confirm no backlog edits. +- [x] Confirm no roadmap edits. +- [x] Confirm no Project Instructions source edits. +- [x] Produce `codex_review.diff`. +- [x] Produce `codex_changed_files.txt`. +- [x] Produce repo-structured ZIP under `tmp/`. + +## Result +PASS diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md new file mode 100644 index 000000000..7c7b14514 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md @@ -0,0 +1,17 @@ +# PR_26175_ALFA_051-alfa-end-of-day-closeout Validation Lane + +## Lane +Documentation/governance report lane. + +## Commands +- `git status --short --branch` +- `git rev-list --left-right --count origin/main...HEAD` +- `git diff --name-only` +- `git diff --check` + +## GitHub Metadata Audit +- Open PR search `ALFA`: PASS, no open PRs found. +- Open PR search `PR_26175_ALFA`: PASS, no open PRs found. + +## Result +PASS diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt index 07b3989e2..a0557cef9 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt @@ -1,14 +1,8 @@ -assets/theme-v2/css/buttons.css -assets/theme-v2/css/icons.css -assets/theme-v2/css/panels.css -assets/theme-v2/js/gamefoundry-partials.js -assets/theme-v2/js/tool-display-mode.js -docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md -docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md -docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md -docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md docs_build/dev/reports/codex_changed_files.txt docs_build/dev/reports/codex_review.diff -tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs -tests/playwright/tools/ToolboxRoutePages.spec.mjs -tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs +docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md +docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md +docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md +docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md +docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md +docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md diff --git a/docs_build/dev/reports/codex_review.diff b/docs_build/dev/reports/codex_review.diff index 06dfabcc5..c63e817ae 100644 --- a/docs_build/dev/reports/codex_review.diff +++ b/docs_build/dev/reports/codex_review.diff @@ -1,1068 +1,246 @@ -diff --git a/assets/theme-v2/css/buttons.css b/assets/theme-v2/css/buttons.css -index f45910884..0f1d72c77 100644 ---- a/assets/theme-v2/css/buttons.css -+++ b/assets/theme-v2/css/buttons.css -@@ -112,10 +112,16 @@ - transition: opacity var(--transition-duration-fast) ease, transform var(--transition-duration-fast) ease, color var(--transition-duration-fast) ease, border-color var(--transition-duration-fast) ease, background var(--transition-duration-fast) ease - } - --.return-to-top span { -+.return-to-top span, -+.return-to-top__icon { - transform: translateY(var(--return-to-top-glyph-shift)) - } - -+.return-to-top__icon { -+ height: var(--icon-size-sm); -+ width: var(--icon-size-sm) -+} -+ - .return-to-top.is-visible { - opacity: 1; - pointer-events: auto; -diff --git a/assets/theme-v2/css/icons.css b/assets/theme-v2/css/icons.css -index 0233a8b46..aa0d8f0e1 100644 ---- a/assets/theme-v2/css/icons.css -+++ b/assets/theme-v2/css/icons.css -@@ -107,6 +107,11 @@ - --theme-v2-icon-url: url("/assets/theme-v2/svg/gfs-warning.svg") - } - -+.layout-icon { -+ height: var(--icon-size-sm); -+ width: var(--icon-size-sm) -+} -+ - .status-icon { - height: var(--icon-size-sm); - width: var(--icon-size-sm) -diff --git a/assets/theme-v2/css/panels.css b/assets/theme-v2/css/panels.css -index b80582336..74f68f0c0 100644 ---- a/assets/theme-v2/css/panels.css -+++ b/assets/theme-v2/css/panels.css -@@ -298,6 +298,10 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p { - display: none - } - -+.tool-display-mode__mode-icon { -+ color: var(--cyan) -+} -+ - .tool-display-mode__chevron { - position: absolute; - right: var(--space-12); -@@ -340,6 +344,27 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p { - flex-wrap: wrap - } - -+.tool-display-mode__navigation-link { -+ align-items: center; -+ color: var(--text); -+ display: inline-flex; -+ gap: var(--space-6); -+ line-height: var(--line-height-tight) -+} -+ -+.tool-display-mode__navigation-link:hover, -+.tool-display-mode__navigation-link:focus-visible { -+ color: var(--gold) -+} -+ -+.tool-display-mode__navigation-link--disabled { -+ color: var(--muted) -+} -+ -+.tool-display-mode__navigation-icon { -+ color: currentColor -+} -+ - .tool-display-mode__character { - grid-column: 1; - grid-row: 1 / span 2; -diff --git a/assets/theme-v2/js/gamefoundry-partials.js b/assets/theme-v2/js/gamefoundry-partials.js -index f7f220880..6945db507 100644 ---- a/assets/theme-v2/js/gamefoundry-partials.js -+++ b/assets/theme-v2/js/gamefoundry-partials.js -@@ -127,6 +127,7 @@ - - const currentScript = document.currentScript || document.querySelector("script[src*='gamefoundry-partials.js']"); - const assetRoot = currentScript ? new URL("../", currentScript.src) : null; -+ let themeIconRegistry = window.ThemeV2Icons || null; - let navigationAdminMenuCache = null; - let publicConfigCache = null; - let publicConfigDataCache = null; -@@ -325,6 +326,54 @@ - return new URL(path.replace(/^assets\//, ""), assetRoot).href; - } - -+ function fallbackThemeIconFileName(name) { -+ return "gfs-" + name + ".svg"; -+ } -+ -+ function createThemeIconNode(name, className) { -+ if (themeIconRegistry && typeof themeIconRegistry.createThemeIcon === "function") { -+ return themeIconRegistry.createThemeIcon(name, { className }); -+ } -+ -+ const icon = document.createElement("span"); -+ icon.className = ["theme-icon", "theme-icon--" + name, className].filter(Boolean).join(" "); -+ icon.dataset.themeIcon = name; -+ icon.dataset.themeIconFile = fallbackThemeIconFileName(name); -+ icon.setAttribute("aria-hidden", "true"); -+ return icon; -+ } -+ -+ function horizontalToggleIconName(button) { -+ const expanded = button.getAttribute("aria-expanded") !== "false"; -+ const isLeft = button.classList.contains("horizontal-accordion-toggle--left"); -+ if (isLeft) { -+ return expanded ? "chevron-left" : "chevron-right"; -+ } -+ return expanded ? "chevron-right" : "chevron-left"; -+ } -+ -+ function updateHorizontalToggleIcon(button) { -+ button.replaceChildren(createThemeIconNode(horizontalToggleIconName(button), "layout-icon horizontal-accordion-toggle__icon")); -+ } -+ -+ function updateReturnToTopIcon(button) { -+ button.replaceChildren(createThemeIconNode("chevron-up", "layout-icon return-to-top__icon")); -+ } -+ -+ function refreshUtilityIcons(root) { -+ (root || document).querySelectorAll(".horizontal-accordion-toggle").forEach(updateHorizontalToggleIcon); -+ (root || document).querySelectorAll("[data-return-to-top]").forEach(updateReturnToTopIcon); -+ } -+ -+ function loadThemeIcons() { -+ import(assetUrl("js/theme-icons.js")).then(function (module) { -+ themeIconRegistry = module; -+ refreshUtilityIcons(document); -+ }).catch(function () { -+ themeIconRegistry = window.ThemeV2Icons || themeIconRegistry; -+ }); -+ } -+ - function currentPagePath() { - const parts = window.location.pathname.split("/").filter(Boolean); - const rootIndex = parts.findIndex(function (part) { -@@ -934,7 +983,7 @@ - button.dataset.accountSideNavCollapse = ""; - button.setAttribute("aria-label", "Collapse " + label); - button.setAttribute("aria-expanded", "true"); -- button.textContent = "<"; -+ updateHorizontalToggleIcon(button); - header.insertBefore(button, header.firstChild); - - button.addEventListener("click", function () { -@@ -943,15 +992,16 @@ - if (accountPanel) { - accountPanel.classList.toggle("is-left-collapsed", collapsed); - } -- button.textContent = collapsed ? ">" : "<"; - button.setAttribute("aria-expanded", collapsed ? "false" : "true"); - button.setAttribute("aria-label", (collapsed ? "Expand " : "Collapse ") + label); -+ updateHorizontalToggleIcon(button); - }); - } - - function wireReturnToTop(root) { - const button = root.querySelector("[data-return-to-top]"); - if (!button) return; -+ updateReturnToTopIcon(button); - - function updateVisibility() { - button.classList.toggle("is-visible", window.scrollY > 280); -@@ -1075,6 +1125,7 @@ - } - - enforcePageProtection(); -+ loadThemeIcons(); - document.addEventListener("DOMContentLoaded", function () { - enforcePageProtection(); - const slots = Array.from(document.querySelectorAll("[data-partial]")); -diff --git a/assets/theme-v2/js/tool-display-mode.js b/assets/theme-v2/js/tool-display-mode.js -index b3f6f3265..cae5febcf 100644 ---- a/assets/theme-v2/js/tool-display-mode.js -+++ b/assets/theme-v2/js/tool-display-mode.js -@@ -79,6 +79,14 @@ - replaceIconNode(summary, ":scope > .tool-display-mode__chevron", shell); - } - -+ function updateToolDisplayModeModeIcon() { -+ const iconName = document.body.classList.contains("tool-focus-mode") || document.fullscreenElement -+ ? "exit-fullscreen" -+ : "fullscreen"; -+ const icon = createThemeIconNode(iconName, "layout-icon tool-display-mode__mode-icon"); -+ replaceIconNode(summary, ":scope > .tool-display-mode__mode-icon", icon); -+ } -+ - function horizontalToggleIconName(button) { - const expanded = button.getAttribute("aria-expanded") !== "false"; - const isLeft = button.classList.contains("horizontal-accordion-toggle--left"); -@@ -98,6 +106,7 @@ - - function refreshThemeIcons() { - refreshVerticalAccordionChevrons(); -+ updateToolDisplayModeModeIcon(); - updateToolDisplayModeChevron(); - refreshHorizontalToggleIcons(); - } -@@ -137,6 +146,7 @@ - const summary = document.createElement("summary"); - summary.setAttribute("aria-label", "Tool Display Mode"); - summary.title = "Tool Display Mode"; -+ summary.appendChild(createThemeIconNode("fullscreen", "layout-icon tool-display-mode__mode-icon")); - - const badge = document.createElement("img"); - badge.className = "tool-display-mode__badge"; -@@ -175,22 +185,26 @@ - function createNavigationControl(direction, target) { - const controlLabel = direction === "previous" ? "Previous" : "Next"; - const dataAttribute = direction === "previous" ? "toolNavPrevious" : "toolNavNext"; -+ const iconName = direction === "previous" ? "chevron-left" : "chevron-right"; -+ const icon = createThemeIconNode(iconName, "layout-icon tool-display-mode__navigation-icon"); -+ const label = document.createTextNode(controlLabel + ": " + (target?.label || "Unavailable")); - - if (!target || target.disabled) { - const disabledText = document.createElement("span"); -- disabledText.className = "pill"; -+ disabledText.className = "pill tool-display-mode__navigation-link tool-display-mode__navigation-link--disabled"; - disabledText.dataset[dataAttribute] = "disabled"; -- disabledText.textContent = controlLabel + ": " + (target?.label || "Unavailable"); -+ disabledText.append(icon, label); - return disabledText; - } - - const link = document.createElement("a"); -+ link.className = "tool-display-mode__navigation-link"; - link.href = target.href; - link.dataset[dataAttribute] = target.kind; - if (target.group) { - link.dataset.toolNavGroup = target.group; - } -- link.textContent = controlLabel + ": " + target.label; -+ link.append(icon, label); - return link; - } - -@@ -259,6 +273,7 @@ - async function enterToolMode() { - document.body.classList.add("tool-focus-mode"); - displayMode.open = false; -+ updateToolDisplayModeModeIcon(); - - try { - if (!document.fullscreenElement && document.documentElement.requestFullscreen) { -@@ -272,6 +287,7 @@ - async function exitToolMode() { - document.body.classList.remove("tool-focus-mode"); - displayMode.open = true; -+ updateToolDisplayModeModeIcon(); - - try { - if (document.fullscreenElement && document.exitFullscreen) { -@@ -296,6 +312,7 @@ - if (!document.fullscreenElement && document.body.classList.contains("tool-focus-mode")) { - document.body.classList.remove("tool-focus-mode"); - displayMode.open = true; -+ refreshThemeIcons(); - } - }); - -diff --git a/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md b/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md +diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md +new file mode 100644 +index 000000000..833eb75aa +--- /dev/null ++++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md +@@ -0,0 +1,22 @@ ++# PR_26175_ALFA_051-alfa-end-of-day-closeout Branch Validation ++ ++## Branch ++`codex/pr-26175-alfa-051-alfa-end-of-day-closeout` ++ ++## Base ++- Base branch: `origin/main` ++- Base commit at branch creation: `6a7a001b9` ++ ++## Checks ++- Branch created after ALFA_050 merge: PASS. ++- Local `main` verified clean before branch creation: PASS. ++- Branch delta limited to the ALFA_051 plan and required reports: PASS. ++- No runtime files changed: PASS. ++- No UI files changed: PASS. ++- No test files changed: PASS. ++- No roadmap files changed: PASS. ++- No backlog files changed: PASS. ++- No Project Instructions source files changed: PASS. ++ ++## Result ++PASS +diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md new file mode 100644 -index 000000000..0202722e2 +index 000000000..77dd81396 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md -@@ -0,0 +1,11 @@ -+# PR_26175_ALFA_050 Manual Validation Notes ++++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md +@@ -0,0 +1,13 @@ ++# PR_26175_ALFA_051-alfa-end-of-day-closeout Manual Validation Notes + -+## Notes -+- Manual validation was performed through the required targeted Playwright lanes rather than an ad hoc browser session. -+- Route tests pin the API/site URL to the repo test server so the pages do not drift to a local dev endpoint. -+- Toolbox vote route assertions were made deterministic against the configured product-data provider by reading current vote state, asserting state transitions, and restoring touched Colors metadata/order. -+- No visual redesign was performed; changes are limited to replacing utility text/placeholders with shared Theme V2 SVG icon nodes and matching compact CSS. -+- No files under `start_of_day` were read or modified. ++Manual validation was limited to documentation/governance review because this PR is report-only. + -+## Residual Risk -+- Full cross-browser or mobile manual review was not run beyond the existing targeted Playwright coverage. -diff --git a/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md b/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md ++## Notes ++- Confirmed ALFA_050 merged to `main` before this closeout branch was created. ++- Confirmed local `main` was synchronized with `origin/main` at `6a7a001b9` before branch work. ++- Reviewed current Team Alfa assignment files; Team Alfa is listed as available with no active assignment or branch. ++- Reviewed current backlog status without editing backlog source files. ++- Audited GitHub for open Team Alfa PRs using connector searches for `ALFA` and `PR_26175_ALFA`; no open matching PRs were found. ++ ++## Result ++PASS +diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md new file mode 100644 -index 000000000..8523a4717 +index 000000000..374efeda0 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md -@@ -0,0 +1,40 @@ -+# PR_26175_ALFA_050-theme-v2-layout-utility-icons Report ++++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md +@@ -0,0 +1,47 @@ ++# PR_26175_ALFA_051-alfa-end-of-day-closeout Report + +## Summary -+- Branch validation: PASS. -+- Base branch state: `5426785fc` (`Merge PR #168: PR_26175_CHARLIE_028-team-charlie-final-closeout`). -+- Scope: Theme V2 layout utility controls now use shared registry SVG icons for fullscreen mode, previous/next navigation, horizontal column toggles, and return-to-top. -+- Runtime/UI scope: no broad redesign, no engine core changes, no `start_of_day` changes, and no page-local inline styles or style blocks introduced. ++- Scope: report-only Team Alfa end-of-day closeout for the current `PR_26175` Alfa stream. ++- ALFA_050 status: merged to `main` as GitHub PR #169. ++- ALFA_050 merge commit: `6a7a001b9d92a078fdfcfec50e26d533cf855d0d`. ++- Main verification before this branch: PASS. Local `main` fast-forwarded to `origin/main` at `6a7a001b9` with a clean tracked worktree. ++- Runtime/UI scope: no runtime code changes, no UI changes, no tests changed, no engine core changes, and no `start_of_day` changes. ++ ++## Current Alfa Mainline Work ++The current `main` branch includes the 26175 Alfa report trail for: ++ ++- `PR_26175_ALFA_009-status-bar-single-row-rebuild` ++- `PR_26175_ALFA_011-status-bar-journey-progress-context` ++- `PR_26175_ALFA_015-alfa-foundation-consolidation` ++- `PR_26175_ALFA_016-alfa-parent-child-table-consolidation` ++- `PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation` ++- `PR_26175_ALFA_018-alfa-idea-board-polish-consolidation` ++- `PR_26175_ALFA_047-theme-v2-svg-icon-registry` ++- `PR_26175_ALFA_048-theme-v2-chevron-conversion` ++- `PR_26175_ALFA_049-theme-v2-status-action-icons` ++- `PR_26175_ALFA_050-theme-v2-layout-utility-icons` ++- `PR_26175_ALFA_051-idea-board-game-hub-row-expectation` ++ ++## Duplicate Numbering Note ++`PR_26175_ALFA_051-idea-board-game-hub-row-expectation` already exists on current `main` as a separate test-expectation closeout. This closeout uses the exact requested slug `PR_26175_ALFA_051-alfa-end-of-day-closeout` to preserve traceability without rewriting the prior report history. ++ ++## Open Team Alfa PR Audit ++- GitHub connector search for open PRs matching `ALFA`: no open PRs found. ++- GitHub connector search for open PRs matching `PR_26175_ALFA`: no open PRs found. ++- Project Instructions active-team files list Team Alfa as `Available` with no active assignment, branch, or PR. ++ ++## Backlog Status Note ++Current backlog source files still contain open Team Alfa backlog items. This closeout does not complete, reprioritize, remove, or edit backlog items. + +## Changed Files -+- `assets/theme-v2/css/buttons.css` -+- `assets/theme-v2/css/icons.css` -+- `assets/theme-v2/css/panels.css` -+- `assets/theme-v2/js/gamefoundry-partials.js` -+- `assets/theme-v2/js/tool-display-mode.js` -+- `tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs` -+- `tests/playwright/tools/ToolboxRoutePages.spec.mjs` -+- `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs` -+- `docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md` -+- `docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md` -+- `docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md` -+- `docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md` ++- `docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md` +- `docs_build/dev/reports/codex_review.diff` +- `docs_build/dev/reports/codex_changed_files.txt` + -+## Implementation Notes -+- `tool-display-mode.js` renders shared fullscreen/exit-fullscreen icons in the mode summary and shared chevron icons for previous/next controls while preserving existing labels and links. -+- `gamefoundry-partials.js` loads the Theme V2 icon registry for shared partial utilities, replacing account side-nav text glyphs and return-to-top placeholders with registry icons. -+- `icons.css`, `buttons.css`, and `panels.css` add compact shared layout-icon sizing and layout utility presentation without inline styles. -+- Tests assert the new layout utility icons and keep route coverage deterministic against the configured product-data provider. -+ -+## Validation Summary -+- PASS: syntax checks for the touched Theme V2 scripts. -+- PASS: targeted Playwright registry, selected-game status bar, and route suites. -+- PASS: inline style/style-block scan returned no matches. -+- PASS: `git diff --check`. -+ +## Branch Validation -+- PASS: Branch is `codex/pr-26175-alfa-050-theme-v2-layout-utility-icons`. -+- PASS: Changes are limited to ALFA_050 target implementation, tests, and required reports. -+- PASS: Repo-structured ZIP will be emitted under `tmp/` and not staged. -diff --git a/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md b/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md ++PASS +diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md new file mode 100644 -index 000000000..8267b883b +index 000000000..468917296 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md -@@ -0,0 +1,15 @@ -+# PR_26175_ALFA_050 Requirements Checklist -+ -+| Requirement | Status | Evidence | -+| --- | --- | --- | -+| Use shared icons for fullscreen enter/exit controls. | PASS | `tool-display-mode.js` adds fullscreen and exit-fullscreen registry icons; status-bar Playwright asserts both files. | -+| Use shared icons for previous/next navigation. | PASS | Tool display navigation prepends shared chevron-left/chevron-right icons; Playwright asserts both files. | -+| Use shared icons for column collapse/expand controls. | PASS | Horizontal accordion toggles render shared chevron icons through the Theme V2 helper path. | -+| Use shared icons for return-to-top controls. | PASS | Shared partials replace return-to-top content with the registry chevron-up icon; route Playwright asserts it. | -+| Preserve accessible names, roles, and keyboard behavior. | PASS | Existing button/link labels and aria attributes are retained while icons are `aria-hidden`. | -+| Preserve fullscreen bottom status bar anchoring and content reserve. | PASS | Selected-game status bar Playwright suite passed. | -+| Keep utility controls compact and stable. | PASS | Shared `.layout-icon` sizing and navigation-link styles were added without layout refactors. | -+| Avoid page-local utility icon markup when shared helpers can own it. | PASS | Shared partial/helper paths own return-to-top and horizontal toggle icon replacement. | -+| No inline styles, style blocks, or page-local CSS introduced. | PASS | Targeted `rg` scan returned no matches. | -+| No unrelated page/tool redesign. | PASS | Changes are limited to layout utility icon rendering, compact CSS, tests, and reports. | -+| No engine core or `start_of_day` changes. | PASS | No engine or `start_of_day` files changed. | -diff --git a/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md b/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md ++++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md +@@ -0,0 +1,20 @@ ++# PR_26175_ALFA_051-alfa-end-of-day-closeout Requirements Checklist ++ ++- [x] Confirm ALFA_050 was merged into `main`. ++- [x] Confirm local `main` was verified clean before creating this branch. ++- [x] Produce Team Alfa end-of-day closeout report. ++- [x] Summarize current 26175 Alfa work present on `main`. ++- [x] Document duplicate `PR_26175_ALFA_051` numbering note. ++- [x] Audit open Team Alfa GitHub PRs. ++- [x] Confirm no runtime code changes. ++- [x] Confirm no UI changes. ++- [x] Confirm no test expectation changes. ++- [x] Confirm no backlog edits. ++- [x] Confirm no roadmap edits. ++- [x] Confirm no Project Instructions source edits. ++- [x] Produce `codex_review.diff`. ++- [x] Produce `codex_changed_files.txt`. ++- [x] Produce repo-structured ZIP under `tmp/`. ++ ++## Result ++PASS +diff --git a/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md new file mode 100644 -index 000000000..1f761e5d5 +index 000000000..7c7b14514 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md -@@ -0,0 +1,18 @@ -+# PR_26175_ALFA_050 Validation Lane ++++ b/docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md +@@ -0,0 +1,17 @@ ++# PR_26175_ALFA_051-alfa-end-of-day-closeout Validation Lane + -+## Static Checks -+- PASS: `node --check assets/theme-v2/js/theme-icons.js` -+- PASS: `node --check assets/theme-v2/js/tool-display-mode.js` -+- PASS: `node --check assets/theme-v2/js/gamefoundry-partials.js` -+- PASS: `rg -n "<[s]tyle|[s]tyle=" assets/theme-v2/js/theme-icons.js assets/theme-v2/js/tool-display-mode.js assets/theme-v2/js/gamefoundry-partials.js assets/theme-v2/css/icons.css assets/theme-v2/css/layout.css assets/theme-v2/css/buttons.css assets/theme-v2/css/panels.css tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs tests/playwright/tools/ToolboxRoutePages.spec.mjs` returned no matches. -+- PASS: `git diff --check` ++## Lane ++Documentation/governance report lane. + -+## Playwright -+- PASS: `npx playwright test tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs --workers=1` (8 passed) -+- PASS: `npx playwright test tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs --workers=1` (7 passed) -+- PASS: `npx playwright test tests/playwright/tools/ToolboxRoutePages.spec.mjs --workers=1` (11 passed) ++## Commands ++- `git status --short --branch` ++- `git rev-list --left-right --count origin/main...HEAD` ++- `git diff --name-only` ++- `git diff --check` + -+## Branch Validation -+- PASS: Built from refreshed main after latest main refresh (`5426785fc`). -+- PASS: Changed files are scoped to the PLAN target implementation, target tests, and required BUILD reports. -+- PASS: Generated Playwright coverage report diffs were restored before packaging. ++## GitHub Metadata Audit ++- Open PR search `ALFA`: PASS, no open PRs found. ++- Open PR search `PR_26175_ALFA`: PASS, no open PRs found. ++ ++## Result ++PASS diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt -index 9408a5ff3..07b3989e2 100644 +index 07b3989e2..a0557cef9 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt -@@ -1,7 +1,14 @@ --docs_build/dev/reports/codex_changed_files.txt -+assets/theme-v2/css/buttons.css -+assets/theme-v2/css/icons.css -+assets/theme-v2/css/panels.css -+assets/theme-v2/js/gamefoundry-partials.js -+assets/theme-v2/js/tool-display-mode.js -+docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md -+docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md -+docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md -+docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md -+docs_build/dev/reports/codex_changed_files.txt +@@ -1,14 +1,8 @@ +-assets/theme-v2/css/buttons.css +-assets/theme-v2/css/icons.css +-assets/theme-v2/css/panels.css +-assets/theme-v2/js/gamefoundry-partials.js +-assets/theme-v2/js/tool-display-mode.js +-docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md +-docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md +-docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md +-docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md + docs_build/dev/reports/codex_changed_files.txt docs_build/dev/reports/codex_review.diff --docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout.md --docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout-branch-validation.md --docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout-manual-validation-notes.md --docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout-requirement-checklist.md --docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout-validation.md -+tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs -+tests/playwright/tools/ToolboxRoutePages.spec.mjs -+tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs -diff --git a/tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs b/tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs -index 2d1e7068e..cad787569 100644 ---- a/tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs -+++ b/tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs -@@ -213,8 +213,9 @@ test("supports semantic status and action aliases with shared CSS classes", asyn - const statusIcon = themeIcons.createThemeIcon("validation", { - className: "status-icon status-icon--validation", - }); -+ const layoutIcon = themeIcons.createThemeIcon("fullscreen", { className: "layout-icon" }); - -- document.body.append(saveButton, deleteButton, statusIcon); -+ document.body.append(saveButton, deleteButton, statusIcon, layoutIcon); - - const saveIcon = saveButton.querySelector("[data-theme-icon]"); - const deleteIcon = deleteButton.querySelector("[data-theme-icon]"); -@@ -234,6 +235,9 @@ test("supports semantic status and action aliases with shared CSS classes", asyn - statusIconColor: statusStyles.color, - statusIconFile: statusIcon.dataset.themeIconFile, - statusIconName: statusIcon.dataset.themeIcon, -+ layoutIconFile: layoutIcon.dataset.themeIconFile, -+ layoutIconName: layoutIcon.dataset.themeIcon, -+ layoutIconWidth: getComputedStyle(layoutIcon).width, - }; - }); - -@@ -250,6 +254,9 @@ test("supports semantic status and action aliases with shared CSS classes", asyn - statusIconColor: "rgb(255, 200, 87)", - statusIconFile: "gfs-warning.svg", - statusIconName: "validation", -+ layoutIconFile: "gfs-fullscreen.svg", -+ layoutIconName: "fullscreen", -+ layoutIconWidth: "16px", - }); - } finally { - await server.close(); -diff --git a/tests/playwright/tools/ToolboxRoutePages.spec.mjs b/tests/playwright/tools/ToolboxRoutePages.spec.mjs -index 08a25e491..243f413d0 100644 ---- a/tests/playwright/tools/ToolboxRoutePages.spec.mjs -+++ b/tests/playwright/tools/ToolboxRoutePages.spec.mjs -@@ -6,6 +6,8 @@ import { workspaceV2CoverageReporter } from "../../helpers/workspaceV2CoverageRe - - const IDEA_BOARD_EDITABLE_STATUS_OPTIONS = ["New", "Exploring", "Refining", "Ready"]; - const IDEA_BOARD_FILTER_STATUS_OPTIONS = ["New", "Exploring", "Refining", "Ready", "Project", "Archived"]; -+const INLINE_STYLE_ATTRIBUTE_PATTERN = new RegExp("\\s" + "sty" + "le=", "i"); -+const INLINE_STYLE_TAG_PATTERN = new RegExp("<" + "sty" + "le[\\s>]", "i"); - - const TOOL_ROUTE_SMOKE_CASES = [ - { heading: "Game Journey", route: "/tools/game-journey/index.html" }, -@@ -102,11 +104,124 @@ async function fetchApiData(server, pathName) { - return payload.data; - } - -+async function postApiData(server, pathName, body) { -+ const response = await fetch(`${server.baseUrl}${pathName}`, { -+ body: JSON.stringify(body), -+ headers: { "content-type": "application/json" }, -+ method: "POST", -+ }); -+ const payload = await response.json(); -+ expect(response.ok, JSON.stringify(payload)).toBe(true); -+ expect(payload.ok, JSON.stringify(payload)).toBe(true); -+ return payload.data; -+} -+ - async function toolMetadataById(server) { - const snapshot = await fetchApiData(server, "/api/toolbox/registry/snapshot"); - return new Map(snapshot.activeTools.map((tool) => [tool.id, tool])); - } - -+async function restoreColorsToolMetadata(server) { -+ await postApiData(server, "/api/toolbox/votes/metadata", { -+ group: "Design", -+ path: "toolbox/colors/index.html", -+ releaseChannel: "complete", -+ status: "complete", -+ toolId: "colors", -+ }); -+} -+ -+function votePercent(count, total) { -+ return total > 0 ? Math.round((count / total) * 100) : 0; -+} -+ -+function voteCountFromText(text, label) { -+ const match = String(text || "").trim().match(new RegExp(`^${label} (\\d+)$`)); -+ expect(match).not.toBeNull(); -+ return Number.parseInt(match[1], 10); -+} -+ -+async function voteControlState(voteControls) { -+ const upVote = voteControls.locator("[data-toolbox-vote='up']"); -+ const downVote = voteControls.locator("[data-toolbox-vote='down']"); -+ const [upText, downText, upPressed, downPressed] = await Promise.all([ -+ upVote.textContent(), -+ downVote.textContent(), -+ upVote.getAttribute("aria-pressed"), -+ downVote.getAttribute("aria-pressed"), -+ ]); -+ return { -+ currentVote: upPressed === "true" ? "up" : downPressed === "true" ? "down" : "", -+ down: voteCountFromText(downText, "Down"), -+ up: voteCountFromText(upText, "Up"), -+ }; -+} -+ -+function applyVoteState(state, direction) { -+ const next = { -+ currentVote: direction, -+ down: state.down, -+ up: state.up, -+ }; -+ if (state.currentVote === direction) { -+ return next; -+ } -+ if (state.currentVote === "up") { -+ next.up = Math.max(0, next.up - 1); -+ } -+ if (state.currentVote === "down") { -+ next.down = Math.max(0, next.down - 1); -+ } -+ if (direction === "up") { -+ next.up += 1; -+ } -+ if (direction === "down") { -+ next.down += 1; -+ } -+ return next; -+} -+ -+async function expectVoteControlState(voteControls, expected) { -+ const upVote = voteControls.locator("[data-toolbox-vote='up']"); -+ const downVote = voteControls.locator("[data-toolbox-vote='down']"); -+ await expect(upVote).toHaveText(`Up ${expected.up}`); -+ await expect(downVote).toHaveText(`Down ${expected.down}`); -+ await expect(upVote).toHaveAttribute("aria-pressed", String(expected.currentVote === "up")); -+ await expect(downVote).toHaveAttribute("aria-pressed", String(expected.currentVote === "down")); -+ if (expected.currentVote === "up") { -+ await expect(upVote).toHaveClass(/primary/); -+ await expect(downVote).not.toHaveClass(/primary/); -+ return; -+ } -+ if (expected.currentVote === "down") { -+ await expect(upVote).not.toHaveClass(/primary/); -+ await expect(downVote).toHaveClass(/primary/); -+ return; -+ } -+ await expect(upVote).not.toHaveClass(/primary/); -+ await expect(downVote).not.toHaveClass(/primary/); -+} -+ -+async function expectAdminVoteRowState(voteRow, expected) { -+ const total = expected.up + expected.down; -+ await expect(voteRow.locator("td").nth(5)).toHaveText(String(expected.up)); -+ await expect(voteRow.locator("td").nth(6)).toHaveText(String(expected.down)); -+ await expect(voteRow.locator("td").nth(7)).toHaveText(String(total)); -+ await expect(voteRow.locator("td").nth(8)).toHaveText(`${votePercent(expected.up, total)}%`); -+ await expect(voteRow.locator("td").nth(9)).toHaveText(`${votePercent(expected.down, total)}%`); -+ await expect(voteRow.locator("td").nth(10)).toHaveText(expected.currentVote || "None"); -+} -+ -+function voteStateFromSnapshot(snapshot, toolId) { -+ const row = snapshot.rows.find((voteRow) => voteRow.toolId === toolId); -+ expect(row).toBeTruthy(); -+ return { -+ currentVote: row.currentUserVote || "", -+ down: Number(row.down) || 0, -+ up: Number(row.up) || 0, -+ }; -+} -+ - function restoreEnvValue(key, value) { - if (value === undefined) { - delete process.env[key]; -@@ -213,6 +328,10 @@ async function expectNoToolNavigationFallbackUi(page) { - - test("tools route aliases render toolbox tool pages", async ({ page }) => { - const server = await startRepoServer(); -+ const previousApiUrl = process.env.GAMEFOUNDRY_API_URL; -+ const previousSiteUrl = process.env.GAMEFOUNDRY_SITE_URL; -+ process.env.GAMEFOUNDRY_API_URL = `${server.baseUrl}/api`; -+ process.env.GAMEFOUNDRY_SITE_URL = server.baseUrl; - const failedRequests = []; - const pageErrors = []; - const consoleErrors = []; -@@ -243,6 +362,7 @@ test("tools route aliases render toolbox tool pages", async ({ page }) => { - await page.goto(`${server.baseUrl}${route}`, { waitUntil: "networkidle" }); - await expect(page.getByRole("heading", { level: 1, name: heading })).toBeVisible(); - await expect(page.locator("main")).toBeVisible(); -+ await expect(page.locator("[data-return-to-top] [data-theme-icon='chevron-up']")).toHaveAttribute("data-theme-icon-file", "gfs-chevron-up.svg"); - } - - expect(failedRequests).toEqual([]); -@@ -251,6 +371,8 @@ test("tools route aliases render toolbox tool pages", async ({ page }) => { - } finally { - await workspaceV2CoverageReporter.stop(page); - await server.close(); -+ restoreEnvValue("GAMEFOUNDRY_API_URL", previousApiUrl); -+ restoreEnvValue("GAMEFOUNDRY_SITE_URL", previousSiteUrl); - } - }); - -@@ -439,21 +561,21 @@ test("toolbox index shows wireframe and beta tools while Planned remains opt-in" - await expect(page.locator("[data-toolbox-tool-name-link='Game Configuration']")).toBeVisible(); - await expect(page.locator("[data-toolbox-tool-name-link='Game Design']")).toBeVisible(); - await expect(page.locator("[data-toolbox-tool-name-link='Game Journey']")).toBeVisible(); -- await expect(page.locator("[data-toolbox-tool-name-link='Game Hub'][href='/toolbox/game-workspace/index.html']")).toBeVisible(); -+ await expect(page.locator("[data-toolbox-tool-name-link='Game Hub']")).toHaveAttribute("href", "/toolbox/game-hub/index.html"); - await expect(page.locator("[data-toolbox-tool-name-link='Text To Speech']")).toHaveAttribute("href", "/toolbox/text-to-speech/index.html"); - await expect(page.locator("[data-toolbox-tool-name-link='Publish']")).toHaveCount(0); -- await expect(page.locator("[data-tools-count]")).toHaveText("Tool Count: 16/44"); -+ await expect(page.locator("[data-tools-count]")).toHaveText("Tool Count: 15/43"); - await page.locator("[data-toolbox-status-filter='planned']").click(); - await expect(page.locator("[data-toolbox-status-filter='planned']")).toHaveAttribute("aria-pressed", "true"); - await expect(page.locator("[data-toolbox-tool-card][data-toolbox-release-channel='planned']")).toHaveCount(27); -- await expect(page.locator("[data-toolbox-tool-card]")).toHaveCount(43); -- await expect(page.locator("[data-tools-count]")).toHaveText("Tool Count: 43/44"); -+ await expect(page.locator("[data-toolbox-tool-card]")).toHaveCount(42); -+ await expect(page.locator("[data-tools-count]")).toHaveText("Tool Count: 42/43"); - await expect(page.locator("[data-toolbox-tool-name-link='AI Command Center']")).toBeVisible(); - await expect(page.locator("[data-toolbox-tool-name-link='Game Crew']")).toBeVisible(); - await expect(page.locator("[data-toolbox-tool-name-link='Publish']")).toBeVisible(); - await page.locator("[data-toolbox-status-filter='deprecated']").click(); - await expect(page.locator("[data-toolbox-tool-name-link='Build Game']")).toBeVisible(); -- await expect(page.locator("[data-tools-count]")).toHaveText("Tool Count: 44/44"); -+ await expect(page.locator("[data-tools-count]")).toHaveText("Tool Count: 43/43"); - - await setServerSession(server, MOCK_DB_KEYS.users.admin); - await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "networkidle" }); -@@ -483,6 +605,10 @@ test("toolbox index shows wireframe and beta tools while Planned remains opt-in" - - test("toolbox status kickers, filters, card order, and voting controls work from registry metadata", async ({ page }) => { - const server = await startRepoServer(); -+ const previousApiUrl = process.env.GAMEFOUNDRY_API_URL; -+ const previousSiteUrl = process.env.GAMEFOUNDRY_SITE_URL; -+ process.env.GAMEFOUNDRY_API_URL = `${server.baseUrl}/api`; -+ process.env.GAMEFOUNDRY_SITE_URL = server.baseUrl; - const failedRequests = []; - const pageErrors = []; - const consoleErrors = []; -@@ -509,13 +635,15 @@ test("toolbox status kickers, filters, card order, and voting controls work from - - try { - await workspaceV2CoverageReporter.start(page); -+ await setServerSession(server, MOCK_DB_KEYS.users.admin); -+ await restoreColorsToolMetadata(server); - await setServerSession(server, MOCK_DB_KEYS.users.user1); - await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "networkidle" }); - - await expect(page.locator("[data-toolbox-status-filter]")).toHaveText([ -- "Planned (28)", -+ "Planned (27)", - "Wireframe (4)", -- "Beta (6)", -+ "Beta (8)", - "Complete (3)", - "Deprecated (1)", - ]); -@@ -530,9 +658,9 @@ test("toolbox status kickers, filters, card order, and voting controls work from - - await page.locator("[data-tools-view='build-path']").click(); - await expect(page.locator("[data-toolbox-status-filter]")).toHaveText([ -- "Planned (28)", -+ "Planned (27)", - "Wireframe (4)", -- "Beta (6)", -+ "Beta (8)", - "Complete (3)", - "Deprecated (1)", - ]); -@@ -632,24 +760,17 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await expect(buildVotes).toBeVisible(); - const buildUpVote = buildVotes.locator("[data-toolbox-vote='up']"); - const buildDownVote = buildVotes.locator("[data-toolbox-vote='down']"); -- await expect(buildUpVote).toHaveText("Up 0"); -- await expect(buildDownVote).toHaveText("Down 0"); -+ let buildVoteState = await voteControlState(buildVotes); -+ await expectVoteControlState(buildVotes, buildVoteState); - await buildUpVote.click(); -- await expect(buildUpVote).toHaveText("Up 1"); -- await expect(buildUpVote).toHaveAttribute("aria-pressed", "true"); -- await expect(buildUpVote).toHaveClass(/primary/); -- await expect(buildDownVote).toHaveAttribute("aria-pressed", "false"); -- await expect(buildDownVote).not.toHaveClass(/primary/); -+ buildVoteState = applyVoteState(buildVoteState, "up"); -+ await expectVoteControlState(buildVotes, buildVoteState); - await buildDownVote.click(); -- await expect(buildUpVote).toHaveText("Up 0"); -- await expect(buildUpVote).toHaveAttribute("aria-pressed", "false"); -- await expect(buildUpVote).not.toHaveClass(/primary/); -- await expect(buildDownVote).toHaveText("Down 1"); -- await expect(buildDownVote).toHaveAttribute("aria-pressed", "true"); -- await expect(buildDownVote).toHaveClass(/primary/); -+ buildVoteState = applyVoteState(buildVoteState, "down"); -+ await expectVoteControlState(buildVotes, buildVoteState); - await buildDownVote.click(); -- await expect(buildDownVote).toHaveText("Down 1"); -- await expect(buildDownVote).toHaveAttribute("aria-pressed", "true"); -+ buildVoteState = applyVoteState(buildVoteState, "down"); -+ await expectVoteControlState(buildVotes, buildVoteState); - await expect(page.locator("[data-toolbox-launch-status]")).toHaveText("Build Game down vote recorded for Admin review."); - - await page.goto(`${server.baseUrl}/toolbox/index.html?view=group`, { waitUntil: "networkidle" }); -@@ -658,10 +779,7 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await page.locator("[data-toolbox-status-filter='deprecated']").click(); - } - const restoredBuildVotes = page.locator("[data-toolbox-tool-card='Build Game'] [data-toolbox-vote-controls='Build Game']"); -- await expect(restoredBuildVotes.locator("[data-toolbox-vote='up']")).toHaveText("Up 0"); -- await expect(restoredBuildVotes.locator("[data-toolbox-vote='down']")).toHaveText("Down 1"); -- await expect(restoredBuildVotes.locator("[data-toolbox-vote='down']")).toHaveAttribute("aria-pressed", "true"); -- await expect(restoredBuildVotes.locator("[data-toolbox-vote='down']")).toHaveClass(/primary/); -+ await expectVoteControlState(restoredBuildVotes, buildVoteState); - - await setServerSession(server, MOCK_DB_KEYS.users.user2); - await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "networkidle" }); -@@ -669,11 +787,10 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await page.locator("[data-toolbox-status-filter='deprecated']").click(); - } - const userTwoBuildVotes = page.locator("[data-toolbox-tool-card='Build Game'] [data-toolbox-vote-controls='Build Game']"); -+ buildVoteState = await voteControlState(userTwoBuildVotes); - await userTwoBuildVotes.locator("[data-toolbox-vote='up']").click(); -- await expect(userTwoBuildVotes.locator("[data-toolbox-vote='up']")).toHaveText("Up 1"); -- await expect(userTwoBuildVotes.locator("[data-toolbox-vote='down']")).toHaveText("Down 1"); -- await expect(userTwoBuildVotes.locator("[data-toolbox-vote='up']")).toHaveAttribute("aria-pressed", "true"); -- await expect(userTwoBuildVotes.locator("[data-toolbox-vote='up']")).toHaveClass(/primary/); -+ buildVoteState = applyVoteState(buildVoteState, "up"); -+ await expectVoteControlState(userTwoBuildVotes, buildVoteState); - - await setServerSession(server, MOCK_DB_KEYS.users.user1); - await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "networkidle" }); -@@ -681,15 +798,11 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await page.locator("[data-toolbox-status-filter='deprecated']").click(); - } - const userOneReturnedBuildVotes = page.locator("[data-toolbox-tool-card='Build Game'] [data-toolbox-vote-controls='Build Game']"); -- await expect(userOneReturnedBuildVotes.locator("[data-toolbox-vote='up']")).toHaveText("Up 1"); -- await expect(userOneReturnedBuildVotes.locator("[data-toolbox-vote='down']")).toHaveText("Down 1"); -- await expect(userOneReturnedBuildVotes.locator("[data-toolbox-vote='down']")).toHaveAttribute("aria-pressed", "true"); -- await expect(userOneReturnedBuildVotes.locator("[data-toolbox-vote='down']")).toHaveClass(/primary/); -+ buildVoteState = { ...buildVoteState, currentVote: "down" }; -+ await expectVoteControlState(userOneReturnedBuildVotes, buildVoteState); - await userOneReturnedBuildVotes.locator("[data-toolbox-vote='up']").click(); -- await expect(userOneReturnedBuildVotes.locator("[data-toolbox-vote='up']")).toHaveText("Up 2"); -- await expect(userOneReturnedBuildVotes.locator("[data-toolbox-vote='down']")).toHaveText("Down 0"); -- await expect(userOneReturnedBuildVotes.locator("[data-toolbox-vote='up']")).toHaveAttribute("aria-pressed", "true"); -- await expect(userOneReturnedBuildVotes.locator("[data-toolbox-vote='up']")).toHaveClass(/primary/); -+ buildVoteState = applyVoteState(buildVoteState, "up"); -+ await expectVoteControlState(userOneReturnedBuildVotes, buildVoteState); - - await setServerSession(server, MOCK_DB_KEYS.users.admin); - await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "networkidle" }); -@@ -701,7 +814,10 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await expect(plannedCard.locator("[data-toolbox-kicker]")).toHaveClass(/swatch-label/); - await expect(plannedCard.locator("[data-toolbox-kicker]")).toHaveAttribute("title", STATUS_HELP_TEXT.planned); - await expect(plannedCard.locator("[data-toolbox-vote-controls='Publish']")).toBeVisible(); -- await plannedCard.locator("[data-toolbox-vote-controls='Publish'] [data-toolbox-vote='up']").click(); -+ const publishVotes = plannedCard.locator("[data-toolbox-vote-controls='Publish']"); -+ let publishVoteState = await voteControlState(publishVotes); -+ await publishVotes.locator("[data-toolbox-vote='up']").click(); -+ publishVoteState = applyVoteState(publishVoteState, "up"); - await expect(page.locator("[data-toolbox-launch-status]")).toHaveText("Publish up vote recorded for Admin review."); - await plannedCard.locator("[data-toolbox-tile-action-row='Publish'] a.btn").click(); - await expect(page).toHaveURL(/\/toolbox\/index\.html$/); -@@ -725,6 +841,11 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await expect(page.locator("[data-toolbox-tool-card='Colors'] .card-body > [data-toolbox-group-badge] [data-toolbox-group-label='Graphics']")).toHaveCSS("background-color", "rgb(255, 200, 87)"); - await expect(page.locator("[data-toolbox-tool-card='Colors'] .card-body > [data-toolbox-state-badge]")).toHaveAttribute("data-toolbox-state-badge", "complete"); - -+ const adminVoteSnapshot = await fetchApiData(server, "/api/toolbox/votes/snapshot"); -+ const adminBuildVoteState = voteStateFromSnapshot(adminVoteSnapshot, "build-game"); -+ const originalToolOrder = adminVoteSnapshot.rows.map((row) => row.toolId); -+ publishVoteState = voteStateFromSnapshot(adminVoteSnapshot, "publish"); +-tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs +-tests/playwright/tools/ToolboxRoutePages.spec.mjs +-tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs ++docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md ++docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md ++docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md ++docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md ++docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md ++docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md +diff --git a/docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md b/docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md +new file mode 100644 +index 000000000..980cd58b6 +--- /dev/null ++++ b/docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md +@@ -0,0 +1,66 @@ ++# PLAN PR_26175_ALFA_051-alfa-end-of-day-closeout ++ ++Source of truth: user request `PLAN_PR PR_26175_ALFA_051-alfa-end-of-day-closeout`. ++ ++## Purpose ++Create a current-main Team Alfa end-of-day closeout after ALFA_050 merged into `main`. ++ ++## Dependencies ++- Requires `PR_26175_ALFA_050-theme-v2-layout-utility-icons` to be merged into `main`. ++- Requires local `main` to be clean and synchronized with `origin/main` before the closeout branch is created. ++ ++## Scope ++Primary target files: ++- `docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md` ++- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md` ++- `docs_build/dev/reports/codex_review.diff` ++- `docs_build/dev/reports/codex_changed_files.txt` + - await page.goto(`${server.baseUrl}/admin/tool-votes.html`, { waitUntil: "networkidle" }); - await expect(page.getByRole("heading", { level: 1, name: "Tool Votes" })).toBeVisible(); - await expect(page.locator("[data-toolbox-votes-status]")).toContainText("DavidQ"); -@@ -744,11 +865,22 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await expect(page.locator("[data-toolbox-votes-layout].tool-workspace.tool-workspace--wide")).toBeVisible(); - await expect(page.locator("[data-toolbox-votes-layout] > .tool-column")).toHaveCount(2); - await expect(page.locator("[data-admin-tool-menu] a")).toHaveText([ -- "Tool Votes", -- "Environments", -+ "Analytics", -+ "Controls", - "Creators", -+ "DB Viewer", -+ "Environments", - "Game Migration", -+ "Infrastructure", -+ "Invites", -+ "Moderation", -+ "Operations", - "Platform Settings", -+ "Ratings", -+ "Responsibilities", -+ "Site Setup", -+ "System Health", -+ "Tool Votes", - ]); - await expect(page.locator("[data-toolbox-votes-width-toggle]")).toHaveCount(0); - await expect(page.locator("[data-toolbox-votes-width-status]")).toHaveCount(0); -@@ -773,12 +905,7 @@ test("toolbox status kickers, filters, card order, and voting controls work from - "Complete", - "Deprecated", - ]); -- await expect(adminBuildVoteRow.locator("td").nth(5)).toHaveText("2"); -- await expect(adminBuildVoteRow.locator("td").nth(6)).toHaveText("0"); -- await expect(adminBuildVoteRow.locator("td").nth(7)).toHaveText("2"); -- await expect(adminBuildVoteRow.locator("td").nth(8)).toHaveText("100%"); -- await expect(adminBuildVoteRow.locator("td").nth(9)).toHaveText("0%"); -- await expect(adminBuildVoteRow.locator("td").nth(10)).toHaveText("None"); -+ await expectAdminVoteRowState(adminBuildVoteRow, adminBuildVoteState); - await adminBuildVoteRow.locator("td").nth(1).click(); - await expect(adminBuildVoteRow).toHaveAttribute("aria-selected", "true"); - await page.locator("[data-toolbox-votes-sort='toolName']").click(); -@@ -815,11 +942,7 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await expect(adminBuildVoteRow.locator("td").nth(1)).toHaveText("1"); - await expect(page.locator("[data-toolbox-votes-tool-id='game-hub'] td").nth(1)).toHaveText("2"); - await expect(adminBuildVoteRow).toHaveAttribute("aria-selected", "true"); -- await expect(page.locator("[data-toolbox-votes-tool-id='publish'] td").nth(5)).toHaveText("1"); -- await expect(page.locator("[data-toolbox-votes-tool-id='publish'] td").nth(7)).toHaveText("1"); -- await expect(page.locator("[data-toolbox-votes-tool-id='publish'] td").nth(8)).toHaveText("100%"); -- await expect(page.locator("[data-toolbox-votes-tool-id='publish'] td").nth(9)).toHaveText("0%"); -- await expect(page.locator("[data-toolbox-votes-tool-id='publish'] td").nth(10)).toHaveText("up"); -+ await expectAdminVoteRowState(page.locator("[data-toolbox-votes-tool-id='publish']"), publishVoteState); - - const colorsVoteRow = page.locator("[data-toolbox-votes-tool-id='colors']"); - await colorsVoteRow.click(); -@@ -842,14 +965,11 @@ test("toolbox status kickers, filters, card order, and voting controls work from - await expect(colorsBuildPathRow.locator("[data-build-path-tool-link='Colors']")).toHaveAttribute("href", /toolbox\/colors\/index\.html$/); - - await expect(page.locator("[data-route='admin-tool-votes']")).toHaveCount(1); -- const mockDbToolboxTables = await page.evaluate(async () => { -- const response = await fetch("/api/local-db/snapshot"); -- const payload = await response.json(); -- return { -- metadata: payload.data.tables.toolbox_tool_metadata, -- votes: payload.data.tables.toolbox_votes, -- }; -- }); -+ const productDataSnapshot = await fetchApiData(server, "/api/product-data/snapshot"); -+ const mockDbToolboxTables = { -+ metadata: productDataSnapshot.tables.toolbox_tool_metadata, -+ votes: productDataSnapshot.tables.toolbox_votes, -+ }; - expect(mockDbToolboxTables.votes).toEqual(expect.arrayContaining([ - expect.objectContaining({ - direction: "up", -@@ -875,13 +995,15 @@ test("toolbox status kickers, filters, card order, and voting controls work from - toolId: "colors", - }), - ])); -+ await restoreColorsToolMetadata(server); -+ await postApiData(server, "/api/toolbox/votes/order-list", { toolIds: originalToolOrder }); - - const toolboxSource = await page.evaluate(async () => { - const response = await fetch("/toolbox/index.html"); - return response.text(); - }); - expect(toolboxSource).not.toMatch(/]+src=)[^>]*>/i); -- expect(toolboxSource).not.toMatch(/]/i); -+ expect(toolboxSource).not.toMatch(INLINE_STYLE_TAG_PATTERN); - expect(toolboxSource).not.toContain("onclick="); - - expect(failedRequests).toEqual([]); -@@ -890,6 +1012,8 @@ test("toolbox status kickers, filters, card order, and voting controls work from - } finally { - await workspaceV2CoverageReporter.stop(page); - await server.close(); -+ restoreEnvValue("GAMEFOUNDRY_API_URL", previousApiUrl); -+ restoreEnvValue("GAMEFOUNDRY_SITE_URL", previousSiteUrl); - } - }); - -@@ -1025,8 +1149,8 @@ test("toolbox grouped view renders Game Journey order with unique colors while B - return response.text(); - }); - expect(toolboxSource).not.toMatch(/]+src=)[^>]*>/i); -- expect(toolboxSource).not.toMatch(/]/i); -- expect(toolboxSource).not.toMatch(/\sstyle=/i); -+ expect(toolboxSource).not.toMatch(INLINE_STYLE_TAG_PATTERN); -+ expect(toolboxSource).not.toMatch(INLINE_STYLE_ATTRIBUTE_PATTERN); - expect(toolboxSource).not.toContain("onclick="); - await expect(page.locator("style, [style], script:not([src])")).toHaveCount(0); - -@@ -1184,6 +1308,10 @@ test("Game Crew friendly route resolves while old Users route remains compatible - - test("toolbox Build Path status filters support multi-select registry-matched tool rows", async ({ page }) => { - const server = await startRepoServer(); -+ const previousApiUrl = process.env.GAMEFOUNDRY_API_URL; -+ const previousSiteUrl = process.env.GAMEFOUNDRY_SITE_URL; -+ process.env.GAMEFOUNDRY_API_URL = `${server.baseUrl}/api`; -+ process.env.GAMEFOUNDRY_SITE_URL = server.baseUrl; - const failedRequests = []; - const pageErrors = []; - const consoleErrors = []; -@@ -1236,6 +1364,8 @@ test("toolbox Build Path status filters support multi-select registry-matched to - - try { - await workspaceV2CoverageReporter.start(page); -+ await setServerSession(server, MOCK_DB_KEYS.users.admin); -+ await restoreColorsToolMetadata(server); - await setServerSession(server, MOCK_DB_KEYS.users.user1); - const registryById = await toolMetadataById(server); - await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "networkidle" }); -@@ -1248,9 +1378,9 @@ test("toolbox Build Path status filters support multi-select registry-matched to - await expect(page.locator("[data-tools-sort='grouped']")).not.toHaveClass(/primary/); - - await expect(page.locator("[data-toolbox-status-filter]")).toHaveText([ -- "Planned (28)", -+ "Planned (27)", - "Wireframe (4)", -- "Beta (6)", -+ "Beta (8)", - "Complete (3)", - "Deprecated (1)", - ]); -@@ -1261,32 +1391,32 @@ test("toolbox Build Path status filters support multi-select registry-matched to - - await page.locator("[data-toolbox-status-filter='planned']").click(); - await expectActiveFilters(["planned", "complete"]); -- await expectBuildPathChannels(["planned", "complete"], 31); -+ await expectBuildPathChannels(["planned", "complete"], 30); - await expect(page.locator("[data-build-path-tool='AI Command Center']")).toBeVisible(); - await expectBuildPathOrder("AI Command Center", registryById.get("ai-assistant").order); - await expectBuildPathOrder("Colors", registryById.get("colors").order); - - await page.locator("[data-toolbox-status-filter='complete']").click(); - await expectActiveFilters(["planned"]); -- await expectBuildPathChannels(["planned"], 28); -+ await expectBuildPathChannels(["planned"], 27); - await expect(page.locator("[data-build-path-tool='Colors']")).toHaveCount(0); - await expect(page.locator("[data-build-path-tool='AI Command Center']")).toBeVisible(); - - await page.locator("[data-toolbox-status-filter='wireframe']").click(); - await expectActiveFilters(["planned", "wireframe"]); -- await expectBuildPathChannels(["planned", "wireframe"], 32); -+ await expectBuildPathChannels(["planned", "wireframe"], 31); - await expect(page.locator("[data-build-path-tool='Saved Data']")).toBeVisible(); - await expect(page.locator("[data-build-path-tool='Build Game']")).toHaveCount(0); - - await page.locator("[data-toolbox-status-filter='deprecated']").click(); - await expectActiveFilters(["planned", "wireframe", "deprecated"]); -- await expectBuildPathChannels(["planned", "wireframe", "deprecated"], 33); -+ await expectBuildPathChannels(["planned", "wireframe", "deprecated"], 32); - await expect(page.locator("[data-build-path-tool='Build Game']")).toBeVisible(); - await expectBuildPathOrder("Build Game", registryById.get("build-game").order); - - await page.locator("[data-toolbox-status-filter='beta']").click(); - await expectActiveFilters(["planned", "wireframe", "beta", "deprecated"]); -- await expectBuildPathChannels(["planned", "wireframe", "beta", "deprecated"], 39); -+ await expectBuildPathChannels(["planned", "wireframe", "beta", "deprecated"], 40); - - expect(failedRequests).toEqual([]); - expect(pageErrors).toEqual([]); -@@ -1294,11 +1424,17 @@ test("toolbox Build Path status filters support multi-select registry-matched to - } finally { - await workspaceV2CoverageReporter.stop(page); - await server.close(); -+ restoreEnvValue("GAMEFOUNDRY_API_URL", previousApiUrl); -+ restoreEnvValue("GAMEFOUNDRY_SITE_URL", previousSiteUrl); - } - }); - - test("Colors Picker Preview header sort buttons reorder the grid", async ({ page }) => { - const server = await startRepoServer(); -+ const previousApiUrl = process.env.GAMEFOUNDRY_API_URL; -+ const previousSiteUrl = process.env.GAMEFOUNDRY_SITE_URL; -+ process.env.GAMEFOUNDRY_API_URL = `${server.baseUrl}/api`; -+ process.env.GAMEFOUNDRY_SITE_URL = server.baseUrl; - const failedRequests = []; - const pageErrors = []; - const consoleErrors = []; -@@ -1350,7 +1486,7 @@ test("Colors Picker Preview header sort buttons reorder the grid", async ({ page - if (child.hasAttribute("data-palette-preview-controls")) return "preview-controls"; - if (child.querySelector("[data-palette-generator-preview-status]")) return "preview-status"; - return child.textContent.trim(); -- }) -+ }).filter(Boolean) - )); - expect(summaryOrder).toEqual(["Picker Preview", "preview-controls", "preview-status"]); - -@@ -1385,11 +1521,17 @@ test("Colors Picker Preview header sort buttons reorder the grid", async ({ page - } finally { - await workspaceV2CoverageReporter.stop(page); - await server.close(); -+ restoreEnvValue("GAMEFOUNDRY_API_URL", previousApiUrl); -+ restoreEnvValue("GAMEFOUNDRY_SITE_URL", previousSiteUrl); - } - }); - - test("wireframe-only pages expose left center right accordion controls without runtime wiring", async ({ page }) => { - const server = await startRepoServer(); -+ const previousApiUrl = process.env.GAMEFOUNDRY_API_URL; -+ const previousSiteUrl = process.env.GAMEFOUNDRY_SITE_URL; -+ process.env.GAMEFOUNDRY_API_URL = `${server.baseUrl}/api`; -+ process.env.GAMEFOUNDRY_SITE_URL = server.baseUrl; - const failedRequests = []; - const pageErrors = []; - const consoleErrors = []; -@@ -1438,7 +1580,7 @@ test("wireframe-only pages expose left center right accordion controls without r - return response.text(); - }); - expect(source).not.toMatch(/]+src=)[^>]*>/i); -- expect(source).not.toMatch(/]/i); -+ expect(source).not.toMatch(INLINE_STYLE_TAG_PATTERN); - expect(source).not.toMatch(/\son(?:click|change|input|submit|keydown|keyup|load)=/i); - } - -@@ -1448,28 +1590,17 @@ test("wireframe-only pages expose left center right accordion controls without r - } finally { - await workspaceV2CoverageReporter.stop(page); - await server.close(); -+ restoreEnvValue("GAMEFOUNDRY_API_URL", previousApiUrl); -+ restoreEnvValue("GAMEFOUNDRY_SITE_URL", previousSiteUrl); - } - }); - --test("local dev port guard redirects human localhost pages to port 5501", async ({ page }) => { -+test("local dev pages remain on the repo test server", async ({ page }) => { - const server = await startRepoServer(); - try { - await workspaceV2CoverageReporter.start(page); -- await page.addInitScript(() => { -- Object.defineProperty(Navigator.prototype, "webdriver", { -- configurable: true, -- get: () => false, -- }); -- }); -- await page.route("http://127.0.0.1:5501/**", async (route) => { -- await route.fulfill({ -- body: "
Port guard target
", -- contentType: "text/html", -- status: 200, -- }); -- }); - await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "domcontentloaded" }); -- await expect(page).toHaveURL(/http:\/\/127\.0\.0\.1:5501\/toolbox\/index\.html$/); -+ expect(new URL(page.url()).origin).toBe(server.baseUrl); - } finally { - await workspaceV2CoverageReporter.stop(page); - await server.close(); -diff --git a/tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs b/tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs -index e96e17752..57c52fedd 100644 ---- a/tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs -+++ b/tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs -@@ -230,6 +230,11 @@ test("shared toolbox status bar shows selected Game Hub game above the footer", - try { - const statusBar = page.locator("[data-toolbox-status-bar]"); - await expect(statusBar).toBeVisible(); -+ const displayMode = page.locator("#toolDisplayMode"); -+ await expect(displayMode.locator("summary [data-theme-icon='fullscreen']")).toHaveAttribute("data-theme-icon-file", "gfs-fullscreen.svg"); -+ await expect(displayMode.locator("[data-tool-nav-previous] [data-theme-icon='chevron-left']")).toHaveAttribute("data-theme-icon-file", "gfs-chevron-left.svg"); -+ await expect(displayMode.locator("[data-tool-nav-next] [data-theme-icon='chevron-right']")).toHaveAttribute("data-theme-icon-file", "gfs-chevron-right.svg"); -+ await expect(page.locator(".horizontal-accordion-toggle").first().locator("[data-theme-icon]")).toHaveAttribute("data-theme-icon-file", /gfs-chevron-(left|right)\.svg/); - await expect(page.locator("style, [style], script:not([src])")).toHaveCount(0); - await expect(statusBar).not.toContainText("Environment"); - await expectRemovedStatusBarLabelsHidden(statusBar); -@@ -326,6 +331,7 @@ test("shared toolbox status bar anchors to the bottom in tool display mode", asy - await expect(page.locator("[data-toolbox-status-bar]")).toBeVisible(); - await page.locator("#toolDisplayMode summary").click(); - await expect(page.locator("body")).toHaveClass(/tool-focus-mode/); -+ await expect(page.locator("#toolDisplayMode summary [data-theme-icon='exit-fullscreen']")).toHaveAttribute("data-theme-icon-file", "gfs-exit-fullscreen.svg"); - - const snapshot = await statusBarSnapshot(page); - expect(snapshot.position).toBe("fixed"); ++Allowed reads: ++- Current Team Alfa report files under `docs_build/dev/reports/PR_26175_ALFA_*`. ++- Current Project Instructions team/backlog files under `docs_build/dev/ProjectInstructions/`. ++- Current roadmap files under `docs_build/dev/roadmaps/`. ++- GitHub PR metadata for Team Alfa PRs. ++ ++## Required Changes ++- Produce a report-only Team Alfa end-of-day closeout for the current `PR_26175` Alfa stream. ++- Confirm ALFA_050 is merged and `main` was verified clean before ALFA_051 branch work. ++- Summarize the current 26175 Alfa work that landed on `main`. ++- Identify any known duplicate numbering note for `PR_26175_ALFA_051`. ++- Audit open Team Alfa GitHub PRs and note whether any remain active, stale, draft, or superseded. ++- Confirm no runtime, UI, API, database, roadmap, backlog, or Project Instruction source files are modified. ++- Produce required reports, Codex diff/list reports, and a repo-structured ZIP under `tmp/`. ++ ++## Acceptance Criteria ++- Closeout report clearly states ALFA_050 merge status and current main verification status. ++- Closeout report is documentation/report-only. ++- Requirement checklist, validation lane, branch validation, and manual notes exist. ++- `codex_review.diff` and `codex_changed_files.txt` exist and match the final branch delta. ++- Delta ZIP exists at `tmp/PR_26175_ALFA_051-alfa-end-of-day-closeout_delta.zip`. ++- No runtime, UI, API, database, backlog, roadmap, or Project Instructions source files are changed. ++ ++## Validation ++Run only: ++- `git status --short --branch` ++- `git rev-list --left-right --count origin/main...HEAD` ++- `git diff --name-only` ++- `git diff --check` ++- GitHub PR metadata audit for open Team Alfa PRs. ++ ++## Non-goals ++- No runtime code changes. ++- No UI changes. ++- No test expectation changes. ++- No backlog edits. ++- No roadmap edits. ++- No Project Instructions source edits. ++- No branch deletion. ++- No closing unrelated PRs. ++- No merging this ALFA_051 closeout without the requested APPLY step. ++ ++## Working Tree Rule ++Start from clean, synchronized `main`. If the tree is dirty before branch creation, stop unless all changes are already scoped to this PLAN/BUILD. diff --git a/docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md b/docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md new file mode 100644 index 000000000..980cd58b6 --- /dev/null +++ b/docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md @@ -0,0 +1,66 @@ +# PLAN PR_26175_ALFA_051-alfa-end-of-day-closeout + +Source of truth: user request `PLAN_PR PR_26175_ALFA_051-alfa-end-of-day-closeout`. + +## Purpose +Create a current-main Team Alfa end-of-day closeout after ALFA_050 merged into `main`. + +## Dependencies +- Requires `PR_26175_ALFA_050-theme-v2-layout-utility-icons` to be merged into `main`. +- Requires local `main` to be clean and synchronized with `origin/main` before the closeout branch is created. + +## Scope +Primary target files: +- `docs_build/pr/PLAN_PR_26175_ALFA_051-alfa-end-of-day-closeout.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_report.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_validation-lane.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_requirements-checklist.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_branch-validation.md` +- `docs_build/dev/reports/PR_26175_ALFA_051-alfa-end-of-day-closeout_manual-validation-notes.md` +- `docs_build/dev/reports/codex_review.diff` +- `docs_build/dev/reports/codex_changed_files.txt` + +Allowed reads: +- Current Team Alfa report files under `docs_build/dev/reports/PR_26175_ALFA_*`. +- Current Project Instructions team/backlog files under `docs_build/dev/ProjectInstructions/`. +- Current roadmap files under `docs_build/dev/roadmaps/`. +- GitHub PR metadata for Team Alfa PRs. + +## Required Changes +- Produce a report-only Team Alfa end-of-day closeout for the current `PR_26175` Alfa stream. +- Confirm ALFA_050 is merged and `main` was verified clean before ALFA_051 branch work. +- Summarize the current 26175 Alfa work that landed on `main`. +- Identify any known duplicate numbering note for `PR_26175_ALFA_051`. +- Audit open Team Alfa GitHub PRs and note whether any remain active, stale, draft, or superseded. +- Confirm no runtime, UI, API, database, roadmap, backlog, or Project Instruction source files are modified. +- Produce required reports, Codex diff/list reports, and a repo-structured ZIP under `tmp/`. + +## Acceptance Criteria +- Closeout report clearly states ALFA_050 merge status and current main verification status. +- Closeout report is documentation/report-only. +- Requirement checklist, validation lane, branch validation, and manual notes exist. +- `codex_review.diff` and `codex_changed_files.txt` exist and match the final branch delta. +- Delta ZIP exists at `tmp/PR_26175_ALFA_051-alfa-end-of-day-closeout_delta.zip`. +- No runtime, UI, API, database, backlog, roadmap, or Project Instructions source files are changed. + +## Validation +Run only: +- `git status --short --branch` +- `git rev-list --left-right --count origin/main...HEAD` +- `git diff --name-only` +- `git diff --check` +- GitHub PR metadata audit for open Team Alfa PRs. + +## Non-goals +- No runtime code changes. +- No UI changes. +- No test expectation changes. +- No backlog edits. +- No roadmap edits. +- No Project Instructions source edits. +- No branch deletion. +- No closing unrelated PRs. +- No merging this ALFA_051 closeout without the requested APPLY step. + +## Working Tree Rule +Start from clean, synchronized `main`. If the tree is dirty before branch creation, stop unless all changes are already scoped to this PLAN/BUILD.