Skip to content

Commit 6217ade

Browse files
author
DavidQ
committed
BUILD_PR_LEVEL_09_10_GAME_ASSET_MANIFEST_COORDINATION
1 parent e9780d6 commit 6217ade

11 files changed

Lines changed: 218 additions & 163 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 3 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,3 @@
1-
# MODEL
2-
GPT-5.4
3-
4-
# REASONING
5-
high
6-
7-
# COMMAND
8-
Create BUILD_PR_LEVEL_09_09_ASSET_PIPELINE_TOOLING as a docs-first, surgical PR for `HTML-JavaScript-Gaming`.
9-
10-
## Mission
11-
Implement the shared asset pipeline layer that converts validated tool-authored data into deterministic runtime-facing assets.
12-
13-
## Dependency context
14-
This PR follows:
15-
- 09_04 asset structure simplification
16-
- 09_05 shared asset handoff enforcement
17-
- 09_06 tool launch contract alignment
18-
- 09_07 tool boundary normalization
19-
- 09_08 tool data contracts
20-
21-
Use 09_08 contract enforcement as the validation gate for this pipeline.
22-
23-
## Required scope
24-
- create a shared pipeline surface under `tools/shared`
25-
- centralize load → validate → normalize → emit stages
26-
- preserve runtime vs tool-data split:
27-
- runtime in `assets/<domain>/`
28-
- tool/editor data in `assets/<domain>/data/`
29-
- support active domains first:
30-
- sprites
31-
- tilemaps
32-
- parallax
33-
- vectors
34-
- add focused validation/tests for the pipeline layer
35-
36-
## Approved ownership pattern
37-
- game-level coordinator file at `games/<game>/assets/<game>.assets.json`
38-
- runtime assets in `games/<game>/assets/<domain>/`
39-
- tool/editor data in `games/<game>/assets/<domain>/data/`
40-
41-
## Hard rules
42-
- do not change engine code
43-
- do not add gameplay/runtime features
44-
- do not redesign tool UI
45-
- do not perform unrelated asset moves
46-
- do not duplicate validation already established in 09_08
47-
- do not let each tool keep ad hoc export logic when shared pipeline extraction is appropriate
48-
49-
## Deliverables
50-
Return a single repo-structured ZIP at:
51-
`<project folder>/tmp/BUILD_PR_LEVEL_09_09_ASSET_PIPELINE_TOOLING.zip`
52-
53-
Include:
54-
- docs/pr/BUILD_PR_LEVEL_09_09_ASSET_PIPELINE_TOOLING.md
55-
- docs/dev/codex_commands.md
56-
- docs/dev/commit_comment.txt
57-
- docs/dev/next_command.txt
58-
- docs/dev/reports/change_summary.txt
59-
- docs/dev/reports/validation_checklist.txt
60-
61-
## Validation
62-
Run focused checks only:
63-
- node --check on touched shared/pipeline files
64-
- focused pipeline validation tests
65-
- existing contract / launch / asset integration tests as needed to prevent regressions
66-
67-
## Success definition
68-
- shared asset pipeline exists under `tools/shared`
69-
- contract validation is reused from 09_08
70-
- runtime outputs and tool data are cleanly separated
71-
- active asset domains flow through a consistent pipeline
72-
- no engine/runtime scope expansion
73-
- final output is one ZIP in `<project folder>/tmp/`
1+
MODEL: GPT-5.4
2+
REASONING: high
3+
COMMAND: Implement game asset manifest coordination.

docs/dev/COMMIT_COMMENT.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
build(assets): add shared pipeline tooling with 09_08 contract-gated emit stages
1+
BUILD_PR_LEVEL_09_10_GAME_ASSET_MANIFEST_COORDINATION

