Skip to content

Commit e3ee0a6

Browse files
author
DavidQ
committed
Wire Workspace Manager V2 UAT to real template manifest and preserve generated game manifest output - PR_26127_001-workspace-manager-v2-uat-template-manifest
1 parent ced7949 commit e3ee0a6

14 files changed

Lines changed: 300 additions & 102 deletions
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# PR_26127_001-workspace-manager-v2-uat-template-manifest
2+
3+
## Scope
4+
5+
- Read `docs/dev/PROJECT_INSTRUCTIONS.md` before implementation.
6+
- Renamed the template source manifest from `games/_template/game.manifest.json` to `games/_template/workspace-manager-v2-template.manifest.json`.
7+
- Added real UAT manifest `games/_template/workspace-manager-v2-UAT.manifest.json`.
8+
- Updated Workspace Manager V2 UAT button flow to load the real UAT manifest from disk instead of constructing UAT manifest data in code.
9+
- Updated new-game scaffold logic so generated games still receive `game.manifest.json` created from `workspace-manager-v2-template.manifest.json`.
10+
- Added canonical V2 launch tiles for `tools/templates-v2`, `tools/asset-manager-v2`, `tools/workspace-manager-v2`, `tools/palette-manager-v2`, and `tools/preview-generator-v2`.
11+
12+
## Validation
13+
14+
- `npm run test:workspace-v2` - PASS, 24 Playwright tests.
15+
- Explicit schema validation:
16+
- `games/_template/workspace-manager-v2-UAT.manifest.json` - PASS against `tools/schemas/workspace.manifest.schema.json`.
17+
- `games/_template/workspace-manager-v2-template.manifest.json` - PASS against `tools/schemas/workspace.manifest.schema.json`.
18+
- `git diff --check` - PASS with only Git line-ending warnings.
19+
- Full samples smoke test skipped by request; this PR is Workspace V2/tool UAT scoped.
20+
21+
## Playwright Impacted
22+
23+
Yes. This PR changes Workspace Manager V2 UAT loading, workspace tool launch tiles, and Tool Template V2 workspace nav when launched from Workspace Manager V2.
24+
25+
Validated behavior:
26+
- UAT button loads `games/_template/workspace-manager-v2-UAT.manifest.json`.
27+
- Asset Manager V2 no longer receives direct `?workspace=UAT` access and still launches through Workspace Manager V2 session/context.
28+
- Five canonical V2 tool tiles render and become launch-ready after a schema-valid manifest is active.
29+
- Tool Template V2 launched from Workspace Manager V2 shows only `Return to Workspace`.
30+
- Workspace Manager V2 self tile restores the active session by `hostContextId`.
31+
- Import/export manifest behavior remains schema-gated.
32+
33+
Expected pass behavior:
34+
- Workspace Manager V2 logs successful UAT manifest load from `games/_template/workspace-manager-v2-UAT.manifest.json`.
35+
- Canonical V2 tiles launch through session/context without direct workspace query fallback.
36+
- Return to Workspace restores the active manifest/session.
37+
38+
Expected fail behavior:
39+
- Direct Asset Manager V2 workspace query launch remains blocked by the launch guard.
40+
- Invalid manifests block export and log the exact schema failure.
41+
42+
## Manual Validation Notes
43+
44+
1. Open `/tools/workspace-manager-v2/index.html?workspace=uat`.
45+
2. Confirm the UAT button is visible.
46+
3. Click UAT and confirm Status logs loading from `/games/_template/workspace-manager-v2-UAT.manifest.json`.
47+
4. Confirm tool tiles are present for First-Class Tool Starter V2, Asset Manager V2, Workspace Manager V2, Palette Manager V2, and Preview Generator V2.
48+
5. Launch Asset Manager V2 and confirm it opens through `launch=workspace` plus `hostContextId`, not `?workspace=uat`.
49+
6. Use Return to Workspace and confirm the active Asteroids UAT session is restored.
50+
51+
Out of scope:
52+
- Full samples smoke test.
53+
- Deprecated `tools/workspace-v2`.
54+
- Sample JSON alignment.
55+

games/_template/game.manifest.json

