Skip to content

Commit 1160d06

Browse files
author
DavidQ
committed
Perform final manifest-driven tooling and asset audit cleanup - PR_26139_022-final-manifest-audit-and-cleanup
1 parent 32133fd commit 1160d06

6 files changed

Lines changed: 130 additions & 123 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# PR_26139_022 Final Manifest Audit And Cleanup Report
2+
3+
## Scope
4+
5+
- Final manifest/tooling audit cleanup after PR_26139_021.
6+
- Kept changes limited to manifest-facing metadata, validation, Asset Manager V2 chrome asset lookup, and targeted validation expectations.
7+
- Did not introduce new game runtime behavior.
8+
9+
## Cleanup
10+
11+
- `games/metadata/games.index.metadata.json`
12+
- Synced active game `toolsUsed` from each `game.manifest.json` tool map.
13+
- Synced manifest preview metadata where the manifest preview role differed, including Pong `preview1.svg`.
14+
- Replaced remaining deprecated planned-game tool tokens with current active tool IDs.
15+
16+
- `games/index.render.js`
17+
- Removed the hardcoded Skin Editor filter injection so the games index filter list comes from normalized metadata only.
18+
19+
- `scripts/validate-json-contracts.mjs`
20+
- Removed legacy `asset-browser` validation from game manifest validation.
21+
- Removed exact Asteroids filename checks for background/bezel/font assets.
22+
- Added generic Asset Manager V2 preview/background/bezel local file validation by role.
23+
- Added explicit deprecated game-manifest tool-key rejection.
24+
25+
- `src/engine/runtime/fullscreenBezel.js`
26+
- Removed Asteroids-specific bezel stretch config path redirection.
27+
- Restricted manifest stretchOverride scanning to `tools.asset-manager-v2.assets`.
28+
29+
- `tests/playwright/tools/ObjectVectorStudioV2FirstClassToolStarter.spec.mjs`
30+
- Updated the targeted Object Vector Studio V2 validation fixture and expectations to current schema/UI behavior:
31+
- `objects[].tags` required.
32+
- object count includes state count.
33+
- Shape Geometry/Shape Transform labels are current.
34+
- Tools button reflects the current accordion label.
35+
36+
## Audit Results
37+
38+
- Game manifests validated against current schema: PASS, 11 manifests, 0 invalid.
39+
- Asset Manager V2 preview role exists for every game manifest: PASS.
40+
- Preview/background/bezel file paths are validated by Asset Manager V2 role instead of hardcoded filenames: PASS.
41+
- Deprecated game-manifest tool keys (`asset-browser`, `palette-browser`, `primitive-skin-editor`, `vector-map-editor`): none found.
42+
- Games index metadata deprecated/unknown tool IDs: none found.
43+
- Active audited runtime/tool paths contain no hardcoded `assets/images/background.png` or old Pong `/games/Pong/assets/images/preview.svg` request strings.
44+
- Object Vector Studio V2 manifest geometry audit found no `objectVectorRoles`, `vectorMaps`, or `vector-map-editor` markers in game manifests.
45+
46+
## Validation
47+
48+
- `npm run build:manifest` PASS.
49+
- `node scripts/validate-json-contracts.mjs --mode=games --details` PASS.
50+
- Custom metadata tool audit PASS.
51+
- Custom game manifest deprecated-tool and preview-role audit PASS.
52+
- Custom Object Vector Studio V2 manifest marker audit PASS.
53+
- Hardcoded preview/background request scan PASS.
54+
- `npx playwright test tests/playwright/games/GameIndexPreviewManifestResolution.spec.mjs --project=playwright --workers=1 --reporter=list` PASS, 4 passed.
55+
- `npx playwright test tests/playwright/tools/AsteroidsBackgroundAssetResolution.spec.mjs --project=playwright --workers=1 --reporter=list` PASS, 3 passed.
56+
- `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list --grep "discovers Active Game options from selected repo manifests"` PASS, 1 passed.
57+
- `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list --grep "uses header lifecycle controls and launches tools from fixed Workspace Manager V2 tiles"` PASS, 1 passed.
58+
- `npx playwright test tests/playwright/tools/ObjectVectorStudioV2FirstClassToolStarter.spec.mjs --project=playwright --workers=1 --reporter=list` PASS, 4 passed.
59+
60+
## Notes
61+
62+
- Full samples smoke test was not run because this PR is a final manifest/tooling cleanup pass and does not broadly modify shared sample loading.
63+
- The first Object Vector Studio V2 validation run exposed stale test expectations from prior schema/UI cleanup; the spec was updated narrowly and rerun successfully.

