Skip to content

Commit 69b465e

Browse files
author
DavidQ
committed
Normalize shared manifest loader to remove Asteroids-specific coupling
BUILD_PR_LEVEL_10_10_SHARED_MANIFEST_LOADER_NORMALIZATION
1 parent a3f1d57 commit 69b465e

9 files changed

Lines changed: 98 additions & 27 deletions

asteroids.txt

3.22 KB
Binary file not shown.

docs/dev/CODEX_COMMANDS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
MODEL: GPT-5.3-codex
2-
REASONING: medium
3-
COMMAND: Implement manifest loader that reads asteroids.asset.manifest.json and exposes discovery API without modifying engine core
2+
REASONING: high
3+
COMMAND: Normalize shared manifest loader to be game-agnostic, rename file and APIs, parameterize gameId, update tests accordingly

docs/dev/COMMIT_COMMENT.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Define Asteroids manifest loader integration contract
2-
BUILD_PR_LEVEL_10_09_ASTEROIDS_MANIFEST_LOADER_INTEGRATION
1+
Normalize shared manifest loader to remove Asteroids-specific coupling
2+
BUILD_PR_LEVEL_10_10_SHARED_MANIFEST_LOADER_NORMALIZATION

docs/dev/NEXT_COMMAND.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
BUILD_PR_LEVEL_10_10_ASTEROIDS_MANIFEST_RUNTIME_HOOK
1+
BUILD_PR_LEVEL_10_11_ASTEROIDS_MANIFEST_RUNTIME_HOOK
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Defined loader integration contract
1+
Identified and corrected shared pipeline coupling issue
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
- Contract defined
2-
- Codex command present
3-
- No engine changes
1+
- No game-specific naming in shared loader
2+
- API parameterized
3+
- Tests updated
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# BUILD_PR_LEVEL_10_10_SHARED_MANIFEST_LOADER_NORMALIZATION
2+
3+
## Problem
4+
Shared pipeline loader is incorrectly scoped to Asteroids:
5+
- Filename includes "asteroids"
6+
- API names are game-specific
7+
- Hardcoded path to Asteroids assets
8+
9+
This violates shared pipeline contract.
10+
11+
## Purpose
12+
Normalize loader to be game-agnostic.
13+
14+
## Scope
15+
- Rename loader to generic name
16+
- Replace Asteroids-specific API with generic API
17+
- Parameterize game path input
18+
19+
## Required Changes (Codex)
20+
- Rename:
21+
tools/shared/pipeline/asteroidsAssetManifestLoader.js
22+
→ tools/shared/pipeline/assetManifestLoader.js
23+
24+
- Replace API:
25+
loadAsteroidsAssetManifest → loadAssetManifest(gameId, options?)
26+
discoverAsteroidsRuntimeAssets → discoverRuntimeAssets(gameId, options?)
27+
28+
- Remove hardcoded path:
29+
games/Asteroids/assets/...
30+
→ games/<gameId>/assets/...
31+
32+
## Testable Outcome
33+
- Loader works for Asteroids via parameter
34+
- No game-specific naming remains
35+
- Existing Asteroids test updated to pass gameId
36+
37+
## Non-Goals
38+
- No engine modification
Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
import assert from "node:assert/strict";
22
import {
3-
ASTEROIDS_ASSET_MANIFEST_RELATIVE_PATH,
4-
discoverAsteroidsRuntimeAssets,
5-
loadAsteroidsAssetManifest
6-
} from "../../tools/shared/pipeline/asteroidsAssetManifestLoader.js";
3+
discoverRuntimeAssets,
4+
getAssetManifestRelativePath,
5+
loadAssetManifest
6+
} from "../../tools/shared/pipeline/assetManifestLoader.js";
77

88
function normalizePath(value) {
99
return String(value || "").replace(/\\/g, "/");
1010
}
1111

1212
export async function run() {
13-
const loaded = await loadAsteroidsAssetManifest();
13+
const gameId = "Asteroids";
14+
const loaded = await loadAssetManifest(gameId);
1415
assert.equal(loaded.status, "ready");
1516
assert.equal(Array.isArray(loaded.issues), true);
1617
assert.equal(loaded.issues.length, 0);
1718
assert.equal(loaded.manifest.gameId, "asteroids");
18-
assert.equal(normalizePath(loaded.manifestPath).endsWith(ASTEROIDS_ASSET_MANIFEST_RELATIVE_PATH), true);
19+
assert.equal(
20+
normalizePath(loaded.manifestPath).endsWith(getAssetManifestRelativePath(gameId)),
21+
true
22+
);
1923

20-
const discovered = await discoverAsteroidsRuntimeAssets();
24+
const discovered = await discoverRuntimeAssets(gameId);
2125
assert.equal(discovered.status, "ready");
2226
assert.equal(discovered.issues.length, 0);
2327
assert.equal(Object.keys(discovered.runtimeAssetSources).length > 0, true);
2428
assert.equal(
2529
discovered.runtimeAssetSources["vector.asteroids.ship"].file.includes("/data/"),
2630
false
2731
);
32+
33+
const missingGameId = await loadAssetManifest("");
34+
assert.equal(missingGameId.status, "invalid");
35+
assert.equal(missingGameId.issues.includes("gameId is required."), true);
2836
}