Lines changed: 0 additions & 47 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"$schema": "tools/schemas/workspace.manifest.schema.json",
3+
"documentKind": "workspace-manifest",
4+
"schema": "html-js-gaming.project",
5+
"version": 1,
6+
"id": "workspace-manager-v2-UAT-Asteroids",
7+
"name": "Workspace Manager V2 UAT Context",
8+
"gameId": "Asteroids",
9+
"gameRoot": "games/Asteroids/",
10+
"assetsPath": "games/Asteroids/assets",
11+
"tools": {
12+
"palette-manager-v2": {
13+
"$schema": "tools/schemas/tools/palette-manager-v2.schema.json",
14+
"schema": "html-js-gaming.palette",
15+
"version": 1,
16+
"id": "workspace-manager-v2-uat-sample",
17+
"name": "Workspace Manager V2 UAT Sample Palette",
18+
"source": "Workspace Manager V2 temporary UAT sample",
19+
"sourceId": "games/_template/workspace-manager-v2-UAT.manifest.json",
20+
"locked": true,
21+
"swatches": [
22+
{
23+
"symbol": "V",
24+
"hex": "#7C3AED",
25+
"name": "Signal Violet!",
26+
"source": "UAT Sample",
27+
"tags": ["ui", "accent"]
28+
},
29+
{
30+
"symbol": "G",
31+
"hex": "#22C55E",
32+
"name": "Success Green",
33+
"source": "UAT Sample",
34+
"tags": ["success", "hud"]
35+
},
36+
{
37+
"symbol": "A",
38+
"hex": "#F59E0B",
39+
"name": "Alert Amber",
40+
"source": "UAT Sample",
41+
"tags": ["warning", "hud"]
42+
}
43+
]
44+
},
45+
"asset-manager-v2": {
46+
"$schema": "tools/schemas/tools/asset-manager-v2.schema.json",
47+
"schema": "html-js-gaming.asset-manager-v2",
48+
"version": 1,
49+
"id": "asset-manager-v2.uat.registry",
50+
"name": "Asset Manager V2 UAT Registry",
51+
"source": "workspace-manager-v2",
52+
"assets": {}
53+
}
54+
}
55+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"$schema": "tools/schemas/workspace.manifest.schema.json",
3+
"documentKind": "workspace-manifest",
4+
"schema": "html-js-gaming.project",
5+
"version": 1,
6+
"id": "workspace-manager-v2-template",
7+
"name": "Workspace Manager V2 Template",
8+
"gameId": "_template",
9+
"gameRoot": "games/_template/",
10+
"assetsPath": "games/_template/assets",
11+
"tools": {
12+
"palette-manager-v2": {
13+
"$schema": "tools/schemas/tools/palette-manager-v2.schema.json",
14+
"schema": "html-js-gaming.palette",
15+
"version": 1,
16+
"id": "palette._template.default",
17+
"name": "_template Palette",
18+
"source": "manifest",
19+
"swatches": [
20+
{
21+
"symbol": "0",
22+
"hex": "#F8FAFC",
23+
"name": "Template Light"
24+
},
25+
{
26+
"symbol": "1",
27+
"hex": "#0F172A",
28+
"name": "Template Dark"
29+
}
30+
]
31+
},
32+
"asset-manager-v2": {
33+
"$schema": "tools/schemas/tools/asset-manager-v2.schema.json",
34+
"schema": "html-js-gaming.asset-manager-v2",
35+
"version": 1,
36+
"id": "asset-manager-v2._template.registry",
37+
"name": "_template Asset Manager V2 Registry",
38+
"source": "manifest",
39+
"assets": {}
40+
}
41+
}
42+
}

scripts/PS/New-Game-from-Template.ps1

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,35 @@ function Write-JsonFile {
119119
[System.IO.File]::WriteAllText($Path, $json + [Environment]::NewLine, [System.Text.Encoding]::UTF8)
120120
}
121121

