Skip to content

Commit 467b7cd

Browse files
author
DavidQ
committed
BUILD_PR_LEVEL_09_07_TOOL_BOUNDARY_NORMALIZATION
Normalizes active tool boundaries by centralizing proven reusable tool logic under tools/shared, removing cross-tool coupling, and adding focused boundary validation without changing engine/runtime or asset layout. & BUILD_PR_LEVEL_09_08_TOOL_DATA_CONTRACTS
1 parent c31e0c7 commit 467b7cd

16 files changed

Lines changed: 474 additions & 96 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
MODEL: GPT-5.3-codex
2-
REASONING: medium
3-
COMMAND: Align tool launch contract.
2+
REASONING: high
3+
COMMAND: Define and enforce tool data contracts.

docs/dev/COMMIT_COMMENT.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
BUILD_PR_LEVEL_09_06_TOOL_LAUNCH_CONTRACT_ALIGNMENT
1+
BUILD_PR_LEVEL_09_08_TOOL_DATA_CONTRACTS

docs/dev/NEXT_COMMAND.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
NEXT: BUILD_PR_LEVEL_09_07_TOOL_BOUNDARY_NORMALIZATION
1+
NEXT: BUILD_PR_LEVEL_09_09_ASSET_PIPELINE_TOOLING
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Aligned tool entry + config loading.
1+
Introduces tool data contract layer.
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
[ ] entry aligned
2-
[ ] config consistent
3-
[ ] tests pass
1+
[ ] contracts defined
2+
[ ] tools aligned
3+
[ ] no engine changes
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# BUILD_PR — LEVEL 09_07 — TOOL BOUNDARY NORMALIZATION
2+
3+
## Objective
4+
Normalize boundaries across active tools so `tools/shared` becomes the only approved shared surface for reusable tool logic, while each tool remains responsible only for its own UI and orchestration.
5+
6+
## Why This PR Exists
7+
The prior lane completed:
8+
- asset structure simplification
9+
- shared asset handoff enforcement
10+
- tool launch contract alignment
11+
12+
This PR is the next dependency-ordered step. The repo now needs a strict separation between:
13+
- tool-local UI / workflow code
14+
- shared tool utilities / state / IO helpers
15+
16+
Without this pass, active tools risk continuing to:
17+
- duplicate helper logic
18+
- import across tool folders
19+
- hide reusable logic inside one tool and copy it elsewhere
20+
- blur the line between shared utility code and tool-specific implementation
21+
22+
## In Scope
23+
- inventory reusable exact-clusters inside active tools
24+
- extract only proven multi-tool logic into `tools/shared`
25+
- replace cross-tool imports with `tools/shared` imports
26+
- document and enforce the rule that tools do not import other tools
27+
- normalize shared helper placement for tool-only utilities
28+
- add or update focused validation that guards tool-boundary rules
29+
30+
## Out of Scope
31+
- no engine changes
32+
- no runtime/gameplay changes
33+
- no asset relocation
34+
- no feature additions
35+
- no UI redesign
36+
- no broad cleanup unrelated to tool boundaries
37+
- no speculative extraction without reuse evidence
38+
39+
## Target Tools
40+
Primary active tools for this pass:
41+
- Tile Map Editor
42+
- Parallax Editor
43+
- Vector Map Editor
44+
- Vector Asset Studio
45+
- Sprite Editor
46+
47+
Secondary tool shells to keep aligned if touched:
48+
- State Inspector
49+
- Replay Visualizer
50+
- Performance Profiler
51+
52+
## Boundary Rules To Enforce
53+
1. A tool must not import code from another tool folder.
54+
2. Reusable tool logic must live under `tools/shared`.
55+
3. Tool entry files should orchestrate only:
56+
- boot
57+
- UI wiring
58+
- tool-local composition
59+
4. Shared logic extracted into `tools/shared` must be:
60+
- tool-agnostic
61+
- minimal
62+
- contractable
63+
- reused by 2+ active tools, or clearly required as the single approved shared surface
64+
5. Tool-specific workflow logic remains in the owning tool.
65+
66+
## Extraction Heuristics
67+
Promote only exact clusters such as:
68+
- path / URL resolution helpers
69+
- manifest/sample loading helpers
70+
- palette serialization / normalization helpers
71+
- shared storage key helpers
72+
- common panel / layout state helpers
73+
- tool-local fetch / import/export wrappers with repeated usage
74+
75+
Do not promote:
76+
- editor-specific commands
77+
- tool-specific scene behavior
78+
- one-off UI event flows
79+
- feature logic that belongs to a single editor
80+
81+
## Expected Implementation Shape
82+
Preferred shared homes:
83+
- `tools/shared/io/...`
84+
- `tools/shared/state/...`
85+
- `tools/shared/utils/...`
86+
- `tools/shared/contracts/...` (only if needed by proven reuse)
87+
- `tools/shared/validation/...` (only if needed by focused checks)
88+
89+
## Required Deliverables
90+
Codex should produce a small surgical delta containing:
91+
- exact-cluster extractions only
92+
- updated imports in affected tools
93+
- focused validation / test coverage for boundary rules
94+
- no unrelated file movement
95+
96+
## Validation Requirements
97+
At minimum validate:
98+
- touched tool entry files parse successfully
99+
- no active tool imports another tool directly
100+
- extracted helpers resolve from `tools/shared`
101+
- prior launch-contract behavior still passes
102+
- asset/palette hook expectations are not regressed
103+
104+
## Suggested Validation Commands
105+
Use the repo's existing validation style and keep it lightweight. Prefer focused checks such as:
106+
- node --check on touched files
107+
- focused tests for tool launch / boundary rules
108+
- existing asset usage / launch contract tests if present
109+
110+
## Acceptance Criteria
111+
- active tools do not import one another
112+
- reusable exact-cluster helpers are centralized under `tools/shared`
113+
- no engine/runtime code is touched
114+
- no asset layout changes occur
115+
- tests/checks covering boundary rules pass
116+
- the delta remains small and purpose-specific
117+
118+
## Implementation Notes
119+
- Keep this PR docs-first and surgical.
120+
- Favor exact-cluster extraction over broad reorganization.
121+
- If a candidate helper is only used once, leave it local.
122+
- If a helper contains UI assumptions from one tool, do not promote it until split cleanly.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Tool data contracts normalization (docs-only PR).

