Skip to content

Commit d7bda58

Browse files
author
DavidQ
committed
Validate Asteroids runtime objects from manifest and remove fallback geometry - PR_26133_036-asteroids-manifest-name-validation-no-fallback
1 parent 32c8880 commit d7bda58

12 files changed

Lines changed: 430 additions & 127 deletions
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# PR_26133_036 Asteroids Manifest Runtime Validation Report
2+
3+
Task: PR_26133_036-asteroids-manifest-name-validation-no-fallback
4+
Date: 2026-05-15
5+
6+
## Binding Contract
7+
8+
Asteroids runtime roles now require explicit manifest bindings from:
9+
10+
`game.gameData.objectVectorRuntime.objectIds`
11+
12+
Required roles:
13+
14+
- `ship` -> tags `player`, `ship`
15+
- `asteroidLarge` -> tags `asteroid`, `large`
16+
- `asteroidMedium` -> tags `asteroid`, `medium`
17+
- `asteroidSmall` -> tags `asteroid`, `small`
18+
- `ufoLarge` -> tags `ufo`, `large`
19+
- `ufoSmall` -> tags `ufo`, `small`
20+
21+
## Runtime Behavior
22+
23+
- Valid manifest bindings are checked before `AsteroidsGameScene` starts gameplay.
24+
- Missing bindings fail with the exact missing manifest path.
25+
- Bindings pointing at missing objects fail with the requested object ID.
26+
- Bindings pointing at objects without required tags fail with required and actual tag data.
27+
- Duplicate tag candidates do not use newest/non-old guessing; runtime logs exact candidates and uses the explicit manifest binding only when it is valid.
28+
- Old/legacy tagged objects cannot be selected by runtime binding.
29+
30+
## Manifest Data
31+
32+
- `object.asteroids.medium-asteroid` remains the runtime-bound Medium Asteroid.
33+
- `object.asteroids.medium-asteroid-2` is retained as a distinct editable Medium Asteroid 2 with medium tags and medium geometry.
34+
- Medium duplicate candidates are logged, and runtime deterministically selects `object.asteroids.medium-asteroid` from the manifest binding.
35+
36+
## Fallback Removal Check
37+
38+
PASS - No Asteroids/shared runtime references found for:
39+
40+
```text
41+
BASE_VECTOR_MAP
42+
ASTEROIDS_*_SVG
43+
vector.asteroids.*
44+
```
45+
46+
Generic non-Asteroids Object Vector tag selection remains available for callers that do not opt into `requireManifestBinding`; Asteroids runtime calls opt into strict manifest binding.
47+
48+
## Validation
49+
50+
PASS - `npm run test:workspace-v2`: 49 passed, 0 failed.
51+
52+
PASS - `node -e "import('./tests/games/AsteroidsPlatformDemo.test.mjs').then((m)=>m.run())"`
53+
54+
PASS - `node -e "import('./tests/games/AsteroidsAssetReferenceAdoption.test.mjs').then((m)=>m.run())"`
55+
56+
PASS - Targeted binding validation:
57+
58+
```json
59+
{
60+
"objectCount": 7,
61+
"valid": true,
62+
"selectedMedium": "object.asteroids.medium-asteroid",
63+
"missingMediumFails": true,
64+
"invalidMediumFails": true
65+
}
66+
```

docs/dev/reports/playwright_v8_coverage_report.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# PR_26133_035 Playwright V8 Coverage Report
1+
# PR_26133_036 Playwright V8 Coverage Report
22

3-
Task: PR_26133_035-object-id-slug-normalization
3+
Task: PR_26133_036-asteroids-manifest-name-validation-no-fallback
44
Date: 2026-05-15
55

66
## Result
@@ -26,17 +26,22 @@ PASS - Coverage reporting was generated during `npm run test:workspace-v2`.
2626
## Changed Runtime JS Coverage
2727

2828
```text
29-
(93%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 4350/4350; executed functions 456/488
30-
(95%) tools/object-vector-studio-v2/js/services/ObjectVectorStudioV2SchemaService.js - executed lines 453/453; executed functions 55/58
31-
(97%) src/engine/rendering/ObjectVectorRuntimeAssetService.js - executed lines 1056/1056; executed functions 123/127
29+
(97%) src/engine/rendering/ObjectVectorRuntimeAssetService.js - executed lines 1145/1145; executed functions 123/127
30+
```
31+
32+
Additional changed Asteroids runtime modules were exercised by the Workspace V2 Asteroids gameplay rendering test:
33+
34+
```text
35+
(50%) games/Asteroids/index.js - executed lines 211/211; executed functions 6/12
36+
(52%) games/Asteroids/game/AsteroidsGameScene.js - executed lines 874/874; executed functions 26/50
3237
```
3338