tools/shared/pipeline/asteroidsAssetManifestLoader.js renamed to tools/shared/pipeline/assetManifestLoader.js

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ import {
66
validateGameAssetManifestStructure
77
} from "./gameAssetManifestDiscovery.js";
88

9-
export const ASTEROIDS_ASSET_MANIFEST_RELATIVE_PATH = "games/Asteroids/assets/asteroids.asset.manifest.json";
10-
119
const MODULE_DIRECTORY = path.dirname(fileURLToPath(import.meta.url));
1210
const REPO_ROOT = path.resolve(MODULE_DIRECTORY, "../../../");
1311

14-
function toManifestPath(options = {}) {
12+
function toManifestPath(gameId, options = {}) {
1513
if (typeof options.manifestPath === "string" && options.manifestPath.trim()) {
1614
return path.resolve(options.manifestPath);
1715
}
18-
return path.resolve(REPO_ROOT, ASTEROIDS_ASSET_MANIFEST_RELATIVE_PATH);
16+
return path.resolve(REPO_ROOT, getAssetManifestRelativePath(gameId));
17+
}
18+
19+
function toGameId(gameId) {
20+
return String(gameId || "").trim();
1921
}
2022

2123
async function readManifestJson(manifestPath) {
@@ -26,8 +28,27 @@ async function readManifestJson(manifestPath) {
2628
};
2729
}
2830

29-
export async function loadAsteroidsAssetManifest(options = {}) {
30-
const manifestPath = toManifestPath(options);
31+
export function getAssetManifestRelativePath(gameId) {
32+
const normalizedGameId = toGameId(gameId);
33+
if (!normalizedGameId) {
34+
throw new Error("gameId is required to resolve asset manifest path.");
35+
}
36+
return `games/${normalizedGameId}/assets/${normalizedGameId.toLowerCase()}.asset.manifest.json`;
37+
}
38+
39+
export async function loadAssetManifest(gameId, options = {}) {
40+
const normalizedGameId = toGameId(gameId);
41+
if (!normalizedGameId) {
42+
return {
43+
status: "invalid",
44+
manifestPath: "",
45+
manifest: null,
46+
discovery: null,
47+
issues: ["gameId is required."]
48+
};
49+
}
50+
51+
const manifestPath = toManifestPath(normalizedGameId, options);
3152
let payload;
3253
try {
3354
payload = await readManifestJson(manifestPath);
@@ -37,11 +58,13 @@ export async function loadAsteroidsAssetManifest(options = {}) {
3758
manifestPath,
3859
manifest: null,
3960
discovery: null,
40-
issues: [error instanceof Error ? error.message : "Failed to read Asteroids asset manifest."]
61+
issues: [error instanceof Error ? error.message : "Failed to read game asset manifest."]
4162
};
4263
}
4364

44-
const validation = validateGameAssetManifestStructure(payload.manifest, { gameId: "asteroids" });
65+
const validation = validateGameAssetManifestStructure(payload.manifest, {
66+
gameId: normalizedGameId.toLowerCase()
67+
});
4568
if (!validation.valid) {
4669
return {
4770
status: "invalid",
@@ -52,7 +75,9 @@ export async function loadAsteroidsAssetManifest(options = {}) {
5275
};
5376
}
5477

55-
const discovery = discoverRuntimeAssetSourcesFromManifest(payload.manifest, { gameId: "asteroids" });
78+
const discovery = discoverRuntimeAssetSourcesFromManifest(payload.manifest, {
79+
gameId: normalizedGameId.toLowerCase()
80+
});
5681
return {
5782
status: discovery.status,
5883
manifestPath,
@@ -62,8 +87,8 @@ export async function loadAsteroidsAssetManifest(options = {}) {
6287
};
6388
}
6489

65-
export async function discoverAsteroidsRuntimeAssets(options = {}) {
66-
const loaded = await loadAsteroidsAssetManifest(options);
90+
export async function discoverRuntimeAssets(gameId, options = {}) {
91+
const loaded = await loadAssetManifest(gameId, options);
6792
if (loaded.status !== "ready") {
6893
return {
6994
status: "invalid",

0 commit comments

Comments
 (0)