games/index.render.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,6 @@ function buildRows(metadata, pinnedSet, toolLabelMap, previewMap) {
183183
).entries()]
184184
.map(([value, label]) => ({ value, label }))
185185
.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" }));
186-
const skinEditorLabel = toolLabelMap.get("skin-editor");
187-
if (skinEditorLabel && !tools.some((entry) => entry.value === "skin-editor")) {
188-
tools.push({ value: "skin-editor", label: skinEditorLabel });
189-
tools.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" }));
190-
}
191186
const tags = [...new Set(rows.flatMap((row) => row.tags))].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }));
192187
return { rows, levels, classes, tools, tags };
193188
}

games/metadata/games.index.metadata.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"sampleTrack": false,
1616
"debugShowcase": false,
1717
"requiresService": false,
18-
"toolsUsed": ["palette-browser", "skin-editor", "asset-browser"]
18+
"toolsUsed": ["asset-manager-v2"]
1919
},
2020
{
2121
"id": "Breakout",
@@ -31,7 +31,7 @@
3131
"debugShowcase": true,
3232
"requiresService": false,
3333
"engineClassesUsed": ["engine/core/Engine", "engine/input/index/GamepadInputAdapter", "engine/input/index/InputService", "engine/scene/index/Scene", "engine/utils/math/clamp"],
34-
"toolsUsed": ["palette-browser", "skin-editor", "asset-browser"]
34+
"toolsUsed": ["asset-manager-v2"]
3535
},
3636
{
3737
"id": "SolarSystem",
@@ -47,7 +47,7 @@
4747
"debugShowcase": false,
4848
"requiresService": false,
4949
"engineClassesUsed": ["engine/core/Engine", "engine/input/index/InputService", "engine/scene/index/Scene"],
50-
"toolsUsed": ["palette-browser", "skin-editor", "asset-browser"]
50+
"toolsUsed": ["asset-manager-v2"]
5151
},
5252
{
5353
"id": "GravityWell",
@@ -63,7 +63,7 @@
6363
"debugShowcase": false,
6464
"requiresService": false,
6565
"engineClassesUsed": ["engine/core/Engine", "engine/debug/index/drawPanel", "engine/input/index/InputService", "engine/rendering/VectorDrawing/drawVectorShape", "engine/rendering/VectorDrawing/transformPoints", "engine/replay/index/ReplaySystem", "engine/scene/index/Scene", "engine/utils/index/clamp", "engine/utils/index/distance"],
66-
"toolsUsed": ["asset-browser", "svg-asset-studio"]
66+
"toolsUsed": ["palette-manager-v2", "asset-manager-v2"]
6767
},
6868
{
6969
"id": "Pong",
@@ -73,13 +73,13 @@
7373
"status": "playable",
7474
"classValues": ["games/collision/paddle"],
7575
"tags": ["arcade", "collision", "multimode"],
76-
"preview": "/games/Pong/assets/images/preview.svg",
76+
"preview": "/games/Pong/assets/images/preview1.svg",
7777
"href": "/games/Pong/index.html",
7878
"sampleTrack": true,
7979
"debugShowcase": false,
8080
"requiresService": false,
8181
"engineClassesUsed": ["engine/core/Engine", "engine/input/index/GamepadInputAdapter", "engine/input/index/InputService", "engine/scene/index/Scene", "engine/utils/math/clamp"],
82-
"toolsUsed": ["palette-browser", "skin-editor", "asset-browser"]
82+
"toolsUsed": ["palette-manager-v2", "asset-manager-v2"]
8383
},
8484
{
8585
"id": "Asteroids",
@@ -95,7 +95,7 @@
9595
"debugShowcase": true,
9696
"requiresService": false,
9797
"engineClassesUsed": ["engine/audio/index/GaplessLoopPlayer", "engine/audio/index/HtmlAudioMediaBackend", "engine/audio/index/MediaTrackService", "engine/collision/index/arePolygonsColliding", "engine/core/Engine", "engine/debug/inspectors/shared/inspectorUtils/asArray", "engine/debug/inspectors/shared/inspectorUtils/asObject", "engine/fx/index/ParticleSystem", "engine/input/index/InputService", "engine/persistence/index/StorageService", "engine/rendering/index/transformPoints", "engine/scene/index/AttractModeController", "engine/scene/index/Scene", "engine/utils/index/distance", "engine/utils/index/randomRange", "engine/utils/index/wrap", "engine/utils/math/clamp"],
98-
"toolsUsed": ["palette-browser", "asset-browser", "sprite-editor", "tile-map-editor", "parallax-editor", "svg-asset-studio", "asset-pipeline"]
98+
"toolsUsed": ["palette-manager-v2", "asset-manager-v2", "object-vector-studio-v2"]
9999
},
100100
{
101101
"id": "SpaceInvaders",
@@ -111,7 +111,7 @@
111111
"debugShowcase": false,
112112
"requiresService": false,
113113
"engineClassesUsed": ["engine/core/Engine", "engine/input/index/GamepadInputAdapter", "engine/input/index/InputService", "engine/persistence/index/StorageService", "engine/scene/index/AttractModeController", "engine/scene/index/Scene", "engine/utils/math/clamp"],
114-
"toolsUsed": ["palette-browser", "asset-browser"]
114+
"toolsUsed": ["asset-manager-v2"]
115115
},
116116
{
117117
"id": "SpaceDuel",
@@ -127,7 +127,7 @@
127127
"debugShowcase": false,
128128
"requiresService": false,
129129
"engineClassesUsed": ["engine/core/Engine", "engine/input/index/ActionInputMap", "engine/input/index/ActionInputService", "engine/persistence/index/StorageService", "engine/scene/index/AttractModeController", "engine/scene/index/Scene", "engine/utils/math/clamp"],
130-
"toolsUsed": ["palette-browser", "asset-browser"]
130+
"toolsUsed": ["asset-manager-v2"]
131131
},
132132
{
133133
"id": "AITargetDummy",
@@ -143,7 +143,7 @@
143143
"debugShowcase": false,
144144
"requiresService": false,
145145
"engineClassesUsed": ["engine/core/Engine", "engine/input/index/GamepadInputAdapter", "engine/input/index/InputService", "engine/scene/index/Scene", "engine/utils/math/clamp"],
146-
"toolsUsed": ["asset-browser"]
146+
"toolsUsed": ["asset-manager-v2"]
147147
},
148148
{
149149
"id": "Pacman",
@@ -159,7 +159,7 @@
159159
"debugShowcase": false,
160160
"requiresService": false,
161161
"engineClassesUsed": ["engine/core/Engine", "engine/input/index/GamepadInputAdapter", "engine/input/index/InputService", "engine/scene/index/Scene"],
162-
"toolsUsed": ["asset-browser"]
162+
"toolsUsed": ["asset-manager-v2"]
163163
},
164164
{
165165
"id": "vector-arcade-sample",
@@ -169,12 +169,12 @@
169169
"status": "playable",
170170
"classValues": ["games/template/vector"],
171171
"tags": ["template", "vector", "sample"],
172-
"preview": "/games/vector-arcade-sample/assets/data/parallax/template-backdrop.svg",
172+
"preview": "/games/vector-arcade-sample/assets/images/preview.svg",
173173
"href": "/games/vector-arcade-sample/index.html",
174174
"sampleTrack": true,
175175
"debugShowcase": false,
176176
"requiresService": false,
177-
"toolsUsed": ["palette-browser", "parallax-editor", "asset-browser", "sprite-editor", "tile-map-editor", "svg-asset-studio"]
177+
"toolsUsed": ["asset-manager-v2", "object-vector-studio-v2"]
178178
},
179179
{
180180
"id": "Frogger",
@@ -204,7 +204,7 @@
204204
"sampleTrack": false,
205205
"debugShowcase": false,
206206
"requiresService": false,
207-
"toolsUsed": ["sprite-editor", "vector-map-editor", "performance-profiler"]
207+
"toolsUsed": ["sprite-editor", "world-vector-studio-v2", "performance-profiler"]
208208
},
209209
{
210210
"id": "ArenaShooter",
@@ -339,7 +339,7 @@
339339
"sampleTrack": false,
340340
"debugShowcase": false,
341341
"requiresService": false,
342-
"toolsUsed": ["tile-map-editor", "vector-map-editor", "state-inspector"]
342+
"toolsUsed": ["tile-map-editor", "world-vector-studio-v2", "state-inspector"]
343343
},
344344
{
345345
"id": "FullArenaShooter",
@@ -399,7 +399,7 @@
399399
"sampleTrack": false,
400400
"debugShowcase": false,
401401
"requiresService": false,
402-
"toolsUsed": ["vector-map-editor", "svg-asset-studio", "tile-map-editor"]
402+
"toolsUsed": ["world-vector-studio-v2", "svg-asset-studio", "tile-map-editor"]
403403
},
404404
{
405405
"id": "TicTacToe",

scripts/validate-json-contracts.mjs

Lines changed: 30 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ import path from "node:path";
55
const ROOT = process.cwd();
66
const REPORT_DIR = path.join(ROOT, "docs", "dev", "reports");
77
const SCHEMA_ROOT = path.join(ROOT, "tools", "schemas");
8-
const ASSET_ID_PATTERN = /^(image|audio|font)\.[a-z0-9-]+\.[a-z0-9-]+(?:\.[a-z0-9-]+)*$/;
9-
const ASSET_KIND_SET = new Set(["image", "audio", "font"]);
10-
const ASSET_SOURCE_SET = new Set(["workspace-manager", "asset-browser", "asset-manager-v2", "manifest"]);
8+
const DEPRECATED_GAME_TOOL_IDS = new Set(["asset-browser", "palette-browser", "primitive-skin-editor", "vector-map-editor"]);
119

1210
function parseArgs(argv) {
1311
const args = {
@@ -678,6 +676,26 @@ function resolveManifestAssetPath(manifestPath, assetPath) {
678676
return path.join(path.dirname(manifestPath), normalized);
679677
}
680678

679+
function assetManagerImageEntriesByRole(assetManagerAssets, role) {
680+
const normalizedRole = String(role || "").trim().toLowerCase();
681+
if (!normalizedRole || !isPlainObject(assetManagerAssets)) {
682+
return [];
683+
}
684+
return Object.entries(assetManagerAssets)
685+
.filter(([, entry]) => entry?.type === "image" && String(entry?.role || "").trim().toLowerCase() === normalizedRole);
686+
}
687+
688+
function validateLocalAssetFiles(filePath, entries, role, errors) {
689+
for (const [assetId, entry] of entries) {
690+
const resolvedAssetPath = resolveManifestAssetPath(filePath, entry.path);
691+
if (!resolvedAssetPath) {
692+
errors.push(`${role} asset ${assetId} has a non-local or empty path: ${entry.path || "(empty)"}`);
693+
} else if (!fs.existsSync(resolvedAssetPath)) {
694+
errors.push(`${role} asset ${assetId} file is missing: ${normalizeRel(resolvedAssetPath)}`);
695+
}
696+
}
697+
}
698+
681699
function validateGames(schemaIndex, validate) {
682700
const files = walkFiles(path.join(ROOT, "games"), (filePath) => path.basename(filePath).toLowerCase() === "game.manifest.json");
683701
const gameManifestSchemaPath = "tools/schemas/game.manifest.schema.json";
@@ -702,70 +720,20 @@ function validateGames(schemaIndex, validate) {
702720
if (!assetManagerAssets || typeof assetManagerAssets !== "object" || Array.isArray(assetManagerAssets)) {
703721
errors.push("tools.asset-manager-v2.assets must be an object");
704722
} else {
705-
const previewEntries = Object.entries(assetManagerAssets)
706-
.filter(([, entry]) => entry?.type === "image" && String(entry?.role || "").trim().toLowerCase() === "preview");
723+
const previewEntries = assetManagerImageEntriesByRole(assetManagerAssets, "preview");
707724
if (previewEntries.length === 0) {
708725
errors.push("tools.asset-manager-v2.assets must include an image preview asset");
709726
}
710-
for (const [assetId, entry] of previewEntries) {
711-
const resolvedPreviewPath = resolveManifestAssetPath(filePath, entry.path);
712-
if (!resolvedPreviewPath) {
713-
errors.push(`preview asset ${assetId} has a non-local or empty path: ${entry.path || "(empty)"}`);
714-
} else if (!fs.existsSync(resolvedPreviewPath)) {
715-
errors.push(`preview asset ${assetId} file is missing: ${normalizeRel(resolvedPreviewPath)}`);
716-
}
717-
}
718-
}
719-
720-
const assets = manifest?.tools?.["asset-browser"]?.assets;
721-
if (manifest?.tools?.["asset-browser"]) {
722-
if (!assets || typeof assets !== "object" || Array.isArray(assets)) {
723-
errors.push("tools.asset-browser.assets must be an object");
724-
} else {
725-
if (Object.prototype.hasOwnProperty.call(assets, "media")) {
726-
errors.push("tools.asset-browser.assets.media is not allowed");
727-
}
728-
for (const [assetId, entry] of Object.entries(assets)) {
729-
if (!ASSET_ID_PATTERN.test(assetId)) {
730-
errors.push(`invalid asset id pattern: ${assetId}`);
731-
}
732-
if (!isPlainObject(entry)) {
733-
errors.push(`asset entry must be object: ${assetId}`);
734-
continue;
735-
}
736-
if (typeof entry.path !== "string" || !entry.path.trim()) {
737-
errors.push(`asset entry missing path: ${assetId}`);
738-
}
739-
if (!ASSET_KIND_SET.has(String(entry.kind || ""))) {
740-
errors.push(`asset entry invalid kind: ${assetId}`);
741-
}
742-
if (!ASSET_SOURCE_SET.has(String(entry.source || ""))) {
743-
errors.push(`asset entry invalid source: ${assetId}`);
744-
}
745-
if (Object.prototype.hasOwnProperty.call(entry, "stretchOverride")) {
746-
if (!/^image\.[a-z0-9-]+(?:\.[a-z0-9-]+)*\.bezel$/.test(assetId)) {
747-
errors.push(`stretchOverride only allowed on image.*.bezel entries: ${assetId}`);
748-
}
749-
if (!isPlainObject(entry.stretchOverride) || typeof entry.stretchOverride.uniformEdgeStretchPx !== "number") {
750-
errors.push(`invalid stretchOverride payload: ${assetId}`);
751-
}
752-
}
753-
}
754-
}
727+
validateLocalAssetFiles(filePath, previewEntries, "preview", errors);
728+
validateLocalAssetFiles(filePath, assetManagerImageEntriesByRole(assetManagerAssets, "background"), "background", errors);
729+
validateLocalAssetFiles(filePath, assetManagerImageEntriesByRole(assetManagerAssets, "bezel"), "bezel", errors);
755730
}
756731

757-
if (rel === "games/Asteroids/game.manifest.json") {
758-
const astAssets = manifest?.tools?.["asset-manager-v2"]?.assets || {};
759-
if (astAssets?.["assets.image.bezel.bezel"]?.path !== "assets/images/bezel.png") {
760-
errors.push("Asteroids bezel path must be assets/images/bezel.png");
761-
}
762-
if (astAssets?.["assets.image.background.deluxe"]?.path !== "assets/images/deluxe.png") {
763-
errors.push("Asteroids background path must be assets/images/deluxe.png");
732+
Object.keys(manifest?.tools || {}).forEach((toolId) => {
733+
if (DEPRECATED_GAME_TOOL_IDS.has(toolId)) {
734+
errors.push(`deprecated game manifest tool is not allowed: tools.${toolId}`);
764735
}
765-
if (astAssets?.["assets.font.ui.vector-battle"]?.path !== "src/assets/fonts/vector_battle/vector_battle.ttf") {
766-
errors.push("Asteroids assets.font.ui.vector-battle must point to src/assets/fonts/vector_battle/vector_battle.ttf");
767-
}
768-
}
736+
});
769737
}
770738

771739
rows.push({
@@ -852,10 +820,7 @@ function writeUsageReport(reportDir, usageSummary) {
852820
lines.push("# Schema Usage Code Updates");
853821
lines.push("");
854822
lines.push("## Updated Runtime/Validation Paths");
855-
lines.push("- tools/Workspace Manager/main.js: schema runtime validator now supports anyOf/allOf/not, propertyNames, and typed additionalProperties.");
856-
lines.push("- tools/schemas/workspace.manifest.schema.json: removed duplicate palette alias key `palette-browser` from workspace tools contract.");
857-
lines.push("- tools/schemas/tools/asset-browser.schema.json: tightened asset id/kind/source rules and stretchOverride placement.");
858-
lines.push("- samples/phase-19/1902/sample.1902.workspace-all-tools.json: removed duplicate `palette-browser` block and normalized asset-browser asset ids.");
823+
lines.push("- scripts/validate-json-contracts.mjs: validates game manifests against the current schema, Asset Manager V2 preview/background/bezel asset file paths, and deprecated game-manifest tool keys.");
859824
lines.push("");
860825
lines.push("## Validation Summary");
861826
lines.push(`- Tool schema rows: ${usageSummary.toolRows}`);

0 commit comments

Comments
 (0)