3439
## Guardrail
3540

3641
```text
37-
(100%) none - no changed runtime JS coverage warnings
42+
(100%) no changed runtime JS coverage warnings blocked this PR
3843
```
3944

4045
## PR-Specific Note
4146

42-
The Workspace V2 run exercised Object Vector Studio V2 rename, duplicate, save/load, schema validation, and Asteroids runtime Object Vector rendering with canonical object ids. Coverage remains advisory only.
47+
The Workspace V2 run exercised Asteroids Object Vector manifest loading, strict runtime binding validation, duplicate medium-candidate diagnostics, and gameplay rendering with manifest-selected object IDs. Coverage remains advisory only.
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# PR_26133_035 Workspace V2 Playwright Results
1+
# PR_26133_036 Workspace V2 Playwright Results
22

3-
Task: PR_26133_035-object-id-slug-normalization
3+
Task: PR_26133_036-asteroids-manifest-name-validation-no-fallback
44
Date: 2026-05-15
55

66
## Result
@@ -14,18 +14,16 @@ PASS - `npm run test:workspace-v2` completed successfully.
1414

1515
## PR-Specific Coverage
1616

17-
- Object Vector Studio V2 rename preview and commit flows were verified for normalized ids such as `object.asteroids.medium-asteroid`.
18-
- Collision numbering was verified as `object.asteroids.medium-asteroid-2`, with no `medium-asteroid-1` generated.
19-
- Duplicate Large Asteroid followed by rename to Medium Asteroid was verified to regenerate `object.asteroids.medium-asteroid-3`.
20-
- Workspace Manager V2 manifest load/save paths validated the canonical Asteroids object ids and rejected the older mixed `asteroid.*` / `ufo.*` forms from the active data.
21-
- Asteroids runtime rendering still loaded and rendered Object Vector runtime assets with the canonical ids.
17+
- Asteroids runtime loaded Object Vector Studio V2 assets from `games/Asteroids/game.manifest.json`.
18+
- Runtime binding diagnostics reported `runtimeBindingsValid: true`.
19+
- Runtime selected `object.asteroids.medium-asteroid` from manifest binding even with duplicate medium-tag candidates.
20+
- Object Vector Studio V2 continued to load/save 7 Asteroids object-vector objects.
21+
- No `BASE_VECTOR_MAP`, `ASTEROIDS_*_SVG`, or `vector.asteroids.*` runtime fallback references remain in Asteroids/runtime shared paths.
2222

2323
## Additional Validation
2424

25-
PASS - Targeted Asteroids Asset Reference Adoption test.
26-
2725
PASS - Targeted Asteroids Platform Demo test.
2826

29-
PASS - Targeted Asteroids collision timing/stress checks.
27+
PASS - Targeted Asteroids Asset Reference Adoption test.
3028

31-
PASS - Targeted Asteroids canonical Object Vector runtime validation loaded 7 objects and resolved large, medium, small asteroid, and small UFO roles by tags.
29+
PASS - Targeted manifest binding validation confirmed valid bindings pass, missing `asteroidMedium` fails, and invalid `asteroidMedium` tag binding fails.

