Skip to content

Commit 1985b67

Browse files
committed
Audit and deduplicate tool contract structure while preserving per-tool ownership - PR_26152_074-tool-contract-deduplication-audit
1 parent ff2af67 commit 1985b67

26 files changed

Lines changed: 188 additions & 78 deletions

docs/dev/reports/tool_contract_coverage.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Tool Contract Coverage
22

3-
PR: PR_26152_073-split-tool-contracts-by-tool
3+
PR: PR_26152_074-tool-contract-deduplication-audit
44
Date: 2026-06-02
55

66
## Discovery Sources
@@ -12,6 +12,14 @@ Date: 2026-06-02
1212
- Per-tool contracts: `src/shared/contracts/tools/*ToolContract.js`
1313
- Contract index: `src/shared/contracts/tools/toolContractsIndex.js`
1414

15+
## Deduplication Status
16+
17+
- Per-tool modules remain split: 34/34 retained.
18+
- Matching per-tool tests remain split: 34/34 retained.
19+
- Shared primitives now own repeated empty/all supported asset declarations and draft contract creation.
20+
- Per-tool declarations still own only tool-specific ids, types, inputs, outputs, asset support, imports, and exports.
21+
- Registered first-class tool coverage remains unchanged.
22+
1523
## Active Registered First-Class Tools
1624

