Skip to content

Commit c80fce5

Browse files
author
DavidQ
committed
Remove duplicate Asteroids object runtime bindings and enforce object IDs as SSoT - PR_26133_044-remove-duplicated-object-vector-runtime-bindings
1 parent 0287320 commit c80fce5

12 files changed

Lines changed: 121 additions & 214 deletions
Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# PR_26133_043 Playwright V8 Coverage Report
1+
# PR_26133_044 Playwright V8 Coverage Report
22

3-
Task: PR_26133_043-object-transform-center-and-opacity-input-tuning
3+
Task: PR_26133_044-remove-duplicated-object-vector-runtime-bindings
44
Date: 2026-05-15
55

66
## Result
@@ -10,32 +10,25 @@ PASS - Coverage reporting was generated during `npm run test:workspace-v2`.
1010
- Coverage source: Playwright/Chromium built-in V8 coverage.
1111
- Thresholds: none enforced.
1212
- Coverage is advisory for this PR.
13-
- Source report: `docs/dev/reports/playwright_v8_coverage_report.txt`.
13+
- Source report: `docs/dev/reports/playwright_v8_coverage.txt`.
1414

1515
## Exercised Tool Entry Points
1616

1717
```text
1818
(82%) Preview Generator V2 - exercised 19 runtime JS files
1919
(74%) Asset Manager V2 - exercised 13 runtime JS files
2020
(62%) Palette Manager V2 - exercised 12 runtime JS files
21-
(0%) Tool Template V2 - not exercised by this Playwright run
2221
(91%) Workspace Manager V2 - exercised 10 runtime JS files
23-
(0%) Workspace Manager - not exercised by this Playwright run
2422
```
2523

26-
## Changed Runtime JS Coverage
24+
## Relevant Runtime Coverage
2725

2826
```text
29-
(94%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 4751/4751; executed functions 493/522
27+
(98%) src/engine/rendering/ObjectVectorRuntimeAssetService.js - executed lines 914/914; executed functions 106/108
28+
(52%) games/Asteroids/game/AsteroidsGameScene.js - executed lines 846/846; executed functions 25/48
3029
```
3130

32-
## Changed Markup/Style/Test Coverage Note
33-
34-
```text
35-
(0%) tests/playwright/tools/WorkspaceManagerV2.spec.mjs - changed JS file not collected as browser runtime coverage
36-
```
37-
38-
Markup and CSS changes in `tools/object-vector-studio-v2/index.html` and `tools/object-vector-studio-v2/styles/toolStarter.css` are verified through Playwright DOM/CSS assertions rather than V8 JavaScript coverage.
31+
The Asteroids runtime role helpers and asteroid geometry helper are exercised through the Asteroids gameplay rendering path and targeted node smoke checks; they are not surfaced as separate changed-runtime rows in the generated V8 summary.
3932

4033
## Guardrail
4134