docs/dev/NEXT_COMMAND.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
APPLY_PR_LEVEL_09_09_ASSET_PIPELINE_TOOLING
1+
BUILD_PR_LEVEL_09_11_RUNTIME_ASSET_BINDING
Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1 @@
1-
Summary
2-
- Implemented a shared asset pipeline tooling surface at `tools/shared/pipeline/assetPipelineTooling.js`.
3-
- Centralized staged flow: load -> validate -> normalize -> emit.
4-
- Reused 09_08 tool-data contract enforcement via `validateToolStateContract` from `tools/shared/projectToolIntegration.js`.
5-
- Added focused pipeline validation test coverage and wired it into the test runner.
6-
7-
Pipeline behavior
8-
- Active domains handled consistently:
9-
- sprites
10-
- tilemaps
11-
- parallax
12-
- vectors
13-
- Runtime/tool-data split is enforced in emitted paths:
14-
- runtime: `games/<game>/assets/<domain>/...`
15-
- tool/editor data: `games/<game>/assets/<domain>/data/...`
16-
- Coordinator output path contract:
17-
- `games/<game>/assets/<game>.assets.json`
18-
19-
Contract gate reuse (09_08)
20-
- `runAssetPipelineTooling(...)` validates all provided tool states through shared 09_08 contract validation.
21-
- Invalid tool contract state blocks emit and returns explicit issues.
22-
- No duplicate contract validation layer was introduced.
23-
24-
Files added
25-
- `tools/shared/pipeline/assetPipelineTooling.js`
26-
- `tests/tools/AssetPipelineTooling.test.mjs`
27-
28-
Files updated
29-
- `tests/run-tests.mjs`
30-
- docs/dev deliverables for this BUILD PR
31-
32-
Scope guard
33-
- No engine files changed.
34-
- No gameplay/runtime feature expansion.
35-
- No tool UI redesign.
36-
- No unrelated asset moves.
1+
Adds root asset manifest coordination.
Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,3 @@
1-
Validation Checklist - BUILD_PR_LEVEL_09_09_ASSET_PIPELINE_TOOLING
2-
3-
Scope
4-
[x] PR remains in the shared tool/asset pipeline lane only
5-
[x] No engine files changed
6-
[x] No gameplay/runtime feature changes introduced
7-
[x] No UI redesign introduced
8-
[x] No unrelated asset moves introduced
9-
10-
Pipeline
11-
[x] Shared pipeline surface exists under `tools/shared`
12-
[x] Pipeline stages cover load / validate / normalize / emit
13-
[x] 09_08 data-contract validation is reused rather than duplicated
14-
[x] Invalid tool data is surfaced before emit
15-
[x] Normalized runtime output is deterministic
16-
[x] Runtime outputs remain in `assets/<domain>/`
17-
[x] Tool/editor data remains in `assets/<domain>/data/`
18-
19-
Domains
20-
[x] Sprites supported by shared pipeline path
21-
[x] Tilemaps supported by shared pipeline path
22-
[x] Parallax supported by shared pipeline path
23-
[x] Vectors supported by shared pipeline path
24-
[x] Tilesets only included if directly required
25-
26-
Validation
27-
[x] `node --check` passes for touched files
28-
[x] Focused pipeline validation tests pass
29-
[x] Existing ProjectToolDataContracts test still passes
30-
[x] Existing ToolEntryLaunchContract test still passes
31-
[x] Existing AssetUsageIntegration test still passes if applicable
32-
33-
Executed commands
34-
- node --check tools/shared/pipeline/assetPipelineTooling.js
35-
- node --check tools/shared/projectToolIntegration.js
36-
- node --check tests/tools/AssetPipelineTooling.test.mjs
37-
- node --check tests/run-tests.mjs
38-
- node --input-type=module -e "import('./tests/tools/AssetPipelineTooling.test.mjs').then(async ({ run }) => { await run(); console.log('PASS AssetPipelineTooling'); })"
39-
- node --input-type=module -e "import('./tests/tools/ProjectToolDataContracts.test.mjs').then(async ({ run }) => { await run(); console.log('PASS ProjectToolDataContracts'); })"
40-
- node --input-type=module -e "import('./tests/tools/ToolEntryLaunchContract.test.mjs').then(async ({ run }) => { await run(); console.log('PASS ToolEntryLaunchContract'); })"
41-
- node --input-type=module -e "import('./tests/tools/AssetUsageIntegration.test.mjs').then(async ({ run }) => { await run(); console.log('PASS AssetUsageIntegration'); })"
42-
43-
Packaging
44-
[x] docs/pr document included
45-
[x] docs/dev/codex_commands.md included
46-
[x] docs/dev/commit_comment.txt included
47-
[x] docs/dev/next_command.txt included
48-
[x] docs/dev/reports/change_summary.txt included
49-
[x] docs/dev/reports/validation_checklist.txt included
50-
[x] Single ZIP produced at `<project folder>/tmp/BUILD_PR_LEVEL_09_09_ASSET_PIPELINE_TOOLING.zip`
1+
[ ] manifest exists
2+
[ ] pipeline integrates
3+
[ ] no engine changes
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Game asset manifest coordination layer.

