Skip to content

Commit ec256a8

Browse files
author
DavidQ
committed
Multi-game validation pass for bezel/background system
BUILD_PR_LEVEL_10_24_MULTI_GAME_VALIDATION_PASS
1 parent d0a366b commit ec256a8

7 files changed

Lines changed: 165 additions & 48 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,25 @@
1+
12
MODEL: GPT-5.4
23
REASONING: high
34

45
COMMAND:
5-
Create `BUILD_PR_LEVEL_10_23_RESTORE_MASTER_ROADMAP_STATUS_ONLY`.
6-
7-
1. Restore this exact file from git history:
8-
`docs/dev/roadmaps/MASTER_ROADMAP_HIGH_LEVEL.md`
9-
10-
2. Use the last known good FULL version from repo history.
11-
- Do NOT reconstruct manually
12-
- Do NOT use a shortened replacement
13-
- Do NOT write a fresh roadmap
14-
- Do NOT accept any restore under 600 lines
6+
Create `BUILD_PR_LEVEL_10_24_MULTI_GAME_VALIDATION_PASS`
157

16-
3. After restore, apply ONLY status-marker updates.
17-
Allowed changes:
18-
- `[ ]`
19-
- `[x]`
20-
- `[.]`
8+
1. Validate across:
9+
- Asteroids
10+
- games/_template
11+
- another sample
2112

22-
4. Forbidden changes:
23-
- no text rewrites
24-
- no formatting changes
25-
- no new sections
26-
- no deleted sections
27-
- no line collapsing
28-
- no summary replacement
13+
2. Verify:
14+
- bezel behavior
15+
- background behavior
16+
- override file creation
2917

30-
5. Validation is REQUIRED:
31-
- report the git source used for restore
32-
- report restored line count
33-
- fail the task if the file is not 600+ lines before status-only edits
18+
3. Fix only real issues (minimal changes)
3419

35-
6. Final packaging step is REQUIRED:
36-
- package ALL changed files into this exact repo-structured ZIP:
37-
`<project folder>/tmp/BUILD_PR_LEVEL_10_23_RESTORE_MASTER_ROADMAP_STATUS_ONLY.zip`
20+
4. Package:
21+
<project folder>/tmp/BUILD_PR_LEVEL_10_24_MULTI_GAME_VALIDATION_PASS.zip
3822

39-
Hard rules:
40-
- exact historical restore
41-
- status-only update after restore
42-
- no unrelated repo changes
43-
- no missing ZIP
23+
Rules:
24+
- no scope expansion
25+
- no unnecessary changes

docs/dev/COMMIT_COMMENT.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Restore full MASTER_ROADMAP_HIGH_LEVEL from history and update status only
2-
BUILD_PR_LEVEL_10_23_RESTORE_MASTER_ROADMAP_STATUS_ONLY
1+
Multi-game validation pass for bezel/background system
2+
BUILD_PR_LEVEL_10_24_MULTI_GAME_VALIDATION_PASS

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_24_MULTI_GAME_VALIDATION_PASS
1+
BUILD_PR_LEVEL_10_25_POLISH_AND_EDGE_CASES
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
- Reissued roadmap restore with strict historical-restore requirement
2-
- Added hard 600+ line guard
3-
- Limited post-restore edits to status markers only
1+
- Multi-game validation
2+
- Confirmed shared behavior
3+
- Minimal fixes if needed
Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
- Restored file came from git history
2-
- Restored file is the full correct roadmap
3-
- Restored file is 600+ lines
4-
- Only status markers changed after restore
5-
- No roadmap text was rewritten
6-
- No sections were added or removed
7-
- Output ZIP created at:
8-
<project folder>/tmp/BUILD_PR_LEVEL_10_23_RESTORE_MASTER_ROADMAP_STATUS_ONLY.zip
1+
2+
- Asteroids passes
3+
- Template passes
4+
- Another game passes
5+
- Bezel works
6+
- Background works
7+
- Override file works
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
# BUILD_PR_LEVEL_10_24_MULTI_GAME_VALIDATION_PASS
3+
4+
## Purpose
5+
Validate bezel/background system across multiple games and template.
6+
7+
## Scope
8+
- Asteroids (reference)
9+
- games/_template
10+
- at least one additional sample game
11+
12+
## Validation Areas
13+
14+
### A. Bezel
15+
- loads correctly
16+
- no path duplication
17+
- fullscreen only
18+
- visible on screen
19+
- transparency fit works
20+
- stretch override works
21+
22+
### B. Background
23+
- gameplay only
24+
- after clear
25+
- before world/starfield
26+
- visible
27+
28+
### C. Override File
29+
- auto-created when missing
30+
- not overwritten
31+
32+
### D. Template
33+
- new game inherits behavior automatically
34+
35+
## Fix Rule
36+
- only minimal surgical fixes allowed
37+
38+
## Packaging
39+
<project folder>/tmp/BUILD_PR_LEVEL_10_24_MULTI_GAME_VALIDATION_PASS.zip
40+
41+
## Implementation Delta
42+
- Extended focused multi-game validation in `tests/core/BackgroundImageAndFullscreenBezel.test.mjs` with `SpaceInvaders` coverage to satisfy the third target without scope expansion.
43+
- Added checks for additional-game behavior:
44+
- background no-op in gameplay when `background.png` is missing
45+
- bezel no-op in fullscreen when `bezel.png` is missing
46+
- no duplicated bezel path resolution
47+
- startup/detection-based override creation for `games/SpaceInvaders/assets/images/bezel.stretch.override.json`
48+
- No runtime/engine behavior changes were required because validation passed after adding cross-game coverage.
49+
50+
## Validation Evidence (2026-04-14)
51+
- `node --check tests/core/BackgroundImageAndFullscreenBezel.test.mjs` PASS
52+
- `node --check tests/games/AsteroidsPresentation.test.mjs` PASS
53+
- `node --check tests/games/SpaceInvadersScene.test.mjs` PASS
54+
- `node --check tests/tools/GamesTemplateContractEnforcement.test.mjs` PASS
55+
- `BackgroundImageAndFullscreenBezel` focused validation PASS
56+
- Asteroids bezel/background behavior
57+
- `_template` override auto-create + non-overwrite
58+
- SpaceInvaders sample-game bezel/background + override creation path
59+
- `AsteroidsPresentation` regression PASS
60+
- `SpaceInvadersScene` regression PASS
61+
- `GamesTemplateContractEnforcement` PASS