docs/specs/tool_data_contract.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Tool Data Contract
2+
3+
## Purpose
4+
Define and enforce normalized tool-state data contracts used by project save/open integration.
5+
6+
This contract is enforced by:
7+
- `tools/shared/projectToolIntegration.js`
8+
- `tests/tools/ProjectToolDataContracts.test.mjs`
9+
10+
## Contract Metadata
11+
- schema: `html-js-gaming.tool-data-contract`
12+
- version: `1`
13+
14+
## Tool Contracts
15+
16+
### Tile Map Editor
17+
- contractId: `tool-state.tile-map-editor/1`
18+
- required state blocks:
19+
- `documentModel`
20+
- `documentModel.assetRefs`
21+
22+
### Parallax Editor
23+
- contractId: `tool-state.parallax-editor/1`
24+
- required state blocks:
25+
- `documentModel`
26+
- `documentModel.assetRefs`
27+
28+
### Sprite Editor
29+
- contractId: `tool-state.sprite-editor/1`
30+
- required state blocks:
31+
- `project`
32+
- `project.assetRefs`
33+
34+
### Vector Map Editor
35+
- contractId: `tool-state.vector-map-editor/1`
36+
- normalized as tool-local object state.
37+
38+
### Vector Asset Studio
39+
- contractId: `tool-state.vector-asset-studio/1`
40+
- normalized field:
41+
- `selectedPaletteId` (string id normalization when present)
42+
43+
### Asset Browser
44+
- contractId: `tool-state.asset-browser/1`
45+
- normalized field:
46+
- `selectedAssetId` (string id normalization when present)
47+
48+
### Palette Browser
49+
- contractId: `tool-state.palette-browser/1`
50+
- normalized field:
51+
- `selectedPaletteId` (string id normalization when present)
52+
53+
## Enforcement Outputs
54+
`buildProjectToolIntegration(...)` publishes:
55+
- per-tool contract status (`valid` / `invalid`)
56+
- per-tool `contractIssues`
57+
- aggregate `contractSummary` with:
58+
- schema/version
59+
- status
60+
- invalid tool ids
61+
- warnings by tool