tests/run-tests.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ import { run as runAssetRemediationSystem } from './tools/AssetRemediationSystem
9191
import { run as runToolBoundaryEnforcement } from './tools/ToolBoundaryEnforcement.test.mjs';
9292
import { run as runProjectToolDataContracts } from './tools/ProjectToolDataContracts.test.mjs';
9393
import { run as runAssetPipelineTooling } from './tools/AssetPipelineTooling.test.mjs';
94+
import { run as runGameAssetManifestCoordinator } from './tools/GameAssetManifestCoordinator.test.mjs';
9495
import { run as runToolEntryLaunchContract } from './tools/ToolEntryLaunchContract.test.mjs';
9596
import { run as runProjectPackagingSystem } from './tools/ProjectPackagingSystem.test.mjs';
9697
import { run as runRuntimeAssetLoader } from './tools/RuntimeAssetLoader.test.mjs';
@@ -207,6 +208,7 @@ const tests = [
207208
['ToolBoundaryEnforcement', runToolBoundaryEnforcement],
208209
['ProjectToolDataContracts', runProjectToolDataContracts],
209210
['AssetPipelineTooling', runAssetPipelineTooling],
211+
['GameAssetManifestCoordinator', runGameAssetManifestCoordinator],
210212
['ToolEntryLaunchContract', runToolEntryLaunchContract],
211213
['ProjectPackagingSystem', runProjectPackagingSystem],
212214
['RuntimeAssetLoader', runRuntimeAssetLoader],

tests/tools/AssetPipelineTooling.test.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export async function run() {
4141
assert.equal(ready.stages.validate.valid, true);
4242
assert.equal(ready.records.length, 4);
4343
assert.equal(ready.stages.emit.coordinatorPath, "games/asteroids/assets/asteroids.assets.json");
44+
assert.equal(ready.stages.emit.gameAssetManifestPath, "games/asteroids/assets/asteroids.assets.json");
4445
assert.equal(
4546
ready.records.every((entry) => entry.runtimePath.includes("/assets/") && !entry.runtimePath.includes("/data/")),
4647
true
@@ -51,6 +52,17 @@ export async function run() {
5152
);
5253
assert.equal(ready.coordinator.domains.sprites[0].runtimePath.startsWith("games/asteroids/assets/sprites/"), true);
5354
assert.equal(ready.coordinator.domains.sprites[0].toolDataPath.startsWith("games/asteroids/assets/sprites/data/"), true);
55+
assert.equal(ready.gameAssetManifest.status, "ready");
56+
assert.equal(ready.gameAssetManifest.filePath, "games/asteroids/assets/asteroids.assets.json");
57+
assert.equal(ready.gameAssetManifest.manifest.domains.sprites[0].assetId, "sprite.ship");
58+
assert.equal(
59+
ready.gameAssetManifest.manifest.domains.sprites[0].runtimePath.startsWith("games/asteroids/assets/sprites/"),
60+
true
61+
);
62+
assert.equal(
63+
ready.gameAssetManifest.manifest.domains.sprites[0].toolDataPath.startsWith("games/asteroids/assets/sprites/data/"),
64+
true
65+
);
5466

5567
const invalid = runAssetPipelineTooling({
5668
gameId: "Asteroids",
@@ -71,4 +83,5 @@ export async function run() {
7183
true
7284
);
7385
assert.equal(invalid.records.length, 0);
86+
assert.equal(invalid.gameAssetManifest, undefined);
7487
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import assert from "node:assert/strict";
2+
import { coordinateGameAssetManifest } from "../../tools/shared/pipeline/gameAssetManifestCoordinator.js";
3+
4+
export async function run() {
5+
const coordinated = coordinateGameAssetManifest({
6+
gameId: "Asteroids",
7+
existingManifest: {
8+
gameId: "asteroids",
9+
domains: {
10+
sprites: [
11+
{
12+
assetId: "sprite.legacy",
13+
runtimePath: "games/asteroids/assets/sprites/sprite-legacy.json",
14+
toolDataPath: "games/asteroids/assets/sprites/data/sprite-legacy-tool.json",
15+
sourceToolId: "sprite-editor"
16+
},
17+
{
18+
assetId: "sprite.ship",
19+
runtimePath: "games/asteroids/assets/sprites/sprite-ship-old.json",
20+
toolDataPath: "games/asteroids/assets/sprites/data/sprite-ship-old-tool.json",
21+
sourceToolId: "sprite-editor"
22+
}
23+
]
24+
}
25+
},
26+
records: [
27+
{
28+
domain: "sprites",
29+
assetId: "sprite.ship",
30+
runtimePath: "games/asteroids/assets/sprites/sprite-ship.json",
31+
toolDataPath: "games/asteroids/assets/sprites/data/sprite-ship-tool.json",
32+
sourceToolId: "sprite-editor"
33+
},
34+
{
35+
domain: "vectors",
36+
assetId: "vector.ship",
37+
runtimePath: "games/asteroids/assets/vectors/vector-ship.json",
38+
toolDataPath: "games/asteroids/assets/vectors/data/vector-ship-tool.json",
39+
sourceToolId: "vector-asset-studio"
40+
}
41+
]
42+
});
43+
44+
assert.equal(coordinated.status, "ready");
45+
assert.equal(coordinated.filePath, "games/asteroids/assets/asteroids.assets.json");
46+
assert.equal(coordinated.summary.totalAssets, 3);
47+
assert.deepEqual(
48+
coordinated.manifest.domains.sprites.map((entry) => entry.assetId),
49+
["sprite.legacy", "sprite.ship"]
50+
);
51+
assert.equal(
52+
coordinated.manifest.domains.sprites.find((entry) => entry.assetId === "sprite.ship").runtimePath,
53+
"games/asteroids/assets/sprites/sprite-ship.json"
54+
);
55+
assert.equal(coordinated.manifest.domains.vectors[0].assetId, "vector.ship");
56+
}

tools/shared/pipeline/assetPipelineTooling.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { safeString } from "../projectSystemValueUtils.js";
22
import { validateToolStateContract } from "../projectToolIntegration.js";
3+
import { coordinateGameAssetManifest } from "./gameAssetManifestCoordinator.js";
34

45
export const ASSET_PIPELINE_TOOLING_SCHEMA = "html-js-gaming.asset-pipeline-tooling";
56
export const ASSET_PIPELINE_TOOLING_VERSION = 1;
@@ -186,9 +187,16 @@ export function runAssetPipelineTooling(options = {}) {
186187
normalizedRecordCount: normalizedRecords.length
187188
};
188189
const coordinator = buildCoordinator(gameId, normalizedRecords);
190+
const gameAssetManifest = coordinateGameAssetManifest({
191+
gameId,
192+
coordinatorPath: `games/${gameId}/assets/${gameId}.assets.json`,
193+
records: normalizedRecords,
194+
existingManifest: options.existingManifest
195+
});
189196
const emitStage = {
190197
stage: ASSET_PIPELINE_TOOLING_STAGES.EMIT,
191-
coordinatorPath: `games/${gameId}/assets/${gameId}.assets.json`,
198+
coordinatorPath: gameAssetManifest.filePath,
199+
gameAssetManifestPath: gameAssetManifest.filePath,
192200
emittedRecordCount: normalizedRecords.length
193201
};
194202

@@ -203,6 +211,7 @@ export function runAssetPipelineTooling(options = {}) {
203211
emit: emitStage
204212
},
205213
records: normalizedRecords,
206-
coordinator
214+
coordinator,
215+
gameAssetManifest
207216
};
208217
}

0 commit comments

Comments
 (0)