Skip to content

Commit c4cccd5

Browse files
author
DavidQ
committed
Verify runtime enforces tool schema boundary (no wrapper/parent JSON) - PR 11.127. Enforce zero-transform payload routing across workspace/tool launch - PR 11.128
1 parent 381a9a4 commit c4cccd5

7 files changed

Lines changed: 248 additions & 73 deletions

docs/dev/codex_commands.md

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,26 @@
33
Model: GPT-5.3-codex
44
Reasoning: high
55

6-
## HARD MODE: WRITE OR FAIL
6+
STRICT SCOPE MODE
77

8-
FILES:
8+
ALLOWED FILES:
9+
- routing files only
910

10-
1. tools/schemas/workspace.manifest.schema.json
11-
2. tools/schemas/tools/palette-browser.schema.json
11+
TASK:
1212

13-
## STEPS
13+
1. Find payload passing code
14+
2. Remove:
15+
- normalize*
16+
- transform*
17+
- convert*
18+
- map*
19+
- enrich*
20+
3. Ensure payload passed directly
1421

15-
FOR EACH FILE:
22+
VERIFY:
23+
- payload before == payload after
1624

17-
1. READ file
18-
2. STORE BEFORE content
19-
3. APPLY REQUIRED MODIFICATIONS
20-
4. WRITE file
21-
5. READ AGAIN
22-
6. STORE AFTER content
23-
7. COMPARE
25+
REPORT:
26+
docs/dev/reports/no_transform_routing_11_128.txt
2427

25-
IF BEFORE == AFTER:
26-
FAIL
27-
28-
## OUTPUT REPORT
29-
30-
docs/dev/reports/enforced_write_11_125.txt:
31-
32-
- file name
33-
- BEFORE snippet
34-
- AFTER snippet
35-
- diff summary
36-
- status: SUCCESS / FAIL
37-
38-
## END CONDITION
39-
40-
If ANY file not changed:
41-
FAIL ENTIRE PR
28+
FAIL if any mutation remains