1725
All active visible registered first-class tools discovered through `getVisibleActiveToolRegistry()` have matching contracts.
@@ -76,3 +84,6 @@ The root Tools Index card data includes public/root cards that are not all activ
7684
- Registered first-class tools without contract: 0
7785
- Root Tools Index cards reviewed: 18
7886
- Root Tools Index cards skipped as non-tool surfaces: 2
87+
- Duplicated empty supported asset declarations remaining in tool files: 0
88+
- Duplicated all-supported-assets declarations remaining in tool files: 0
89+
- Duplicated draft status declarations remaining in tool files: 0
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Tool Contract Deduplication Audit
2+
3+
PR: PR_26152_074-tool-contract-deduplication-audit
4+
Date: 2026-06-02
5+
6+
## Scope
7+
8+
- Audited current contract structure after PR_26152_073 split tool contracts by tool.
9+
- Limited changes to `src/shared/contracts/`, `src/shared/contracts/tools/`, contract tests validation, and reports.
10+
- No runtime code, UI, CSS, HTML, or non-contract JavaScript changed.
11+
- Per-tool contract files remain split and were not merged into one file.
12+
13+
## Structure Reviewed
14+
15+
| Area | Result |
16+
|---|---|
17+
| `identityPermissionsContract.js` | Identity roles, permissions, scopes, and visibility states remain shared primitives. |
18+
| `projectContract.js` | Project roles, visibility, access rules, and state validation remain shared primitives. |
19+
| `toolStateContract.js` | Tool State ownership, visibility, status, versioning, recovery, and exportability remain shared primitives. |
20+
| `assetContract.js` | Generic asset ownership, status, visibility, metadata, type, and export behavior remain shared primitives. |
21+
| `paletteContract.js` | Palette-specific swatch validation and portable export behavior remain shared primitives. |
22+
| `vectorAssetContract.js` | Vector asset validation and portable export behavior remain shared primitives. |
23+
| `toolContractPrimitives.js` | Owns tool contract defaults, validation, ownership, visibility, access, export/import format validation, and shared asset-type/status declaration helpers. |
24+
| `contracts/tools/*.js` | Remain per-tool declarations only, with unique tool inputs/outputs/type/assets/import/export data. |
25+
26+
## Duplication Findings
27+
28+
| Category | Before | After | Action |
29+
|---|---:|---:|---|
30+
| Per-tool contract files | 34 | 34 | Preserved split per-tool modules. |
31+
| Matching per-tool tests | 34 | 34 | Preserved tool-by-tool coverage. |
32+
| `supportedAssetTypes: []` duplicated in tool files | 13 | 0 | Replaced with `TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.NONE`. |
33+
| `Object.values(ASSET_TYPES)` duplicated in tool files | 5 | 0 | Replaced with `TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.ALL`. |
34+
| `status: TOOL_CONTRACT_STATUS.DRAFT` duplicated in tool files | 11 | 0 | Replaced with `createDraftToolContract(...)`. |
35+
| Duplicated ownership rules in tool files | 0 | 0 | Ownership remains in `createToolContract`. |
36+
| Duplicated visibility rules in tool files | 0 | 0 | Visibility/access remains in `toolContractPrimitives.js`. |
37+
| Duplicated validation logic in tool files | 0 | 0 | Validation remains in `validateToolContract` and shared test helper. |
38+
| Duplicated portable export/import validation | 0 | 0 | Portable export/import validation remains in `toolContractPrimitives.js`. |
39+
40+
## Per-Tool Audit
41+
42+
| Tool Contract Group | Unique Tool Data | Deduplicated Data | Validation/Ownership/Visibility |
43+
|---|---|---|---|
44+
| Active registered tools | `toolId`, `toolType`, inputs, outputs, asset types, import/export formats | Empty/all supported asset declarations where applicable | Shared through `toolContractPrimitives.js`. |
45+
| Root Tools Index planning contracts | `toolId`, `toolType`, inputs, outputs, asset types, import/export formats | Draft status, empty/all supported asset declarations where applicable | Shared through `toolContractPrimitives.js`. |
46+
| Tool contract index | Contract aggregation and root-card coverage mapping | No validation logic added | Lookup and coverage only; per-tool declarations stay split. |
47+
| Per-tool tests | Expected tool id per module | Repeated assertions remain in `toolContractTestHelpers.mjs` | Matching one test per tool preserved. |
48+
49+
## Shared Primitive Ownership Summary
50+
51+
`src/shared/contracts/toolContractPrimitives.js` now owns:
52+
53+
- default tool contract owner/project identifiers
54+
- default visibility/status/version behavior
55+
- `createToolContract`
56+
- `createDraftToolContract`
57+
- `TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.ALL`
58+
- `TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.NONE`
59+
- tool type/status/visibility/format validators
60+
- source tool state validation
61+
- actor visibility/access checks
62+
- archived edit policy checks
63+
- portable tool contract export creation and validation
64+
65+
Per-tool contract modules own only the data that distinguishes that tool:
66+
67+
- `toolId`
68+
- `toolType`
69+
- `requiredInputs`
70+
- `producedOutputs`
71+
- `supportedAssetTypes`
72+
- `importFormats`
73+
- `exportFormats`
74+
75+
## Behavior Invariance
76+
77+
- No tool contract was removed.
78+
- No tool contract id changed.
79+
- No per-tool coverage test was removed.
80+
- No validation, ownership, visibility, access, status, import, or export rule changed.
81+
- All changed contract outputs remain covered by the same targeted contract test suite.
82+
83+
## Validation
84+
85+
```powershell
86+
$rootContractTests = Get-ChildItem -Path tests/shared -Filter '*Contract.test.mjs' | Sort-Object Name | ForEach-Object { $_.FullName }
87+
$toolContractTests = Get-ChildItem -Path tests/shared/tools -Filter '*.test.mjs' | Sort-Object Name | ForEach-Object { $_.FullName }
88+
node ./scripts/run-node-test-files.mjs $rootContractTests $toolContractTests
89+
```
90+
91+
Result: PASS, 41/41 targeted node test files passed.
92+
93+
## Lane Report
94+
95+
- Lanes executed: contract lane for shared contracts and tool contract declarations.
96+
- Lanes skipped: runtime, integration, engine, samples, recovery/UAT because this PR changes only contract declarations/primitives and reports.
97+
- Samples decision: SKIP because samples are out of scope and no sample JSON or runtime behavior changed.
98+
- Playwright impacted: No. This PR changes contract primitives/declarations only and does not change browser UI or runtime behavior.
99+
- Blocker scope: targeted contract lane only.
100+
101+
## Manual Validation
102+
103+
- Confirm `src/shared/contracts/tools/` still contains one contract module per tool/control.
104+
- Confirm `tests/shared/tools/` still contains one matching test per tool/control plus shared coverage/helper tests.
105+
- Confirm no runtime, UI, CSS, HTML, samples, games, or non-contract tool files changed.

