Skip to content

Commit 3d47e97

Browse files
author
DavidQ
committed
Engine usage enforcement completion (Level 18 Track A)
BUILD_PR_LEVEL_18_1_ENGINE_USAGE_ENFORCEMENT_COMPLETION
1 parent 76b4509 commit 3d47e97

20 files changed

Lines changed: 176 additions & 213 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
MODEL: GPT-5.3-codex
22
REASONING: high
33

4-
Execute BUILD_PR_LEVEL_19_25_ENGINE_TOOL_BOUNDARY_FINAL_CONFIRMATION:
4+
Execute BUILD_PR_LEVEL_18_1_ENGINE_USAGE_ENFORCEMENT_COMPLETION:
55

6-
1. Re-run boundary validation across src/engine
7-
2. Confirm no tool-specific logic remains
8-
3. Cross-check previous violation reports
9-
4. Produce final confirmation report
10-
5. If clean:
11-
- update roadmap status [ ] -> [x] for Track E final item
12-
6. Do not modify any other roadmap text
6+
- scan games/
7+
- detect non-engine implementations
8+
- migrate to engine/shared
9+
- re-run validation
10+
- output report to docs/dev/reports

docs/dev/COMMIT_COMMENT.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
Final confirmation of engine/tool boundary integrity (Phase 19 closeout)
1+
Engine usage enforcement completion (Level 18 Track A)
22

3-
BUILD_PR_LEVEL_19_25_ENGINE_TOOL_BOUNDARY_FINAL_CONFIRMATION
3+
BUILD_PR_LEVEL_18_1_ENGINE_USAGE_ENFORCEMENT_COMPLETION
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# BUILD_PR_LEVEL_18_1_ENGINE_USAGE_ENFORCEMENT_COMPLETION Report
2+
3+
Date: 2026-04-17
4+
Scope: `games/` engine-usage enforcement completion (scan -> migrate duplicated local logic -> re-validate).
5+
6+
## Scan Method
7+
1. Scanned `games/` for local helper/function duplication and non-engine reimplementation patterns.
8+
2. Compared duplicates against stable reusable surfaces in `src/shared`/`src/engine`.
9+
3. Migrated only clearly duplicated local logic to shared utilities.
10+
11+
## Violations Detected (Pre-Migration)
12+
Two concrete duplicate clusters in `games/`:
13+
14+
1. Repeated cardinal-direction reverse logic (`opposite`) in:
15+
- `games/PacmanLite/game/PacmanLiteNavigator.js`
16+
- `games/PacmanFullAI/game/PacmanFullAINavigator.js`
17+
- `games/PacmanFullAI/game/PacmanFullAIWorld.js`
18+
19+
2. Repeated character-count overlay text wrapping logic across scenes:
20+
- `games/breakout/game/BreakoutScene.js`
21+
- `games/bouncing-ball/game/BouncingBallScene.js`
22+
- `games/MultiBallChaos/game/MultiBallChaosScene.js`
23+
- `games/Gravity/game/GravityScene.js`
24+
- `games/Thruster/game/ThrusterScene.js`
25+
- `games/PaddleIntercept/game/PaddleInterceptScene.js`
26+
- `games/pong/game/PongScene.js`
27+
28+
## Migration Applied
29+
### New shared utilities
30+
- Added `src/shared/utils/directionUtils.js`
31+
- `oppositeCardinalDirection(direction)`
32+
- Added `src/shared/utils/textWrapUtils.js`
33+
- `wrapTextByCharacterCount(text, maxCharacters, { preserveParagraphs })`
34+
- Exported both from `src/shared/utils/index.js`
35+
36+
### Game rewiring
37+
- Pacman navigators/world now use `oppositeCardinalDirection` from shared utils.
38+
- Scene overlay wrappers now use `wrapTextByCharacterCount` from shared utils.
39+
40+
## Re-Validation
41+
### Duplicate re-scan
42+
- Command: duplicate-function scan script over `games/`.
43+
- Result: `DUPLICATE_FUNCTION_CLUSTERS = 0`
44+
45+
### Targeted runtime tests
46+
Executed and passed:
47+
- `BreakoutValidation`
48+
- `BouncingBallValidation`
49+
- `MultiBallChaosValidation`
50+
- `PongValidation`
51+
- `ThrusterValidation`
52+
- `PaddleInterceptValidation`
53+
- `GravityValidation`
54+
- `PacmanLiteValidation`
55+
- `PacmanLiteWorld`
56+
- `PacmanFullAIValidation`
57+
- `PacmanFullAIWorld`
58+
59+
Result: `11/11 targeted tests passed`
60+
61+
## Roadmap Status Update
62+
Execution-backed status update applied:
63+
- `docs/dev/roadmaps/MASTER_ROADMAP_HIGH_LEVEL.md`
64+
- Level 18 Track A: `verify all games use engine systems` changed `[.] -> [x]`
65+
66+
No other roadmap text was modified.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Docs-only final confirmation gate
1+
Docs-only enforcement PR
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
[ ] validation re-run
2-
[ ] zero violations
3-
[ ] roadmap status updated
1+
[ ] games use engine
2+
[ ] no local logic
3+
[ ] validation pass

docs/dev/roadmaps/MASTER_ROADMAP_HIGH_LEVEL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@
723723