@@ -45,4 +38,4 @@ Markup and CSS changes in `tools/object-vector-studio-v2/index.html` and `tools/
4538

4639
## PR-Specific Note
4740

48-
The Workspace V2 run exercised Object Vector Studio V2 Center button labeling and recentering behavior, 0-255 opacity input validation, byte-to-normalized opacity conversion for SVG/schema rendering, and opacity input sizing/layout assertions. Coverage remains advisory only.
41+
The Workspace V2 run exercised Object Vector runtime manifest loading from `game.workspace.tools.object-vector-studio-v2.objects`, direct object ID role resolution, runtime rendering for asteroids/ship/UFO, and schema rejection of the removed `game.gameData.objectVectorRuntime` branch.
Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# PR_26133_043 Workspace V2 Playwright Results
1+
# PR_26133_044 Workspace V2 Playwright Results
22

3-
Task: PR_26133_043-object-transform-center-and-opacity-input-tuning
3+
Task: PR_26133_044-remove-duplicated-object-vector-runtime-bindings
44
Date: 2026-05-15
55

66
## Result
@@ -10,17 +10,22 @@ PASS - `npm run test:workspace-v2` completed successfully.
1010
- Command: `npm run test:workspace-v2`
1111
- Playwright target: `tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list`
1212
- Final result: 51 passed, 0 failed.
13-
- Runtime/console guard: Object Vector Studio V2 tests that monitor page errors and console errors completed with no reported errors.
13+
- Runtime/console guard: Asteroids Object Vector runtime and Workspace Manager V2 tests completed with no reported page errors.
1414

1515
## PR-Specific Coverage
1616

17-
- Verified Object Preview viewport controls now render `Center` instead of `Dot`.
18-
- Verified Center recenters the preview viewport to origin `0,0`, preserves current zoom, refreshes stale pointer text back to the centered origin display, and keeps the center marker visible.
19-
- Verified Fill Op and Stroke Op inputs use `min=0`, `max=255`, `step=1`, and width sufficient for 4 visible digits.
20-
- Verified opacity inputs visibly reject out-of-range values such as `-1` and `256`.
21-
- Verified valid 0-255 opacity inputs convert to normalized style opacity values for schema/SVG rendering.
22-
- Verified Fill Op and Stroke Op remain in the compact opacity row below Paint, Stroke, and Width.
17+
- Verified Asteroids launches Object Vector runtime assets from `game.workspace.tools.object-vector-studio-v2.objects`.
18+
- Verified runtime role validation resolves `object.asteroids.*` IDs directly from the loaded Object Vector object list.
19+
- Verified `game.gameData.objectVectorRuntime` is absent from `games/Asteroids/game.manifest.json`.
20+
- Verified schema validation rejects a manifest when `game.gameData.objectVectorRuntime` is re-added.
21+
- Verified runtime rendering counts for asteroids, ship, and UFO remain active after removing the duplicate binding map.
2322

24-
## Manual Verification Equivalent
23+
## Additional Validation
2524

26-
Targeted Object Vector Studio V2 browser automation covered the requested Center label and centering behavior, opacity input sizing/range validation, normalized opacity rendering behavior, Palette opacity row layout, and no-console-error checks.
25+
- `node` manifest-schema check: current Asteroids manifest returned `{ ok: true }`.
26+
- `node` manifest-schema check: injected `game.gameData.objectVectorRuntime` returned `{ ok: false }`.
27+
- Targeted node smoke checks passed for `tests/games/AsteroidsPlatformDemo.test.mjs` and `tests/games/AsteroidsAssetReferenceAdoption.test.mjs`.
28+
29+
## Notes
30+
31+
- `npm test` is blocked before the node suite by the existing shared-extraction guard baseline drift; this PR did not touch those unrelated guard violations.

games/Asteroids/game.manifest.json

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,6 @@
1111
"directPath": "/games/Asteroids/index.html",
1212
"workspaceManagerPath": "/tools/workspace-manager-v2/index.html?gameId=Asteroids",
1313
"workspaceManagerOptional": true
14-
},
15-
"objectVectorRuntime": {
16-
"objectIds": {
17-
"ship": "object.asteroids.ship",
18-
"asteroidLarge": "object.asteroids.large-asteroid",
19-
"asteroidMedium": "object.asteroids.medium-asteroid",
20-
"asteroidSmall": "object.asteroids.small-asteroid",
21-
"ufoLarge": "object.asteroids.large-ufo",
22-
"ufoSmall": "object.asteroids.small-ufo"
23-
}
2414
}
2515
},
2616
"workspace": {

games/Asteroids/game/AsteroidsGameScene.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { createAsteroidGeometryProfilesFromObjectVectorAssets } from './asteroid
1717
import {
1818
ASTEROID_SIZE_RUNTIME_ROLES,
1919
runtimeObjectRoleOptions,
20-
validateAsteroidsRuntimeObjectBindings
20+
validateAsteroidsRuntimeObjectRoles
2121
} from './asteroidsObjectVectorRoles.js';
2222
import {
2323
ASTEROIDS_GAME_OVER_AUTO_EXIT_SECONDS, ASTEROIDS_GAME_OVER_RETURN_MODE
@@ -118,16 +118,15 @@ export default class AsteroidsGameScene extends Scene {
118118
this.devConsoleIntegration = options.devConsoleIntegration || null;
119119
this.objectVectorAssets = options.objectVectorAssets || null;
120120
this.objectVectorRuntime = options.objectVectorRuntime || null;
121-
this.objectVectorRuntimeBindings = this.objectVectorAssets?.runtimeBindings || {};
122-
this.objectVectorRuntimeBindingValidation = this.objectVectorAssets
123-
? validateAsteroidsRuntimeObjectBindings([...this.objectVectorAssets.objectsById.values()], this.objectVectorRuntimeBindings, {
121+
this.objectVectorRuntimeObjectValidation = this.objectVectorAssets
122+
? validateAsteroidsRuntimeObjectRoles([...this.objectVectorAssets.objectsById.values()], {
124123
logger: this.objectVectorRuntime,
125124
})
126125
: { errors: [], objectsByRole: {}, ok: false, warnings: [] };
127-
if (this.objectVectorAssets && !this.objectVectorRuntimeBindingValidation.ok) {
128-
const message = validationFailureMessage(this.objectVectorRuntimeBindingValidation);
126+
if (this.objectVectorAssets && !this.objectVectorRuntimeObjectValidation.ok) {
127+
const message = validationFailureMessage(this.objectVectorRuntimeObjectValidation);
129128
this.objectVectorRuntime?.log?.('FAIL', message, {
130-
errors: this.objectVectorRuntimeBindingValidation.errors,
129+
errors: this.objectVectorRuntimeObjectValidation.errors,
131130
});
132131
console.error(message);
133132
throw new Error(message);
@@ -869,7 +868,7 @@ export default class AsteroidsGameScene extends Scene {
869868
}
870869

871870
objectVectorRoleOptions(roleId) {
872-
return runtimeObjectRoleOptions(roleId, this.objectVectorRuntimeBindings);
871+
return runtimeObjectRoleOptions(roleId);
873872
}
874873

875874
drawObjectVectorAsset(renderer, renderKey, options) {
@@ -907,7 +906,7 @@ export default class AsteroidsGameScene extends Scene {
907906
assetCount: this.objectVectorAssets?.objectsById?.size || 0,
908907
loaded: Boolean(this.objectVectorAssets),
909908
objectCount: this.objectVectorAssets?.objectsById?.size || 0,
910-
runtimeBindingsValid: Boolean(this.objectVectorRuntimeBindingValidation?.ok),
909+
runtimeObjectsValid: Boolean(this.objectVectorRuntimeObjectValidation?.ok),
911910
renderCounts: { ...this.objectVectorRenderCounts },
912911
};
913912
} catch {

games/Asteroids/game/asteroidObjectGeometry.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ const ASTEROID_SIZE_LABELS = Object.freeze({
99
3: 'LRG',
1010
});
1111

12-
function asRecord(value) {
13-
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
14-
}
15-
1612
function asArray(value) {
1713
return Array.isArray(value) ? value : [];
1814
}
@@ -88,15 +84,12 @@ function createProfilesFromObjects(objects, options = {}) {
8884
}
8985

9086
export function createAsteroidGeometryProfilesFromObjectVectorPayload(payload, options = {}) {
91-
return createProfilesFromObjects(asRecord(payload).objects, options);
87+
return createProfilesFromObjects(payload?.objects, options);
9288
}
9389

9490
export function createAsteroidGeometryProfilesFromObjectVectorAssets(assetSet, options = {}) {
9591
if (assetSet?.objectsById instanceof Map) {
96-
return createProfilesFromObjects([...assetSet.objectsById.values()], {
97-
runtimeBindings: asRecord(assetSet.runtimeBindings),
98-
...options,
99-
});
92+
return createProfilesFromObjects([...assetSet.objectsById.values()], options);
10093
}
10194
return createAsteroidGeometryProfilesFromObjectVectorPayload(assetSet?.payload, options);
10295
}

games/Asteroids/game/asteroidsObjectVectorRoles.js

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
export const ASTEROIDS_RUNTIME_OBJECT_ROLES = Object.freeze({
22
ship: Object.freeze({
33
label: 'Ship',
4+
objectId: 'object.asteroids.ship',
45
}),
56
asteroidLarge: Object.freeze({
67
label: 'Large Asteroid',
8+
objectId: 'object.asteroids.large-asteroid',
79
size: 3,
810
}),
911
asteroidMedium: Object.freeze({
1012
label: 'Medium Asteroid',
13+
objectId: 'object.asteroids.medium-asteroid',
1114
size: 2,
1215
}),
1316
asteroidSmall: Object.freeze({
1417
label: 'Small Asteroid',
18+
objectId: 'object.asteroids.small-asteroid',
1519
size: 1,
1620
}),
1721
ufoLarge: Object.freeze({
1822
label: 'Large UFO',
23+
objectId: 'object.asteroids.large-ufo',
1924
}),
2025
ufoSmall: Object.freeze({
2126
label: 'Small UFO',
27+
objectId: 'object.asteroids.small-ufo',
2228
}),
2329
});
2430

@@ -36,10 +42,6 @@ function asArray(value) {
3642
return Array.isArray(value) ? value : [];
3743
}
3844

39-
function asRecord(value) {
40-
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
41-
}
42-
4345
function normalizeString(value) {
4446
return String(value || '').trim();
4547
}
@@ -73,25 +75,21 @@ function logResolution(logger, level, message, details = {}) {
7375
logger[method]?.(message, details);
7476
}
7577

76-
export function runtimeObjectRoleOptions(roleId, runtimeBindings = {}) {
78+
export function runtimeObjectRoleOptions(roleId) {
7779
const role = ASTEROIDS_RUNTIME_OBJECT_ROLES[roleId] || null;
7880
if (!role) {
7981
return {
8082
objectId: '',
81-
requireManifestBinding: true,
8283
runtimeRole: roleId,
8384
};
8485
}
85-
const bindings = asRecord(runtimeBindings);
8686
return {
87-
objectId: normalizeString(bindings[roleId]),
88-
requireManifestBinding: true,
87+
objectId: normalizeString(role.objectId),
8988
runtimeRole: roleId,
9089
};
9190
}
9291

9392
export function resolveAsteroidsObjectVectorRole(objects, roleId, {
94-
runtimeBindings = {},
9593
logger = null,
9694
} = {}) {
9795
const role = ASTEROIDS_RUNTIME_OBJECT_ROLES[roleId] || null;
@@ -101,9 +99,9 @@ export function resolveAsteroidsObjectVectorRole(objects, roleId, {
10199
return null;
102100
}
103101

104-
const explicitObjectId = normalizeString(asRecord(runtimeBindings)[roleId]);
105-
const explicitObject = explicitObjectId
106-
? objectList.find((object) => object?.id === explicitObjectId) || null
102+
const targetObjectId = normalizeString(role.objectId);
103+
const targetObject = targetObjectId
104+
? objectList.find((object) => object?.id === targetObjectId) || null
107105
: null;
108106
const candidates = objectList
109107
.map((object, index) => ({
@@ -113,11 +111,11 @@ export function resolveAsteroidsObjectVectorRole(objects, roleId, {
113111
}))
114112
.filter((candidate) => candidate.object);
115113

116-
if (!explicitObjectId) {
114+
if (!targetObjectId) {
117115
logResolution(
118116
logger,
119117
'FAIL',
120-
`Asteroids Object Vector runtime role ${roleId} is missing required manifest binding game.gameData.objectVectorRuntime.objectIds.${roleId}.`,
118+
`Asteroids Object Vector runtime role ${roleId} is missing its required object ID contract.`,
121119
{
122120
candidates: candidates.map(candidateLabel),
123121
objectCount: objectList.length,
@@ -126,37 +124,37 @@ export function resolveAsteroidsObjectVectorRole(objects, roleId, {
126124
return null;
127125
}
128126

129-
if (!explicitObject) {
127+
if (!targetObject) {
130128
logResolution(
131129
logger,
132130
'FAIL',
133-
`Asteroids Object Vector runtime role ${roleId} manifest binding ${explicitObjectId} does not match any Object Vector object in game.manifest.json.`,
131+
`Asteroids Object Vector runtime role ${roleId} requires object ${targetObjectId} in game.workspace.tools.object-vector-studio-v2.objects.`,
134132
{
135133
candidates: candidates.map(candidateLabel),
136-
explicitObjectId,
137134
objectCount: objectList.length,
135+
targetObjectId,
138136
}
139137
);
140138
return null;
141139
}
142140

143-
if (oldObjectSignal(explicitObject)) {
141+
if (oldObjectSignal(targetObject)) {
144142
logResolution(
145143
logger,
146144
'FAIL',
147-
`Asteroids Object Vector runtime role ${roleId} manifest binding ${explicitObjectId} points to an old/legacy object; update the manifest binding to the active object.`,
145+
`Asteroids Object Vector runtime role ${roleId} object ${targetObjectId} is marked old/legacy; keep runtime object IDs on active Object Vector objects.`,
148146
{
149147
candidates: candidates.map(candidateLabel),
150-
explicitObjectId,
148+
targetObjectId,
151149
}
152150
);
153151
return null;
154152
}
155153

156-
return explicitObject;
154+
return targetObject;
157155
}
158156

159-
export function validateAsteroidsRuntimeObjectBindings(objects, runtimeBindings = {}, {
157+
export function validateAsteroidsRuntimeObjectRoles(objects, {
160158
logger = null,
161159
} = {}) {
162160
const errors = [];
@@ -177,7 +175,6 @@ export function validateAsteroidsRuntimeObjectBindings(objects, runtimeBindings
177175
ASTEROIDS_REQUIRED_RUNTIME_OBJECT_ROLE_IDS.forEach((roleId) => {
178176
const object = resolveAsteroidsObjectVectorRole(objects, roleId, {
179177
logger: collectingLogger,
180-
runtimeBindings,
181178
});
182179
if (object) {
183180
objectsByRole[roleId] = object;

0 commit comments

Comments
 (0)