Skip to content

Commit e57a1b0

Browse files
committed
Merge PR_26177_ALFA_061-game-configuration-foundation
# Conflicts: # tests/playwright/tools/GameConfigurationApiBehavior.spec.mjs # tests/playwright/tools/GameConfigurationApiDb.spec.mjs # tests/playwright/tools/GameConfigurationMockRepository.spec.mjs
2 parents fcec3ab + 0d216f6 commit e57a1b0

15 files changed

Lines changed: 1404 additions & 291 deletions

assets/toolbox/game-configuration/js/index.js

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,41 @@ const elements = {
3333
form: document.querySelector("[data-game-configuration-form]"),
3434
formCard: document.querySelector("[data-game-configuration-form-card]"),
3535
gameBasics: document.querySelector("[data-game-configuration-game-basics]"),
36+
gameDetails: document.querySelector("[data-game-configuration-game-details]"),
37+
gameName: document.querySelector("[data-game-configuration-game-name]"),
3638
gameRules: document.querySelector("[data-game-configuration-game-rules]"),
39+
gameType: document.querySelector("[data-game-configuration-game-type]"),
3740
handoffContext: document.querySelector("[data-game-configuration-handoff-context]"),
3841
handoffOverlay: document.querySelector("[data-game-configuration-handoff-overlay]"),
3942
missingItems: document.querySelector("[data-game-configuration-output-missing]"),
4043
objectSetup: document.querySelector("[data-game-configuration-object-setup]"),
4144
outputCapability: document.querySelector("[data-game-configuration-output-capability]"),
45+
outputDetails: document.querySelector("[data-game-configuration-output-details]"),
46+
outputGameType: document.querySelector("[data-game-configuration-output-game-type]"),
47+
outputName: document.querySelector("[data-game-configuration-output-name]"),
4248
outputNextStep: document.querySelector("[data-game-configuration-output-next-step]"),
49+
outputPlatforms: document.querySelector("[data-game-configuration-output-platforms]"),
4350
outputPlayerMode: document.querySelector("[data-game-configuration-output-player-mode]"),
4451
outputReadiness: document.querySelector("[data-game-configuration-output-readiness]"),
52+
outputResolution: document.querySelector("[data-game-configuration-output-resolution]"),
53+
outputStartup: document.querySelector("[data-game-configuration-output-startup]"),
4554
outputSummary: document.querySelector("[data-game-configuration-output-summary]"),
55+
outputVersion: document.querySelector("[data-game-configuration-output-version]"),
56+
outputVisibility: document.querySelector("[data-game-configuration-output-visibility]"),
57+
platforms: document.querySelector("[data-game-configuration-platforms]"),
4658
playerSetup: document.querySelector("[data-game-configuration-player-setup]"),
4759
progressCurrentFocus: document.querySelector("[data-game-configuration-current-focus]"),
4860
progressGame: document.querySelector("[data-game-configuration-game-progress]"),
4961
progressPublishing: document.querySelector("[data-game-configuration-publishing-progress]"),
5062
progressRecommended: document.querySelectorAll("[data-game-configuration-recommended-tool]"),
63+
resolution: document.querySelector("[data-game-configuration-resolution]"),
5164
statusLog: document.querySelector("[data-game-configuration-log]"),
65+
startupSettings: document.querySelector("[data-game-configuration-startup-settings]"),
5266
testReadiness: document.querySelector("[data-game-configuration-test-readiness]"),
5367
validationList: document.querySelector("[data-game-configuration-validation-list]"),
5468
validationOverlay: document.querySelector("[data-game-configuration-validation-overlay]"),
69+
version: document.querySelector("[data-game-configuration-version]"),
70+
visibility: document.querySelector("[data-game-configuration-visibility]"),
5571
worldSetup: document.querySelector("[data-game-configuration-world-setup]")
5672
};
5773

@@ -93,10 +109,16 @@ function readForm() {
93109
return {
94110
audioSetup: elements.audioSetup?.value,
95111
gameBasics: elements.gameBasics?.value,
112+
gameDetails: elements.gameDetails?.value,
96113
gameRules: elements.gameRules?.value,
97114
objectSetup: elements.objectSetup?.value,
115+
platforms: elements.platforms?.value,
98116
playerSetup: elements.playerSetup?.value,
117+
resolution: elements.resolution?.value,
118+
startupSettings: elements.startupSettings?.value,
99119
testReadiness: elements.testReadiness?.value,
120+
version: elements.version?.value,
121+
visibility: elements.visibility?.value,
100122
worldSetup: elements.worldSetup?.value
101123
};
102124
}
@@ -108,6 +130,15 @@ function clearForm() {
108130
input.value = "";
109131
}
110132
});
133+
if (elements.version) {
134+
elements.version.value = "";
135+
}
136+
if (elements.resolution) {
137+
elements.resolution.value = "1280x720";
138+
}
139+
if (elements.visibility) {
140+
elements.visibility.value = "Private";
141+
}
111142
}
112143