724724
### Track A � Engine Usage Enforcement
725725
- [x] verify all `samples/` use engine systems (no local reimplementation)
726-
- [.] verify all `games/` use engine systems
726+
- [x] verify all `games/` use engine systems
727727
- [x] migrate any local logic into engine/shared where appropriate
728728
- [ ] remove sample-specific logic from engine paths
729729

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# BUILD_PR_LEVEL_18_1_ENGINE_USAGE_ENFORCEMENT_COMPLETION
2+
3+
## Purpose
4+
Advance Track A of Level 18 by completing verification that all games use engine systems.
5+
6+
## Scope
7+
- validation + enforcement planning
8+
- docs-only
9+
- no implementation authored here
10+
11+
## Codex Responsibilities
12+
- scan games/ for non-engine logic usage
13+
- identify violations
14+
- migrate logic to engine/shared where required
15+
- re-validate usage
16+
17+
## Acceptance
18+
- all games use engine systems
19+
- no local reimplementation remains
20+
- report produced

games/Gravity/game/GravityScene.js

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Scene } from '/src/engine/scene/index.js';
88
import GravityAudio from './GravityAudio.js';
99
import GravityInputController from './GravityInputController.js';
1010
import GravityWorld from './GravityWorld.js';
11+
import { wrapTextByCharacterCount } from '/src/shared/utils/index.js';
1112

1213
const VIEW = {
1314
width: 960,
@@ -25,28 +26,6 @@ const COLORS = {
2526
gravity: '#f59e0b',
2627
};
2728

28-
function wrapText(text, maxCharacters = 40) {
29-
const words = String(text ?? '').split(/\s+/).filter(Boolean);
30-
const lines = [];
31-
let current = '';
32-
33-
words.forEach((word) => {
34-
const next = current ? `${current} ${word}` : word;
35-
if (next.length > maxCharacters && current) {
36-
lines.push(current);
37-
current = word;
38-
return;
39-
}
40-
current = next;
41-
});
42-
43-
if (current) {
44-
lines.push(current);
45-
}
46-
47-
return lines;
48-
}
49-
5029
export default class GravityScene extends Scene {
5130
constructor() {
5231
super();
@@ -219,7 +198,7 @@ export default class GravityScene extends Scene {
219198
textBaseline: 'top',
220199
});
221200

222-
wrapText(copy.body).forEach((line, index) => {
201+
wrapTextByCharacterCount(copy.body, 40).forEach((line, index) => {
223202
renderer.drawText(line, VIEW.width / 2, 336 + (index * 24), {
224203
color: COLORS.muted,
225204
font: '18px monospace',

games/MultiBallChaos/game/MultiBallChaosScene.js

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Scene } from '/src/engine/scene/index.js';
88
import MultiBallChaosAudio from './MultiBallChaosAudio.js';
99
import MultiBallChaosInputController from './MultiBallChaosInputController.js';
1010
import MultiBallChaosWorld from './MultiBallChaosWorld.js';
11+
import { wrapTextByCharacterCount } from '/src/shared/utils/index.js';
1112

1213
const VIEW = {
1314
width: 960,
@@ -25,28 +26,6 @@ const COLORS = {
2526
lane: '#142033',
2627
};
2728

28-
function wrapText(text, maxCharacters = 38) {
29-
const words = String(text ?? '').split(/\s+/).filter(Boolean);
30-
const lines = [];
31-
let current = '';
32-
33-
words.forEach((word) => {
34-
const next = current ? `${current} ${word}` : word;
35-
if (next.length > maxCharacters && current) {
36-
lines.push(current);
37-
current = word;
38-
return;
39-
}
40-
current = next;
41-
});
42-
43-
if (current) {
44-
lines.push(current);
45-
}
46-
47-
return lines;
48-
}
49-
5029
export default class MultiBallChaosScene extends Scene {
5130
constructor() {
5231
super();
@@ -192,7 +171,7 @@ export default class MultiBallChaosScene extends Scene {
192171
font: '18px monospace',
193172
textBaseline: 'top',
194173
});
195-
wrapText(preset.description, 24).forEach((line, index) => {
174+
wrapTextByCharacterCount(preset.description, 24).forEach((line, index) => {
196175
renderer.drawText(line, sidebarX + 18, 194 + (index * 20), {
197176
color: COLORS.muted,
198177
font: '15px monospace',
@@ -255,7 +234,7 @@ export default class MultiBallChaosScene extends Scene {
255234
textBaseline: 'top',
256235
});
257236

258-
wrapText(copy.body, 54).forEach((line, index) => {
237+
wrapTextByCharacterCount(copy.body, 54).forEach((line, index) => {
259238
renderer.drawText(line, VIEW.width / 2, 336 + (index * 24), {
260239
color: COLORS.muted,
261240
font: '18px monospace',

games/PacmanFullAI/game/PacmanFullAINavigator.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,15 @@ David Quesenberry
44
03/25/2026
55
PacmanFullAINavigator.js
66
*/
7+
import { oppositeCardinalDirection as opposite } from '/src/shared/utils/index.js';
8+
79
const DIRS = Object.freeze({
810
left: { x: -1, y: 0 },
911
right: { x: 1, y: 0 },
1012
up: { x: 0, y: -1 },
1113
down: { x: 0, y: 1 },
1214
});
1315

14-
function opposite(direction) {
15-
if (direction === 'left') return 'right';
16-
if (direction === 'right') return 'left';
17-
if (direction === 'up') return 'down';
18-
if (direction === 'down') return 'up';
19-
return null;
20-
}
21-
2216
function getLegalDirections(grid, tileX, tileY) {
2317
return Object.keys(DIRS).filter((name) => {
2418
const v = DIRS[name];

0 commit comments

Comments
 (0)