src/shared/contracts/toolContractPrimitives.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
isToolStateVersion,
2323
} from "./toolStateContract.js";
2424
import {
25+
ASSET_TYPES,
2526
isAssetType,
2627
} from "./assetContract.js";
2728

@@ -199,6 +200,11 @@ export const TOOL_CONTRACT_ERRORS = Object.freeze({
199200
PORTABLE_EXPORT_INVALID: "TOOL_CONTRACT_PORTABLE_EXPORT_INVALID",
200201
});
201202

203+
export const TOOL_CONTRACT_SUPPORTED_ASSET_TYPES = Object.freeze({
204+
ALL: Object.freeze(Object.values(ASSET_TYPES)),
205+
NONE: Object.freeze([]),
206+
});
207+
202208
export function createToolContract({
203209
toolId,
204210
toolType,
@@ -228,6 +234,13 @@ export function createToolContract({
228234
});
229235
}
230236

237+
export function createDraftToolContract(toolContractDeclaration) {
238+
return createToolContract({
239+
...toolContractDeclaration,
240+
status: TOOL_CONTRACT_STATUS.DRAFT,
241+
});
242+
}
243+
231244
export function createRootCardCoverage(title, contractId, status, reason) {
232245
return Object.freeze({ title, contractId, status, reason });
233246
}

src/shared/contracts/tools/aiAssistantToolContract.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,17 @@ aiAssistantToolContract.js
66
*/
77
import {
88
TOOL_CONTRACT_FORMATS,
9-
TOOL_CONTRACT_STATUS,
9+
TOOL_CONTRACT_SUPPORTED_ASSET_TYPES,
1010
TOOL_CONTRACT_TYPES,
11-
createToolContract,
11+
createDraftToolContract,
1212
} from "../toolContractPrimitives.js";
1313

14-
export const AI_ASSISTANT_TOOL_CONTRACT = createToolContract({
14+
export const AI_ASSISTANT_TOOL_CONTRACT = createDraftToolContract({
1515
toolId: "ai-assistant",
1616
toolType: TOOL_CONTRACT_TYPES.UTILITY,
1717
requiredInputs: [TOOL_CONTRACT_FORMATS.TEXT],
1818
producedOutputs: [TOOL_CONTRACT_FORMATS.TEXT],
19-
supportedAssetTypes: [],
19+
supportedAssetTypes: TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.NONE,
2020
importFormats: [TOOL_CONTRACT_FORMATS.TEXT],
2121
exportFormats: [TOOL_CONTRACT_FORMATS.TEXT],
22-
status: TOOL_CONTRACT_STATUS.DRAFT,
2322
});

src/shared/contracts/tools/animationStudioToolContract.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,16 @@ import {
99
} from "../assetContract.js";
1010
import {
1111
TOOL_CONTRACT_FORMATS,
12-
TOOL_CONTRACT_STATUS,
1312
TOOL_CONTRACT_TYPES,
14-
createToolContract,
13+
createDraftToolContract,
1514
} from "../toolContractPrimitives.js";
1615

17-
export const ANIMATION_STUDIO_TOOL_CONTRACT = createToolContract({
16+
export const ANIMATION_STUDIO_TOOL_CONTRACT = createDraftToolContract({
1817
toolId: "animation-studio",
1918
toolType: TOOL_CONTRACT_TYPES.STUDIO,
2019
requiredInputs: [TOOL_CONTRACT_FORMATS.IMAGE_FILE],
2120
producedOutputs: [TOOL_CONTRACT_FORMATS.ANIMATION_JSON],
2221
supportedAssetTypes: [ASSET_TYPES.IMAGE],
2322
importFormats: [TOOL_CONTRACT_FORMATS.IMAGE_FILE],
2423
exportFormats: [TOOL_CONTRACT_FORMATS.ANIMATION_JSON],
25-
status: TOOL_CONTRACT_STATUS.DRAFT,
2624
});

src/shared/contracts/tools/assetManagerV2ToolContract.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ David Quesenberry
44
06/02/2026
55
assetManagerV2ToolContract.js
66
*/
7-
import {
8-
ASSET_TYPES,
9-
} from "../assetContract.js";
107
import {
118
TOOL_CONTRACT_FORMATS,
9+
TOOL_CONTRACT_SUPPORTED_ASSET_TYPES,
1210
TOOL_CONTRACT_TYPES,
1311
createToolContract,
1412
} from "../toolContractPrimitives.js";
@@ -18,7 +16,7 @@ export const ASSET_MANAGER_V2_TOOL_CONTRACT = createToolContract({
1816
toolType: TOOL_CONTRACT_TYPES.MANAGER,
1917
requiredInputs: [TOOL_CONTRACT_FORMATS.PALETTE_JSON, TOOL_CONTRACT_FORMATS.METADATA_JSON],
2018
producedOutputs: [TOOL_CONTRACT_FORMATS.METADATA_JSON, TOOL_CONTRACT_FORMATS.PROJECT_PACKAGE],
21-
supportedAssetTypes: Object.values(ASSET_TYPES),
19+
supportedAssetTypes: TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.ALL,
2220
importFormats: [TOOL_CONTRACT_FORMATS.METADATA_JSON, TOOL_CONTRACT_FORMATS.ASSET],
2321
exportFormats: [TOOL_CONTRACT_FORMATS.METADATA_JSON, TOOL_CONTRACT_FORMATS.PROJECT_PACKAGE],
2422
});

src/shared/contracts/tools/assetPipelineToolContract.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ David Quesenberry
44
06/02/2026
55
assetPipelineToolContract.js
66
*/
7-
import {
8-
ASSET_TYPES,
9-
} from "../assetContract.js";
107
import {
118
TOOL_CONTRACT_FORMATS,
9+
TOOL_CONTRACT_SUPPORTED_ASSET_TYPES,
1210
TOOL_CONTRACT_TYPES,
1311
createToolContract,
1412
} from "../toolContractPrimitives.js";
@@ -18,7 +16,7 @@ export const ASSET_PIPELINE_TOOL_CONTRACT = createToolContract({
1816
toolType: TOOL_CONTRACT_TYPES.PIPELINE,
1917
requiredInputs: [TOOL_CONTRACT_FORMATS.METADATA_JSON, TOOL_CONTRACT_FORMATS.ASSET],
2018
producedOutputs: [TOOL_CONTRACT_FORMATS.METADATA_JSON, TOOL_CONTRACT_FORMATS.PROJECT_PACKAGE],
21-
supportedAssetTypes: Object.values(ASSET_TYPES),
19+
supportedAssetTypes: TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.ALL,
2220
importFormats: [TOOL_CONTRACT_FORMATS.METADATA_JSON, TOOL_CONTRACT_FORMATS.ASSET],
2321
exportFormats: [TOOL_CONTRACT_FORMATS.METADATA_JSON, TOOL_CONTRACT_FORMATS.PROJECT_PACKAGE],
2422
});

src/shared/contracts/tools/assetStudioToolContract.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,16 @@ import {
99
} from "../assetContract.js";
1010
import {
1111
TOOL_CONTRACT_FORMATS,
12-
TOOL_CONTRACT_STATUS,
1312
TOOL_CONTRACT_TYPES,
14-
createToolContract,
13+
createDraftToolContract,
1514
} from "../toolContractPrimitives.js";
1615

17-
export const ASSET_STUDIO_TOOL_CONTRACT = createToolContract({
16+
export const ASSET_STUDIO_TOOL_CONTRACT = createDraftToolContract({
1817
toolId: "asset-studio",
1918
toolType: TOOL_CONTRACT_TYPES.STUDIO,
2019
requiredInputs: [TOOL_CONTRACT_FORMATS.PALETTE_JSON],
2120
producedOutputs: [TOOL_CONTRACT_FORMATS.IMAGE_FILE, TOOL_CONTRACT_FORMATS.VECTOR_JSON, TOOL_CONTRACT_FORMATS.PALETTE_JSON],
2221
supportedAssetTypes: [ASSET_TYPES.IMAGE, ASSET_TYPES.VECTOR, ASSET_TYPES.PALETTE],
2322
importFormats: [TOOL_CONTRACT_FORMATS.PALETTE_JSON, TOOL_CONTRACT_FORMATS.IMAGE_FILE],
2423
exportFormats: [TOOL_CONTRACT_FORMATS.IMAGE_FILE, TOOL_CONTRACT_FORMATS.VECTOR_JSON, TOOL_CONTRACT_FORMATS.PALETTE_JSON],
25-
status: TOOL_CONTRACT_STATUS.DRAFT,
2624
});

src/shared/contracts/tools/codeStudioToolContract.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,17 @@ codeStudioToolContract.js
66
*/
77
import {
88
TOOL_CONTRACT_FORMATS,
9-
TOOL_CONTRACT_STATUS,
9+
TOOL_CONTRACT_SUPPORTED_ASSET_TYPES,
1010
TOOL_CONTRACT_TYPES,
11-
createToolContract,
11+
createDraftToolContract,
1212
} from "../toolContractPrimitives.js";
1313

14-
export const CODE_STUDIO_TOOL_CONTRACT = createToolContract({
14+
export const CODE_STUDIO_TOOL_CONTRACT = createDraftToolContract({
1515
toolId: "code-studio",
1616
toolType: TOOL_CONTRACT_TYPES.EDITOR,
1717
requiredInputs: [TOOL_CONTRACT_FORMATS.CODE_FILE],
1818
producedOutputs: [TOOL_CONTRACT_FORMATS.CODE_FILE],
19-
supportedAssetTypes: [],
19+
supportedAssetTypes: TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.NONE,
2020
importFormats: [TOOL_CONTRACT_FORMATS.CODE_FILE],
2121
exportFormats: [TOOL_CONTRACT_FORMATS.CODE_FILE],
22-
status: TOOL_CONTRACT_STATUS.DRAFT,
2322
});

src/shared/contracts/tools/gameBuilderToolContract.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,19 @@ David Quesenberry
44
06/02/2026
55
gameBuilderToolContract.js
66
*/
7-
import {
8-
ASSET_TYPES,
9-
} from "../assetContract.js";
107
import {
118
TOOL_CONTRACT_FORMATS,
12-
TOOL_CONTRACT_STATUS,
9+
TOOL_CONTRACT_SUPPORTED_ASSET_TYPES,
1310
TOOL_CONTRACT_TYPES,
14-
createToolContract,
11+
createDraftToolContract,
1512
} from "../toolContractPrimitives.js";
1613

17-
export const GAME_BUILDER_TOOL_CONTRACT = createToolContract({
14+
export const GAME_BUILDER_TOOL_CONTRACT = createDraftToolContract({
1815
toolId: "game-builder",
1916
toolType: TOOL_CONTRACT_TYPES.STUDIO,
2017
requiredInputs: [TOOL_CONTRACT_FORMATS.GAME_DESIGN_JSON, TOOL_CONTRACT_FORMATS.ASSET],
2118
producedOutputs: [TOOL_CONTRACT_FORMATS.GAME_MANIFEST],
22-
supportedAssetTypes: Object.values(ASSET_TYPES),
19+
supportedAssetTypes: TOOL_CONTRACT_SUPPORTED_ASSET_TYPES.ALL,
2320
importFormats: [TOOL_CONTRACT_FORMATS.GAME_DESIGN_JSON, TOOL_CONTRACT_FORMATS.ASSET],
2421
exportFormats: [TOOL_CONTRACT_FORMATS.GAME_MANIFEST, TOOL_CONTRACT_FORMATS.PROJECT_PACKAGE],
25-
status: TOOL_CONTRACT_STATUS.DRAFT,
2622
});

0 commit comments

Comments
 (0)