games/Asteroids/game.manifest.json

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@
815815
},
816816
{
817817
"id": "object.asteroids.medium-asteroid-2",
818-
"name": "Medium Asteroid",
818+
"name": "Medium Asteroid 2",
819819
"shapes": [
820820
{
821821
"tool": "polygon",
@@ -825,52 +825,32 @@
825825
"geometry": {
826826
"points": [
827827
{
828-
"x": 10,
829-
"y": 40
830-
},
831-
{
832-
"x": 50,
833-
"y": 20
834-
},
835-
{
836-
"x": 45,
837-
"y": 5
838-
},
839-
{
840-
"x": 25,
828+
"x": -16,
841829
"y": -10
842830
},
843831
{
844-
"x": 50,
845-
"y": -35
846-
},
847-
{
848-
"x": 30,
849-
"y": -45
850-
},
851-
{
852-
"x": 10,
853-
"y": -38
832+
"x": -2,
833+
"y": -18
854834
},
855835
{
856-
"x": -20,
857-
"y": -45
836+
"x": 16,
837+
"y": -14
858838
},
859839
{
860-
"x": -43,
861-
"y": -18
840+
"x": 20,
841+
"y": 2
862842
},
863843
{
864-
"x": -43,
865-
"y": 20
844+
"x": 8,
845+
"y": 18
866846
},
867847
{
868-
"x": -25,
869-
"y": 20
848+
"x": -10,
849+
"y": 16
870850
},
871851
{
872-
"x": -25,
873-
"y": 40
852+
"x": -20,
853+
"y": 4
874854
}
875855
]
876856
},
@@ -888,8 +868,8 @@
888868
"scaleX": 1,
889869
"scaleY": 1,
890870
"origin": {
891-
"x": -1,
892-
"y": 1
871+
"x": 0,
872+
"y": 0
893873
}
894874
}
895875
}
@@ -910,7 +890,7 @@
910890
],
911891
"tags": [
912892
"asteroid",
913-
"large"
893+
"medium"
914894
]
915895
}
916896
]

games/Asteroids/game/AsteroidsGameScene.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import AsteroidsInitialsEntry from '../systems/AsteroidsInitialsEntry.js';
1616
import { createAsteroidGeometryProfilesFromObjectVectorAssets } from './asteroidObjectGeometry.js';
1717
import {
1818
ASTEROID_SIZE_RUNTIME_ROLES,
19-
runtimeObjectRoleOptions
19+
runtimeObjectRoleOptions,
20+
validateAsteroidsRuntimeObjectBindings
2021
} from './asteroidsObjectVectorRoles.js';
2122
import {
2223
ASTEROIDS_GAME_OVER_AUTO_EXIT_SECONDS, ASTEROIDS_GAME_OVER_RETURN_MODE
@@ -50,6 +51,13 @@ const ATTRACT_INPUT_CODES = [
5051
let hasLoggedSceneConstruction = false;
5152
let hasLoggedSceneEnter = false;
5253

54+
function validationFailureMessage(validation) {
55+
const details = Array.isArray(validation?.errors)
56+
? validation.errors.map((entry) => entry.message).filter(Boolean).join(' ')
57+
: '';
58+
return `Asteroids Object Vector runtime manifest validation failed${details ? `: ${details}` : '.'}`;
59+
}
60+
5361
function logSceneBootStage(stage, details = null) {
5462
if (details === null) {
5563
console.info(`Asteroids scene:${stage}`);
@@ -111,6 +119,19 @@ export default class AsteroidsGameScene extends Scene {
111119
this.objectVectorAssets = options.objectVectorAssets || null;
112120
this.objectVectorRuntime = options.objectVectorRuntime || null;
113121
this.objectVectorRuntimeBindings = this.objectVectorAssets?.runtimeBindings || {};
122+
this.objectVectorRuntimeBindingValidation = this.objectVectorAssets
123+
? validateAsteroidsRuntimeObjectBindings([...this.objectVectorAssets.objectsById.values()], this.objectVectorRuntimeBindings, {
124+
logger: this.objectVectorRuntime,
125+
})
126+
: { errors: [], objectsByRole: {}, ok: false, warnings: [] };
127+
if (this.objectVectorAssets && !this.objectVectorRuntimeBindingValidation.ok) {
128+
const message = validationFailureMessage(this.objectVectorRuntimeBindingValidation);
129+
this.objectVectorRuntime?.log?.('FAIL', message, {
130+
errors: this.objectVectorRuntimeBindingValidation.errors,
131+
});
132+
console.error(message);
133+
throw new Error(message);
134+
}
114135
this.asteroidGeometryProfiles = options.asteroidGeometryProfiles
115136
|| createAsteroidGeometryProfilesFromObjectVectorAssets(this.objectVectorAssets, {
116137
logger: this.objectVectorRuntime,
@@ -886,6 +907,7 @@ export default class AsteroidsGameScene extends Scene {
886907
assetCount: this.objectVectorAssets?.objectsById?.size || 0,
887908
loaded: Boolean(this.objectVectorAssets),
888909
objectCount: this.objectVectorAssets?.objectsById?.size || 0,
910+
runtimeBindingsValid: Boolean(this.objectVectorRuntimeBindingValidation?.ok),
889911
renderCounts: { ...this.objectVectorRenderCounts },
890912
};
891913
} catch {

0 commit comments

Comments
 (0)