tests/run-tests.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ import { run as runStorageService } from './persistence/StorageService.test.mjs'
8888
import { run as runAssetValidationEngine } from './tools/AssetValidationEngine.test.mjs';
8989
import { run as runAssetUsageIntegration } from './tools/AssetUsageIntegration.test.mjs';
9090
import { run as runAssetRemediationSystem } from './tools/AssetRemediationSystem.test.mjs';
91+
import { run as runToolBoundaryEnforcement } from './tools/ToolBoundaryEnforcement.test.mjs';
92+
import { run as runProjectToolDataContracts } from './tools/ProjectToolDataContracts.test.mjs';
9193
import { run as runToolEntryLaunchContract } from './tools/ToolEntryLaunchContract.test.mjs';
9294
import { run as runProjectPackagingSystem } from './tools/ProjectPackagingSystem.test.mjs';
9395
import { run as runRuntimeAssetLoader } from './tools/RuntimeAssetLoader.test.mjs';
@@ -201,6 +203,8 @@ const tests = [
201203
['AssetValidationEngine', runAssetValidationEngine],
202204
['AssetUsageIntegration', runAssetUsageIntegration],
203205
['AssetRemediationSystem', runAssetRemediationSystem],
206+
['ToolBoundaryEnforcement', runToolBoundaryEnforcement],
207+
['ProjectToolDataContracts', runProjectToolDataContracts],
204208
['ToolEntryLaunchContract', runToolEntryLaunchContract],
205209
['ProjectPackagingSystem', runProjectPackagingSystem],
206210
['RuntimeAssetLoader', runRuntimeAssetLoader],
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import assert from "node:assert/strict";
2+
import {
3+
TOOL_DATA_CONTRACT_SCHEMA,
4+
TOOL_DATA_CONTRACT_VERSION,
5+
buildProjectToolIntegration,
6+
validateToolStateContract
7+
} from "../../tools/shared/projectToolIntegration.js";
8+
9+
export async function run() {
10+
const validTileState = {
11+
documentModel: {
12+
assetRefs: {
13+
tilemapId: "tilemap.alpha",
14+
tilesetId: "tileset.alpha",
15+
parallaxSourceIds: ["parallax.alpha", "parallax.alpha"]
16+
}
17+
}
18+
};
19+
const validSpriteState = {
20+
project: {
21+
assetRefs: {
22+
spriteId: "sprite.hero",
23+
paletteId: "palette.hero"
24+
}
25+
}
26+
};
27+
28+
const tileValidation = validateToolStateContract("tile-map-editor", validTileState);
29+
assert.equal(tileValidation.valid, true);
30+
assert.equal(tileValidation.contractId, "tool-state.tile-map-editor/1");
31+
assert.equal(tileValidation.normalizedState.documentModel.assetRefs.tilemapId, "tilemap.alpha");
32+
assert.deepEqual(tileValidation.normalizedState.documentModel.assetRefs.parallaxSourceIds, ["parallax.alpha"]);
33+
34+
const invalidSpriteValidation = validateToolStateContract("sprite-editor", { project: {} });
35+
assert.equal(invalidSpriteValidation.valid, false);
36+
assert.deepEqual(invalidSpriteValidation.issues, ["project.assetRefs block is required."]);
37+
38+
const integration = buildProjectToolIntegration({
39+
"tile-map-editor": validTileState,
40+
"sprite-editor": { project: {} },
41+
"vector-asset-studio": { selectedPaletteId: "palette.shared" }
42+
});
43+
44+
assert.equal(integration.contractSummary.schema, TOOL_DATA_CONTRACT_SCHEMA);
45+
assert.equal(integration.contractSummary.version, TOOL_DATA_CONTRACT_VERSION);
46+
assert.equal(integration.contractSummary.status, "invalid");
47+
assert.deepEqual(integration.contractSummary.invalidToolIds, ["sprite-editor"]);
48+
assert.equal(integration.tools["tile-map-editor"].contractStatus, "valid");
49+
assert.equal(integration.tools["sprite-editor"].contractStatus, "invalid");
50+
assert.equal(
51+
integration.tools["sprite-editor"].contractIssues.includes("project.assetRefs block is required."),
52+
true
53+
);
54+
assert.equal(integration.tools["vector-asset-studio"].contractStatus, "valid");
55+
assert.deepEqual(integration.assetReferences.tilemapIds, ["tilemap.alpha"]);
56+
assert.deepEqual(integration.assetReferences.tilesetIds, ["tileset.alpha"]);
57+
assert.deepEqual(integration.assetReferences.parallaxSourceIds, ["parallax.alpha"]);
58+
assert.deepEqual(integration.assetReferences.paletteIds, ["palette.shared"]);
59+
}

0 commit comments

Comments
 (0)