113144
function applyConfigurationToForm(configuration) {
@@ -122,6 +153,15 @@ function applyConfigurationToForm(configuration) {
122153
input.value = configuration[section] || "";
123154
}
124155
});
156+
if (elements.version) {
157+
elements.version.value = configuration.version || "";
158+
}
159+
if (elements.resolution) {
160+
elements.resolution.value = configuration.resolution || "1280x720";
161+
}
162+
if (elements.visibility) {
163+
elements.visibility.value = configuration.visibility || "Private";
164+
}
125165
}
126166

127167
function renderValidation(validation) {
@@ -159,16 +199,36 @@ function renderHandoff(snapshot) {
159199
}
160200
}
161201

202+
function inheritedGameName(snapshot) {
203+
return snapshot.handoff.activeProject?.name || snapshot.handoff.activeGame?.name || "";
204+
}
205+
206+
function inheritedGameType(snapshot) {
207+
return snapshot.handoff.activeProject?.gameType || snapshot.handoff.activeDesign?.gameType || snapshot.handoff.activeProject?.purpose || "";
208+
}
209+
162210
function renderOutput(snapshot) {
163211
const configuration = snapshot.configuration;
164212
const validation = snapshot.validation;
213+
const gameName = configuration?.gameName || inheritedGameName(snapshot);
214+
const gameType = inheritedGameType(snapshot);
165215
const missing = validation.findings.map((finding) => finding.label).join(", ");
166216
const summary = configuration?.gameBasics || "No configuration summary saved yet.";
167217
const activeGame = snapshot.handoff.activeGame || snapshot.handoff.activeProject;
168218
const capability = activeGame?.purpose === "Capability Demo"
169219
? `${activeGame.name} remains a game-owned capability demo.`
170220
: "Standard game configuration.";
171221

222+
setText(elements.gameName, gameName || "From Game Hub");
223+
setText(elements.gameType, gameType || "From Game Hub");
224+
setText(elements.outputName, gameName || "No game name saved yet.");
225+
setText(elements.outputGameType, gameType || "No game type inherited yet.");
226+
setText(elements.outputDetails, configuration?.gameDetails || "No game details saved yet.");
227+
setText(elements.outputVersion, configuration?.version || "No version saved yet.");
228+
setText(elements.outputResolution, configuration?.resolution || "No resolution saved yet.");
229+
setText(elements.outputPlatforms, configuration?.platforms || "No platforms saved yet.");
230+
setText(elements.outputVisibility, configuration?.visibility || "No visibility saved yet.");
231+
setText(elements.outputStartup, configuration?.startupSettings || "No startup settings saved yet.");
172232
setText(elements.outputSummary, summary);
173233
setText(elements.outputPlayerMode, configuration?.playerMode || snapshot.handoff.activeDesign?.playerMode || "1 Player");
174234
setText(elements.outputReadiness, snapshot.progressHandoff.readinessStatus);
@@ -222,7 +282,7 @@ elements.form?.addEventListener("submit", (event) => {
222282

223283
const configuration = repository.updateConfiguration(projectId, readForm());
224284
const nextSnapshot = repository.getSnapshot();
225-
const message = configuration?.status === "Ready"
285+
const message = configuration?.status === "Ready" || nextSnapshot.progressHandoff.readinessStatus === "Ready"
226286
? "Saved Game Configuration as ready. Assets is the recommended next tool."
227287
: `Saved Game Configuration with ${nextSnapshot.validation.findings.length} missing item${nextSnapshot.validation.findings.length === 1 ? "" : "s"}.`;
228288

docs_build/database/ddl/game-configuration.sql

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,44 @@
88
CREATE TABLE IF NOT EXISTS game_configuration_records (
99
key text PRIMARY KEY,
1010
"gameKey" text REFERENCES game_workspace_games(key),
11+
"gameDetails" text,
12+
"version" text,
13+
"resolution" text,
14+
"platforms" text,
15+
"visibility" text,
16+
"startupSettings" text,
1117
"status" text,
1218
"summary" text,
1319
"playerMode" text,
20+
"gameBasics" text,
21+
"gameRules" text,
22+
"playerSetup" text,
23+
"worldSetup" text,
24+
"objectSetup" text,
25+
"audioSetup" text,
26+
"testReadiness" text,
1427
"createdAt" timestamptz NOT NULL DEFAULT now(),
1528
"updatedAt" timestamptz NOT NULL DEFAULT now(),
1629
"createdBy" text NOT NULL REFERENCES users(key),
1730
"updatedBy" text NOT NULL REFERENCES users(key)
1831
);
1932

33+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameDetails" text;
34+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "version" text;
35+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "resolution" text;
36+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "platforms" text;
37+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "visibility" text;
38+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "startupSettings" text;
39+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "summary" text;
40+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "playerMode" text;
41+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameBasics" text;
42+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameRules" text;
43+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "playerSetup" text;
44+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "worldSetup" text;
45+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "objectSetup" text;
46+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "audioSetup" text;
47+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "testReadiness" text;
48+
2049
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_gamekey ON game_configuration_records ("gameKey");
2150
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_createdby ON game_configuration_records ("createdBy");
2251
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_updatedby ON game_configuration_records ("updatedBy");
@@ -36,6 +65,7 @@ ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "testReadiness"
3665
CREATE TABLE IF NOT EXISTS game_configuration_validation_items (
3766
key text PRIMARY KEY,
3867
"gameKey" text REFERENCES game_workspace_games(key),
68+
"section" text,
3969
"label" text,
4070
"status" text,
4171
"action" text,
@@ -45,6 +75,8 @@ CREATE TABLE IF NOT EXISTS game_configuration_validation_items (
4575
"updatedBy" text NOT NULL REFERENCES users(key)
4676
);
4777

78+
ALTER TABLE game_configuration_validation_items ADD COLUMN IF NOT EXISTS "section" text;
79+
4880
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_gamekey ON game_configuration_validation_items ("gameKey");
4981
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_createdby ON game_configuration_validation_items ("createdBy");
5082
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_updatedby ON game_configuration_validation_items ("updatedBy");

docs_build/database/seed/game-configuration.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
"game_configuration_records": [],
99
"game_configuration_validation_items": []
1010
},
11-
"note": "Seed records for this group are intentionally empty until an Admin-owned server API seeds them."
11+
"note": "Game Configuration records are server/API-owned. Browser pages must not seed or generate authoritative configuration records."
1212
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Branch Validation
2+
3+
Generated: 2026-06-26 20:51:40 UTC
4+
5+
- Branch check: PASS - current branch is `PR_26177_ALFA_061-game-configuration-foundation`.
6+
- Scope check: PASS - runtime changes are limited to the stacked Alfa API service/tool pages/tests needed for Tags, Game Design, and Game Configuration DB-backed behavior.
7+
- No-mock check: PASS - `tags-mock-repository.js`, `game-design-mock-repository.js`, and `game-configuration-mock-repository.js` are absent, and the guardrail test fails if they return or are imported.
8+
- Router check: PASS - `local-api-router.mjs` routes Tags, Game Design, and Game Configuration through database-backed API services, not retired mock repositories.
9+
- Architecture check: PASS - targeted tests exercise Browser -> API -> Database persistence and guest write rejection/redirect behavior.
10+
- Validation result: PASS.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Manual Validation Notes
2+
3+
Generated: 2026-06-26 20:51:40 UTC
4+
5+
- Loaded `/toolbox/game-configuration/index.html` with the default valid current-game handoff and confirmed the selected game status shows Demo Game.
6+
- Confirmed Game Name and Game Type render as inherited read-only text, with no editable inputs for those values.
7+
- Confirmed seeded Game Details, Platforms, Startup Settings, Game Basics, Game Rules, and setup fields load for the current game.
8+
- Edited configuration fields, saved through the API, verified `game_configuration_records` rows, reloaded, and confirmed persisted values return.
9+
- Cleared required fields, saved, and confirmed the validation overlay reports missing sections without generic snapshot seeding hiding the invalid state.
10+
- Verified guest browser save redirects to `account/sign-in.html`.
11+
- Verified Tags and Game Design focused lanes still pass after the shared Alfa API service changes.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Report
2+
3+
Generated: 2026-06-26 20:51:40 UTC
4+
Branch: `PR_26177_ALFA_061-game-configuration-foundation`
5+
Base: stacked on `PR_26177_ALFA_060-game-design-foundation`
6+
Current HEAD before packaging: `d0ce8ebda`
7+
8+
## Summary
9+
PR061 completes the Game Configuration foundation as a human-testable Browser -> API -> Database tool. Game Name and Game Type are inherited from the current Game Hub/Game Design context and remain read-only, while configuration-owned fields save through the API, reload from database persistence, and surface Creator-safe readiness guidance.
10+
11+
## Implementation Notes
12+
- Game Configuration uses the shared Alfa API service in `src/dev-runtime/toolbox-api/alfa-tool-services.mjs`; the deleted Game Configuration mock repository is not routed or imported.
13+
- The normal valid-handoff bootstrap prepares a ready starter configuration only when the current game has no complete usable configuration. Explicit invalid saves remain visible and are not silently repaired by later snapshots.
14+
- `local-api-router.mjs` routes Tags, Game Design, and Game Configuration to the shared database-backed service instead of retired mock repositories.
15+
- Provider contract stubs include the Game Design section/demo tables required by the shared service contract.
16+
- No scoped Tags, Game Crew, Game Design, or Game Configuration mock repository source of truth is present in this branch.
17+
18+
## Validation
19+
- PASS - `node --check src/dev-runtime/toolbox-api/alfa-tool-services.mjs`
20+
- PASS - `node --check src/dev-runtime/server/local-api-router.mjs`
21+
- PASS - `node --check assets/toolbox/tags/js/index.js`
22+
- PASS - `node --check assets/toolbox/game-design/js/index.js`
23+
- PASS - `node --check assets/toolbox/game-configuration/js/index.js`
24+
- PASS - `node --test tests/dev-runtime/DevRuntimeBoundary.test.mjs` (5 passed)
25+
- PASS - `npx playwright test tests/playwright/tools/TagsTool.spec.mjs --project=playwright --workers=1 --reporter=line` (4 passed)
26+
- PASS - `npx playwright test tests/playwright/tools/GameDesignApiBehavior.spec.mjs --project=playwright --workers=1 --reporter=line` (6 passed)
27+
- PASS - `npx playwright test tests/playwright/tools/GameConfigurationApiBehavior.spec.mjs --project=playwright --workers=1 --reporter=line` (6 passed)
28+
- PASS - `git diff --check` (line-ending notices only)
29+
30+
## Packaging
31+
- Repo-structured ZIP: `tmp/PR_26177_ALFA_061-game-configuration-foundation_delta.zip`
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Requirement Checklist
2+
3+
Generated: 2026-06-26 20:51:40 UTC
4+
5+
- PASS - Center title is Configuration; Configuration Workspace wording is absent.
6+
- PASS - Game Name comes from Game Hub and renders read-only.
7+
- PASS - Game Type comes from the Game Hub/Game Design handoff and renders read-only.
8+
- PASS - Configuration owns editable settings only after project creation.
9+
- PASS - Tool loads seeded current-game configuration data through the API/database path.
10+
- PASS - Signed-in Creator can edit settings, save, refresh, and see persisted values.
11+
- PASS - Invalid saves remain visible as missing-section validation and are not silently repaired by generic snapshots.
12+
- PASS - Guest browser save redirects to `account/sign-in.html`; direct guest API save returns 401.
13+
- PASS - Tags, Game Design, and Game Configuration do not route through retired mock repositories.
14+
- PASS - Guardrail test fails if `tags-mock-repository.js`, `game-design-mock-repository.js`, or `game-configuration-mock-repository.js` exists or is imported.
15+
- PASS - No scoped mock-db-store expansion, page-local arrays, JSON source of truth, SQLite, or tmp runtime dependency was introduced.
16+
- PASS - DDL, DML, and seed artifacts remain under `docs_build/database/ddl/`, `docs_build/database/dml/`, and `docs_build/database/seed/`.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Validation Lane
2+
3+
Generated: 2026-06-26 20:51:40 UTC
4+
5+
- PASS - `node --check src/dev-runtime/toolbox-api/alfa-tool-services.mjs`
6+
- PASS - `node --check src/dev-runtime/server/local-api-router.mjs`
7+
- PASS - `node --check assets/toolbox/tags/js/index.js`
8+
- PASS - `node --check assets/toolbox/game-design/js/index.js`
9+
- PASS - `node --check assets/toolbox/game-configuration/js/index.js`
10+
- PASS - `node --test tests/dev-runtime/DevRuntimeBoundary.test.mjs`
11+
- PASS - `npx playwright test tests/playwright/tools/TagsTool.spec.mjs --project=playwright --workers=1 --reporter=line`
12+
- PASS - `npx playwright test tests/playwright/tools/GameDesignApiBehavior.spec.mjs --project=playwright --workers=1 --reporter=line`
13+
- PASS - `npx playwright test tests/playwright/tools/GameConfigurationApiBehavior.spec.mjs --project=playwright --workers=1 --reporter=line`
14+
- PASS - `git diff --check`
15+
16+
Note: an earlier parallel Game Design run timed out while writing Playwright trace artifacts; the same lane passed when rerun alone.

0 commit comments

Comments
 (0)