122+
function ConvertTo-WorkspaceManifestForGame {
123+
param(
124+
[Parameter(Mandatory = $true)]
125+
[object]$TemplateManifest,
126+
[Parameter(Mandatory = $true)]
127+
[string]$GameId,
128+
[Parameter(Mandatory = $true)]
129+
[string]$GameName
130+
)
131+
132+
$manifest = $TemplateManifest | ConvertTo-Json -Depth 40 | ConvertFrom-Json
133+
$manifest.id = "workspace-manager-v2-$GameId"
134+
$manifest.name = "$GameName Workspace Manager V2 Context"
135+
$manifest.gameId = $GameId
136+
$manifest.gameRoot = "games/$GameId/"
137+
$manifest.assetsPath = "games/$GameId/assets"
138+
139+
if ($null -ne $manifest.tools.'palette-manager-v2') {
140+
$manifest.tools.'palette-manager-v2'.id = "palette.$GameId.default"
141+
$manifest.tools.'palette-manager-v2'.name = "$GameName Palette"
142+
}
143+
if ($null -ne $manifest.tools.'asset-manager-v2') {
144+
$manifest.tools.'asset-manager-v2'.id = "asset-manager-v2.$GameId.registry"
145+
$manifest.tools.'asset-manager-v2'.name = "$GameName Asset Manager V2 Registry"
146+
}
147+
148+
return $manifest
149+
}
150+
122151
function New-EmptyAssetRefs {
123152
return [ordered]@{
124153
assetIds = @()
@@ -220,6 +249,25 @@ Get-ChildItem -LiteralPath $TemplatePath -Force | ForEach-Object {
220249
Copy-Item -LiteralPath $_.FullName -Destination $targetGamePath -Recurse -Force
221250
}
222251

252+
$workspaceManifestTemplatePath = Join-Path $TemplatePath "workspace-manager-v2-template.manifest.json"
253+
if (-not (Test-Path -LiteralPath $workspaceManifestTemplatePath)) {
254+
throw "Workspace Manager V2 template manifest not found: $workspaceManifestTemplatePath"
255+
}
256+
$workspaceManifestTemplate = Get-Content -LiteralPath $workspaceManifestTemplatePath -Raw | ConvertFrom-Json
257+
$gameManifestPath = Join-Path $targetGamePath "game.manifest.json"
258+
$generatedWorkspaceManifest = ConvertTo-WorkspaceManifestForGame -TemplateManifest $workspaceManifestTemplate -GameId $normalizedGameId -GameName $DisplayName
259+
Write-JsonFile -Value $generatedWorkspaceManifest -Path $gameManifestPath
260+
$templateOnlyManifestFiles = @(
261+
"workspace-manager-v2-template.manifest.json",
262+
"workspace-manager-v2-UAT.manifest.json"
263+
)
264+
foreach ($templateOnlyManifestFile in $templateOnlyManifestFiles) {
265+
$copiedTemplateOnlyManifestPath = Join-Path $targetGamePath $templateOnlyManifestFile
266+
if (Test-Path -LiteralPath $copiedTemplateOnlyManifestPath) {
267+
Remove-Item -LiteralPath $copiedTemplateOnlyManifestPath
268+
}
269+
}
270+
223271
$assetsRoot = Join-Path $targetGamePath "assets"
224272
Ensure-Directory -Path $assetsRoot
225273

@@ -329,6 +377,7 @@ $requiredPaths = @(
329377
(Join-Path $assetsRoot "tilemaps\data"),
330378
(Join-Path $assetsRoot "parallax\data"),
331379
(Join-Path $assetsRoot "vectors\data"),
380+
$gameManifestPath,
332381
$manifestPath,
333382
$projectManifestPath
334383
)
@@ -341,5 +390,6 @@ if ($missing.Count -gt 0) {
341390
Write-Host "Created game scaffold: $normalizedGameId"
342391
Write-Host "Template source: $TemplatePath"
343392
Write-Host "Game path: $targetGamePath"
393+
Write-Host "Game manifest: $gameManifestPath"
344394
Write-Host "Asset manifest: $manifestPath"
345395
Write-Host "Tool project scaffold: $projectManifestPath"

tests/playwright/tools/AssetManagerV2.spec.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ test.describe("Asset Manager V2", () => {
10061006
assetsPath: "games/Asteroids/assets",
10071007
gameRoot: "games/Asteroids/",
10081008
ok: true,
1009-
sourceId: "?workspace=UAT",
1009+
sourceId: "games/_template/workspace-manager-v2-UAT.manifest.json",
10101010
swatchCount: 3
10111011
});
10121012

@@ -1243,7 +1243,7 @@ test.describe("Asset Manager V2", () => {
12431243
});
12441244

12451245
try {
1246-
await expect(page.locator("#workspaceToolTiles [data-workspace-tool-id]")).toHaveCount(3);
1246+
await expect(page.locator("#workspaceToolTiles [data-workspace-tool-id]")).toHaveCount(5);
12471247
await page.locator("#activeGameSelect").selectOption("Asteroids");
12481248
await expect(page.locator("#workspaceContextOutput")).toContainText('"gameRoot": "games/Asteroids/"');
12491249
await expect(page.locator("#workspaceContextOutput")).toContainText('"assetsPath": "games/Asteroids/assets"');

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
140140
await expect(page.locator("#seedUatManifestButton")).toBeHidden();
141141
await expect(page.locator("#loadAsteroidsButton")).toHaveText("Load Asteroids");
142142
await expect(page.locator("#launchAssetManagerV2Button")).toHaveCount(0);
143-
await expect(page.locator("#workspaceToolTiles [data-workspace-tool-id]")).toHaveCount(3);
143+
await expect(page.locator("#workspaceToolTiles [data-workspace-tool-id]")).toHaveCount(5);
144144
expect(await page.locator("#workspaceToolTiles [data-workspace-tool-id]").evaluateAll((tiles) => tiles.every((tile) => tile.disabled))).toBe(true);
145145
await expect(page.locator("#activeGameSelect option")).toHaveText([
146146
"Select a game",
@@ -170,20 +170,29 @@ test.describe("Workspace Manager V2 bootstrap", () => {
170170
await expect(page.locator("#workspaceContextOutput")).not.toContainText('"workspaceMetadata"');
171171
await expect(page.locator("#workspaceContextOutput")).not.toContainText("samples/");
172172
await expect(page.locator("#exportManifestButton")).toBeEnabled();
173+
const templateTile = page.locator('[data-workspace-tool-id="templates-v2"]');
173174
const assetTile = page.locator('[data-workspace-tool-id="asset-manager-v2"]');
175+
const workspaceTile = page.locator('[data-workspace-tool-id="workspace-manager-v2"]');
174176
const paletteTile = page.locator('[data-workspace-tool-id="palette-manager-v2"]');
175177
const previewTile = page.locator('[data-workspace-tool-id="preview-generator-v2"]');
178+
await expect(templateTile).toBeEnabled();
179+
await expect(templateTile).toContainText("First-Class Tool Starter V2");
180+
await expect(templateTile).toContainText("Canonical V2 template");
176181
await expect(assetTile).toBeEnabled();
177182
await expect(assetTile).toContainText("Asset Manager V2");
178183
await expect(assetTile).toContainText("Ready to launch");
179184
await expect(assetTile).toContainText("13 managed assets");
185+
await expect(workspaceTile).toContainText("Workspace Manager V2");
186+
await expect(workspaceTile).toContainText("Active workspace surface");
180187
await expect(paletteTile).toContainText("11 palette swatches");
181188
await expect(previewTile).toContainText("Schema-valid manifest");
182189
const tileLayout = await page.locator("#workspaceToolTiles [data-workspace-tool-id]").evaluateAll((tiles) => tiles.map((tile) => ({
183190
height: Math.round(tile.getBoundingClientRect().height),
184191
width: Math.round(tile.getBoundingClientRect().width)
185192
})));
186193
expect(tileLayout).toEqual([
194+
{ height: 118, width: 180 },
195+
{ height: 118, width: 180 },
187196
{ height: 118, width: 180 },
188197
{ height: 118, width: 180 },
189198
{ height: 118, width: 180 }
@@ -324,6 +333,16 @@ test.describe("Workspace Manager V2 bootstrap", () => {
324333
await expect(page.locator("#exportManifestButton")).toBeEnabled();
325334
await expect(page.locator("#statusLog")).toHaveValue(/OK Restored Asteroids workspace from session context workspace-manager-v2-/);
326335

336+
await page.locator('[data-workspace-tool-id="templates-v2"]').click();
337+
await expect(page).toHaveURL(/templates-v2\/index\.html.*launch=workspace/);
338+
await expect(page.locator('[data-launch-mode-nav="tool"]')).toBeHidden();
339+
await expect(page.locator('[data-launch-mode-nav="workspace"]')).toBeVisible();
340+
await expect(page.locator('[data-launch-mode-nav="workspace"]').getByRole("button")).toHaveText(["Return to Workspace"]);
341+
await page.locator("#returnToWorkspaceButton").click();
342+
await expect(page).toHaveURL(/workspace-manager-v2\/index\.html\?hostContextId=workspace-manager-v2-/);
343+
await page.locator('[data-workspace-tool-id="workspace-manager-v2"]').click();
344+
await expect(page).toHaveURL(/workspace-manager-v2\/index\.html\?hostContextId=workspace-manager-v2-/);
345+
await expect(page.locator("#activeGameSelect")).toHaveValue("Asteroids");
327346
await page.locator('[data-workspace-tool-id="palette-manager-v2"]').click();
328347
await expect(page).toHaveURL(/palette-manager-v2\/index\.html.*launch=workspace/);
329348
await expect(page.locator('[data-launch-mode-nav="tool"]')).toBeHidden();
@@ -442,6 +461,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
442461
test("owns temporary UAT manifest seeding and launches Asset Manager V2 through session context", async ({ page }) => {
443462
const server = await openWorkspaceManagerV2(page, "?workspace=uat");
444463
const pageErrors = [];
464+
const uatManifest = JSON.parse(await readFile("games/_template/workspace-manager-v2-UAT.manifest.json", "utf8"));
445465

446466
page.on("pageerror", (error) => {
447467
pageErrors.push(error.message);
@@ -451,14 +471,22 @@ test.describe("Workspace Manager V2 bootstrap", () => {
451471
await expect(page.locator("#seedUatManifestButton")).toBeVisible();
452472
await expect(page.locator("#exportManifestButton")).toBeDisabled();
453473
await page.locator("#seedUatManifestButton").click();
474+
const uatManifestValidation = await page.evaluate(async (manifest) => {
475+
const { WorkspaceManagerV2ContextService } = await import("/tools/workspace-manager-v2/js/services/WorkspaceManagerV2ContextService.js");
476+
return new WorkspaceManagerV2ContextService().validateGeneratedManifest(manifest);
477+
}, uatManifest);
478+
expect(uatManifestValidation).toEqual({ ok: true });
454479
await expect(page.locator("#activeGameSelect")).toHaveValue("Asteroids");
455480
await expect(page.locator("#activePaletteSummary")).toContainText("Workspace Manager V2 UAT Sample Palette has 3 active colors.");
456481
await expect(page.locator("#activeAssetRegistrySummary")).toHaveText("Schema-ready Asset Manager V2 manifest payload contains 0 managed assets.");
482+
await expect(page.locator('[data-workspace-tool-id="templates-v2"]')).toContainText("Canonical V2 template");
457483
await expect(page.locator('[data-workspace-tool-id="asset-manager-v2"]')).toContainText("0 managed assets");
484+
await expect(page.locator('[data-workspace-tool-id="workspace-manager-v2"]')).toContainText("Active workspace surface");
458485
await expect(page.locator('[data-workspace-tool-id="palette-manager-v2"]')).toContainText("3 palette swatches");
486+
await expect(page.locator('[data-workspace-tool-id="preview-generator-v2"]')).toContainText("Schema-valid manifest");
459487
await expect(page.locator("#workspaceContextOutput")).toContainText('"id": "workspace-manager-v2-UAT-Asteroids"');
460-
await expect(page.locator("#workspaceContextOutput")).toContainText('"sourceId": "?workspace=UAT"');
461-
await expect(page.locator("#statusLog")).toHaveValue(/OK Seeded temporary UAT Workspace Manager V2 manifest workspace-manager-v2-UAT-Asteroids\./);
488+
await expect(page.locator("#workspaceContextOutput")).toContainText('"sourceId": "games/_template/workspace-manager-v2-UAT.manifest.json"');
489+
await expect(page.locator("#statusLog")).toHaveValue(/OK Loaded UAT Workspace Manager V2 manifest workspace-manager-v2-UAT-Asteroids from \/games\/_template\/workspace-manager-v2-UAT\.manifest\.json\./);
462490

463491
await page.locator('[data-workspace-tool-id="asset-manager-v2"]').click();
464492
await expect(page).toHaveURL(/asset-manager-v2\/index\.html.*launch=workspace/);

tools/templates-v2/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ <h2 class="tools-platform-frame__eyebrow">First-Class Tools Surface V2</h2>
4646
<button id="workspaceImportManifestButton" type="button">Import manifest</button>
4747
<button id="workspaceCopyManifestButton" type="button">Copy manifest</button>
4848
<button id="workspaceExportManifestButton" type="button">Export manifest</button>
49+
<button id="returnToWorkspaceButton" type="button" hidden>Return to Workspace</button>
4950
</nav>
5051

5152
<main class="tool-starter app-shell" data-tool-id="tool-template-v2">

0 commit comments

Comments
 (0)