docs/dev/commit_comment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Enforce mandatory schema file modifications with diff verification - PR 11.125
1+
Enforce zero-transform payload routing across workspace/tool launch - PR 11.128
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
No-Transform Routing Report: 11_128
2+
Date: 2026-04-30
3+
Repo: C:/Users/davidq/Documents/GitHub/HTML-JavaScript-Gaming
4+
Mode: STRICT SCOPE
5+
6+
Task
7+
- Find payload passing code.
8+
- Remove normalize*/transform*/convert*/map*/enrich* from payload pass path.
9+
- Ensure payload is passed directly.
10+
11+
Routing file changed
12+
- tools/shared/platformShell.js
13+
14+
Targeted payload passing path
15+
- resolveWorkspaceManifestScopedToolPreset(rawPreset, toolId)
16+
- Used by selectWorkspaceScopedToolPreset(...) and workspace-scoped fetch shim pass-through.
17+
18+
Change summary
19+
- Removed normalized/mapped candidate-key resolution from payload routing.
20+
- Removed normalized tool-id/schema checks in this payload resolver path.
21+
- Switched to direct key lookup: tools[toolId].
22+
- Preserved boundary validation while returning the original payload object directly.
23+
24+
Verification
25+
1) Mutation keyword scan inside resolver function:
26+
- Pattern: /\b(?:normalize\w*|transform\w*|convert\w*|map\w*|enrich\w*)\b/
27+
- Result: none
28+
29+
2) Direct pass-through checks:
30+
- palette route: resolved === original payload -> true
31+
- palette route: JSON.stringify(resolved) === JSON.stringify(original) -> true
32+
- wrapped route: resolved === original payload -> true
33+
- wrapped route: JSON.stringify(resolved) === JSON.stringify(original) -> true
34+
35+
Result
36+
- PASS: payload before == payload after in routing resolver.
37+
- PASS: no mutation helpers remain in targeted payload pass function.
38+
- FAIL condition not triggered.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
Runtime Schema Boundary Report: 11_127
2+
Date: 2026-04-30
3+
Repo: C:/Users/davidq/Documents/GitHub/HTML-JavaScript-Gaming
4+
Scope Mode: STRICT
5+
6+
Allowed files:
7+
- tools/schemas/workspace.manifest.schema.json
8+
- tools/schemas/tools/palette-browser.schema.json
9+
10+
Loaded schema:
11+
- tools/schemas/tools/palette-browser.schema.json
12+
13+
Test target:
14+
- Validate boundary for palette direct payload schema
15+
16+
Input A (valid palette JSON):
17+
{
18+
"schema": "html-js-gaming.palette",
19+
"version": 1,
20+
"name": "Test Palette",
21+
"swatches": [
22+
{ "symbol": "A", "hex": "#112233", "name": "Ink" },
23+
{ "symbol": "B", "hex": "#445566", "name": "Fog" }
24+
]
25+
}
26+
Result A: PASS
27+
28+
Input B (wrapper JSON):
29+
{
30+
"tool": "palette-browser",
31+
"payload": { ...A... }
32+
}
33+
Result B: FAIL
34+
Observed boundary errors (excerpt):
35+
- missing required key 'schema'
36+
- missing required key 'version'
37+
- missing required key 'name'
38+
- missing required key 'swatches'
39+
40+
Input C (workspace JSON):
41+
{
42+
"documentKind": "workspace-manifest",
43+
"schema": "html-js-gaming.workspace",
44+
"version": 1,
45+
"id": "ws-1",
46+
"name": "Workspace",
47+
"tools": { "palette-browser": { ...A... } }
48+
}
49+
Result C: FAIL
50+
Observed boundary errors (excerpt):
51+
- missing required key 'swatches'
52+
- additional property 'documentKind' not allowed
53+
- additional property 'tools' not allowed
54+
- schema must equal 'html-js-gaming.palette'
55+
56+
Verification summary:
57+
- A = pass
58+
- B = fail
59+
- C = fail
60+
61+
Boundary enforcement status: ENFORCED
62+
No schema or routing changes required.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# BUILD_PR_LEVEL_11_127_VERIFY_AND_ENFORCE_SCHEMA_BOUNDARY_AT_RUNTIME
2+
3+
## Purpose
4+
After strict schema file changes, verify runtime actually respects schema boundaries (no hidden wrapper/payload usage).
5+
6+
## Scope
7+
- testable
8+
- STRICT SCOPE
9+
- runtime verification only
10+
- no schema edits unless explicitly required by failure
11+
12+
## ALLOWED FILES
13+
14+
- tools/schemas/workspace.manifest.schema.json
15+
- tools/schemas/tools/palette-browser.schema.json
16+
- workspace manager routing file(s) (read-only unless violation found)
17+
18+
## ALLOWED CHANGES
19+
20+
- ONLY if violation found:
21+
- remove runtime wrapper handling for palette
22+
- ensure direct payload passed
23+
24+
## VALIDATION TARGETS
25+
26+
1. Palette Browser receives ONLY palette JSON
27+
2. Passing wrapper JSON must FAIL schema
28+
3. Passing game/workspace JSON must FAIL schema
29+
4. Workspace manager must pass referenced payload only (no transform)
30+
31+
## REQUIRED TESTS
32+
33+
Codex must simulate:
34+
35+
- valid palette JSON → PASS
36+
- wrapper {tool,payload} → FAIL
37+
- workspace/game JSON → FAIL
38+
39+
## OUTPUT
40+
41+
docs/dev/reports/runtime_schema_boundary_11_127.txt:
42+
- test cases
43+
- results
44+
- violations
45+
- fixes applied (if any)
46+
47+
## FAILURE
48+
49+
FAIL if:
50+
- wrapper still works
51+
- parent JSON still accepted
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# BUILD_PR_LEVEL_11_128_ENFORCE_NO_TRANSFORM_ROUTING
2+
3+
## Purpose
4+
Ensure Workspace Manager and launch paths pass JSON payloads WITHOUT transformation.
5+
6+
## STRICT SCOPE
7+
8+
ALLOWED FILES:
9+
- workspace manager routing files (only those that pass payloads)
10+
- tools launch handler files (only if needed)
11+
12+
ALLOWED CHANGES:
13+
- remove transform/normalize/convert logic
14+
- pass payload as-is
15+
16+
## RULE
17+
18+
input JSON → schema validate → tool
19+
20+
NO:
21+
- transform
22+
- normalize
23+
- wrap
24+
- unwrap
25+
- convert
26+
- enrich
27+
- infer
28+
29+
## REQUIRED CHECKS
30+
31+
Codex must verify:
32+
33+
1. Payload passed EXACTLY as found in source JSON
34+
2. No intermediate object creation
35+
3. No field renaming
36+
4. No default injection
37+
38+
## VALIDATION
39+
40+
- trace payload from:
41+
sample → workspace → tool
42+
- confirm byte-level equality (no shape change)
43+
44+
## REPORT
45+
46+
docs/dev/reports/no_transform_routing_11_128.txt:
47+
- files checked
48+
- violations found
49+
- fixes applied
50+
- before/after snippets
51+
52+
## FAILURE
53+
54+
FAIL if:
55+
- any transform remains
56+
- payload mutated