tests/core/BackgroundImageAndFullscreenBezel.test.mjs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,39 @@ function testNoOpWhenBackgroundMissing() {
234234
assert.equal(order.length, 0);
235235
}
236236

237+
function testSampleGameBackgroundAndBezelNoOpWhenMissing() {
238+
const documentRef = createDocumentStub("/games/SpaceInvaders/index.html");
239+
const paths = resolveGameImageConventionPaths({ documentRef });
240+
assert.equal(paths.backgroundPath, "games/SpaceInvaders/assets/images/background.png");
241+
assert.equal(paths.bezelPath, "games/SpaceInvaders/assets/images/bezel.png");
242+
243+
const backgroundLayer = new backgroundImage({
244+
documentRef,
245+
imageFactory: createImageFactory(new Set())
246+
});
247+
const backgroundOrder = [];
248+
const backgroundResult = backgroundLayer.render(createRendererSpy(backgroundOrder), {
249+
scene: { session: { mode: "playing" } }
250+
});
251+
assert.equal(backgroundResult.drawn, false);
252+
assert.equal(backgroundResult.path, "games/SpaceInvaders/assets/images/background.png");
253+
assert.equal(backgroundOrder.length, 0);
254+
255+
const host = createElement("div", documentRef);
256+
const canvas = createElement("canvas", documentRef);
257+
host.appendChild(canvas);
258+
documentRef.body.appendChild(host);
259+
260+
const bezel = new fullscreenBezel({ canvas, documentRef });
261+
bezel.attach();
262+
assert.equal(bezel.element.src, "/games/SpaceInvaders/assets/images/bezel.png");
263+
assert.equal(bezel.element.src.includes("/games/SpaceInvaders/games/SpaceInvaders/"), false);
264+
bezel.element.onerror?.();
265+
const bezelResult = bezel.sync({ fullscreenActive: true, fullscreenElement: host });
266+
assert.equal(bezelResult.visible, false);
267+
assert.equal(bezel.element.style.display, "none");
268+
}
269+
237270
function testFullscreenBezelVisibilityAndHtmlAttachment() {
238271
const documentRef = createDocumentStub();
239272
const host = createElement("div", documentRef);
@@ -548,6 +581,46 @@ async function testBezelDetectionDoesNotOverwriteExistingStretchConfig() {
548581
}
549582
}
550583

584+
async function testSampleGameBezelDetectionCreatesStretchConfig() {
585+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "bezel-detected-spaceinvaders-config-"));
586+
const documentRef = createDocumentStub("/games/SpaceInvaders/index.html");
587+
const host = createElement("div", documentRef);
588+
const canvas = createElement("canvas", documentRef);
589+
canvas.width = 960;
590+
canvas.height = 720;
591+
host.appendChild(canvas);
592+
documentRef.body.appendChild(host);
593+
594+
try {
595+
const bezel = new fullscreenBezel({
596+
canvas,
597+
documentRef,
598+
stretchConfigProvider(configPath) {
599+
return ensureBezelStretchConfigFile(configPath, {
600+
cwd: tempRoot,
601+
fsModule: fs,
602+
pathModule: path
603+
});
604+
}
605+
});
606+
607+
bezel.attach();
608+
bezel.element.naturalWidth = 1920;
609+
bezel.element.naturalHeight = 1080;
610+
bezel.element.onload?.();
611+
if (bezel.stretchConfigPromise) {
612+
await bezel.stretchConfigPromise;
613+
}
614+
615+
const createdPath = path.resolve(tempRoot, "games/SpaceInvaders/assets/images/bezel.stretch.override.json");
616+
const saved = JSON.parse(await fs.readFile(createdPath, "utf8"));
617+
assert.deepEqual(saved, { uniformEdgeStretchPx: 0 });
618+
assert.equal(bezel.getState().stretchConfigPath, "games/SpaceInvaders/assets/images/bezel.stretch.override.json");
619+
} finally {
620+
await fs.rm(tempRoot, { recursive: true, force: true });
621+
}
622+
}
623+
551624
function testEngineRuntimeIntegration() {
552625
const animationFrame = createAnimationFrameStub();
553626
const originalDocument = globalThis.document;
@@ -685,6 +758,7 @@ export async function run() {
685758
testBackgroundGameplayGatingAndOrder();
686759
testGameImageConventionsAreGameAgnostic();
687760
testNoOpWhenBackgroundMissing();
761+
testSampleGameBackgroundAndBezelNoOpWhenMissing();
688762
testFullscreenBezelVisibilityAndHtmlAttachment();
689763
testNoOpWhenBezelMissing();
690764
testTransparentWindowDetectionAndAspectFit();
@@ -693,5 +767,6 @@ export async function run() {
693767
await testBezelStretchConfigAutoCreate();
694768
await testBezelDetectionTriggersStretchConfigAutoCreate();
695769
await testBezelDetectionDoesNotOverwriteExistingStretchConfig();
770+
await testSampleGameBezelDetectionCreatesStretchConfig();
696771
testEngineRuntimeIntegration();
697772
}

0 commit comments

Comments
 (0)