tools/shared/platformShell.js

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -481,17 +481,9 @@ function isWorkspaceManifestPreset(rawPreset) {
481481
return documentKind === "workspace-manifest" || schema === "html-js-gaming.project";
482482
}
483483

484-
function normalizeWorkspaceManifestToolKey(rawKey) {
485-
const normalizedKey = normalizeTextValue(rawKey).toLowerCase();
486-
if (!normalizedKey) {
487-
return "";
488-
}
489-
return normalizedKey;
490-
}
491-
492484
function resolveWorkspaceManifestScopedToolPreset(rawPreset, toolId) {
493-
const normalizedToolId = normalizeTextValue(toolId).toLowerCase();
494-
if (!normalizedToolId) {
485+
const directToolId = typeof toolId === "string" ? toolId : "";
486+
if (!directToolId) {
495487
return null;
496488
}
497489
const tools = rawPreset.tools && typeof rawPreset.tools === "object" && !Array.isArray(rawPreset.tools)
@@ -501,44 +493,33 @@ function resolveWorkspaceManifestScopedToolPreset(rawPreset, toolId) {
501493
return null;
502494
}
503495

504-
const candidateKeys = Object.keys(tools).filter((key) => normalizeWorkspaceManifestToolKey(key) === normalizedToolId);
505-
if (candidateKeys.length === 0) {
496+
const scopedPreset = tools[directToolId];
497+
if (!scopedPreset || typeof scopedPreset !== "object" || Array.isArray(scopedPreset)) {
506498
return null;
507499
}
508500

509-
const exactKeyIndex = candidateKeys.findIndex((key) => normalizeTextValue(key).toLowerCase() === normalizedToolId);
510-
const orderedKeys = exactKeyIndex >= 0
511-
? [candidateKeys[exactKeyIndex], ...candidateKeys.filter((_, index) => index !== exactKeyIndex)]
512-
: candidateKeys;
513-
for (const key of orderedKeys) {
514-
const scopedPreset = tools[key];
515-
if (!scopedPreset || typeof scopedPreset !== "object" || Array.isArray(scopedPreset)) {
516-
continue;
517-
}
518-
if (normalizedToolId === "palette-browser") {
519-
const isDirectPaletteDocument = normalizeTextValue(scopedPreset.schema).toLowerCase() === "html-js-gaming.palette"
520-
&& Array.isArray(scopedPreset.swatches);
521-
if (!isDirectPaletteDocument) {
522-
console.warn(`[tools.platform] workspace scoped preset rejected: key="${key}" must be direct palette JSON for palette-browser.`);
523-
continue;
524-
}
525-
return scopedPreset;
526-
}
527-
528-
const payloadToolId = normalizeTextValue(scopedPreset.tool).toLowerCase();
529-
if (!payloadToolId) {
530-
console.warn(`[tools.platform] workspace scoped preset rejected: key="${key}" is missing required "tool" field.`);
531-
continue;
532-
}
533-
if (payloadToolId !== normalizedToolId) {
534-
console.warn(
535-
`[tools.platform] workspace scoped preset rejected: key="${key}" expected tool="${normalizedToolId}" but found tool="${payloadToolId}".`
536-
);
537-
continue;
501+
if (directToolId === "palette-browser") {
502+
const isDirectPaletteDocument = scopedPreset.schema === "html-js-gaming.palette"
503+
&& Array.isArray(scopedPreset.swatches);
504+
if (!isDirectPaletteDocument) {
505+
console.warn(`[tools.platform] workspace scoped preset rejected: key="${directToolId}" must be direct palette JSON for palette-browser.`);
506+
return null;
538507
}
539508
return scopedPreset;
540509
}
541-
return null;
510+
511+
const payloadToolId = typeof scopedPreset.tool === "string" ? scopedPreset.tool : "";
512+
if (!payloadToolId) {
513+
console.warn(`[tools.platform] workspace scoped preset rejected: key="${directToolId}" is missing required "tool" field.`);
514+
return null;
515+
}
516+
if (payloadToolId !== directToolId) {
517+
console.warn(
518+
`[tools.platform] workspace scoped preset rejected: key="${directToolId}" expected tool="${directToolId}" but found tool="${payloadToolId}".`
519+
);
520+
return null;
521+
}
522+
return scopedPreset;
542523
}
543524

544525
function selectWorkspaceScopedToolPreset(rawPreset, toolId) {

0 commit comments

Comments
 (0)