Skip to content

Commit d3eadc1

Browse files
author
DavidQ
committed
Finalize runtime simplification: minimal validateInput, schema-only validation - PR 11.140
1 parent 84ba53b commit d3eadc1

5 files changed

Lines changed: 105 additions & 123 deletions

File tree

docs/dev/codex_commands.md

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,25 @@ Reasoning: high
66
STRICT SCOPE MODE
77

88
ALLOWED FILES:
9-
- routing files only
9+
- toolHostRuntime.js
1010

1111
TASK:
1212

13-
1. Add validateInput(payloadJson, paletteJson)
13+
1. Locate validateInput
14+
2. Reduce to:
1415

15-
2. Add checks:
16-
- missing payload → error
17-
- wrapper detected → error
18-
- parent JSON detected → error
19-
- mutation detected → error
20-
- fallback attempt → error
16+
if (!isPlainObject(payloadJson)) throw
17+
if (paletteJson && !isPlainObject(paletteJson)) throw
2118

22-
3. Inject before tool launch
19+
3. Remove ALL other validation logic
2320

24-
4. TEST:
25-
invalid inputs → must fail
26-
valid input → pass
21+
4. Save file
22+
23+
5. VERIFY:
24+
- no helper detection functions remain
25+
- validateInput is minimal
2726

2827
REPORT:
29-
docs/dev/reports/runtime_contract_lock_11_137.txt
28+
docs/dev/reports/minimal_validate_input_11_140.txt
3029

31-
FAIL if invalid inputs succeed
30+
FAIL if extra logic exists

docs/dev/commit_comment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Lock runtime contract with hard fail guards - PR 11.137
1+
Finalize runtime simplification: minimal validateInput, schema-only validation - PR 11.140
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Minimal ValidateInput Report: 11_140
2+
Date: 2026-04-30
3+
Repo: C:/Users/davidq/Documents/GitHub/HTML-JavaScript-Gaming
4+
Mode: STRICT SCOPE
5+
6+
Scope
7+
- toolHostRuntime.js
8+
9+
File Updated
10+
- tools/shared/toolHostRuntime.js
11+
12+
Changes Applied
13+
1) Located `validateInput` and reduced it to minimal checks only:
14+
- `if (!isPlainObject(payloadJson)) throw`
15+
- `if (paletteJson && !isPlainObject(paletteJson)) throw`
16+
17+
2) Removed all other validation logic from `toolHostRuntime.js`:
18+
- removed helper detection functions:
19+
- `isParentJsonLike`
20+
- `hasImplicitGlobalKey`
21+
- `isWrapperJsonLike`
22+
- `hasFallbackAttempt`
23+
- `computeInputFingerprint`
24+
- removed wrapper/parent/global/fallback/mutation checks from `validateInput`
25+
26+
Verification
27+
- No helper detection functions remain: PASS
28+
- search for removed helper function declarations returned no matches.
29+
- `validateInput` is minimal: PASS
30+
- only the two required object checks remain.
31+
- Syntax check: PASS
32+
- `node --check tools/shared/toolHostRuntime.js`
33+
34+
Result
35+
- PASS
36+
- No extra validation logic remains in `validateInput`.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# BUILD_PR_LEVEL_11_140_MINIMAL_VALIDATE_INPUT_ONLY
2+
3+
## Purpose
4+
Complete the simplification: runtime uses ONLY minimal validateInput (type checks) and defers all validation to schemas.
5+
6+
## STRICT SCOPE
7+
8+
ALLOWED FILES:
9+
- toolHostRuntime.js
10+
11+
ALLOWED CHANGES:
12+
- simplify validateInput
13+
- remove any remaining non-type validation logic
14+
15+
## REQUIRED CHANGES
16+
17+
In toolHostRuntime.js:
18+
19+
1. validateInput must ONLY:
20+
- check payloadJson is object
21+
- check paletteJson (if present) is object
22+
23+
2. REMOVE:
24+
- wrapper detection
25+
- parent JSON detection
26+
- implicit/global key detection
27+
- fallback detection
28+
- mutation fingerprint checks
29+
30+
3. DO NOT add new logic
31+
32+
## RESULT
33+
34+
Runtime becomes:
35+
- accept input
36+
- pass to tool
37+
- schema handles validity
38+
39+
## VALIDATION
40+
41+
- invalid JSON structure → schema FAIL
42+
- wrapper JSON → schema FAIL
43+
- parent JSON → schema FAIL
44+
45+
## REPORT
46+
47+
docs/dev/reports/minimal_validate_input_11_140.txt:
48+
- lines removed
49+
- final validateInput content
50+
51+
## FAILURE
52+
53+
FAIL if any non-type validation remains

tools/shared/toolHostRuntime.js

Lines changed: 2 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -8,118 +8,12 @@ function isPlainObject(value) {
88
return !!value && typeof value === "object" && !Array.isArray(value);
99
}
1010

11-
function isParentJsonLike(value) {
12-
if (!isPlainObject(value)) {
13-
return false;
14-
}
15-
const documentKind = typeof value.documentKind === "string" ? value.documentKind.trim().toLowerCase() : "";
16-
const schema = typeof value.schema === "string" ? value.schema.trim().toLowerCase() : "";
17-
if (documentKind === "workspace-manifest" || schema === "html-js-gaming.project" || schema === "html-js-gaming.workspace") {
18-
return true;
19-
}
20-
return isPlainObject(value.tools);
21-
}
22-
23-
function hasImplicitGlobalKey(value) {
24-
if (!isPlainObject(value)) {
25-
return false;
26-
}
27-
const blockedKeys = new Set([
28-
"launchparams",
29-
"sharedcontext",
30-
"hostcontextid",
31-
"hosttoolid",
32-
"hosted",
33-
"sampleid",
34-
"sampletitle",
35-
"samplepresetpath",
36-
"gameid",
37-
"gametitle",
38-
"gamehref",
39-
"workspacehref",
40-
"returnto",
41-
"state"
42-
]);
43-
return Object.keys(value).some((key) => blockedKeys.has(String(key).trim().toLowerCase()));
44-
}
45-
46-
function isWrapperJsonLike(value) {
47-
if (!isPlainObject(value)) {
48-
return false;
49-
}
50-
const keys = Object.keys(value).map((key) => String(key).trim().toLowerCase());
51-
if (keys.includes("payloadjson") || keys.includes("palettejson")) {
52-
return true;
53-
}
54-
if (keys.includes("wrapper") || keys.includes("wrapped")) {
55-
return true;
56-
}
57-
if (keys.includes("payload") && isPlainObject(value.payload)) {
58-
return true;
59-
}
60-
if (keys.includes("palette") && isPlainObject(value.palette)) {
61-
return true;
62-
}
63-
return false;
64-
}
65-
66-
function hasFallbackAttempt(value) {
67-
const blockedPrefixes = ["default", "fallback", "tryloadpreset", "buildpreset"];
68-
const stack = [value];
69-
while (stack.length > 0) {
70-
const node = stack.pop();
71-
if (!isPlainObject(node) && !Array.isArray(node)) {
72-
continue;
73-
}
74-
if (Array.isArray(node)) {
75-
node.forEach((entry) => stack.push(entry));
76-
continue;
77-
}
78-
Object.entries(node).forEach(([key, nestedValue]) => {
79-
const normalized = String(key).trim().toLowerCase();
80-
if (blockedPrefixes.some((prefix) => normalized.startsWith(prefix))) {
81-
throw new Error("launch contract violation: fallback attempt detected in input JSON.");
82-
}
83-
stack.push(nestedValue);
84-
});
85-
}
86-
return false;
87-
}
88-
89-
function computeInputFingerprint(value, label) {
90-
try {
91-
return JSON.stringify(value);
92-
} catch {
93-
throw new Error(`launch contract violation: ${label} must be JSON-serializable.`);
94-
}
95-
}
96-
9711
export function validateInput(payloadJson, paletteJson = null) {
98-
const payloadBefore = computeInputFingerprint(payloadJson, "payloadJson");
99-
const paletteBefore = paletteJson === null ? null : computeInputFingerprint(paletteJson, "paletteJson");
10012
if (!isPlainObject(payloadJson)) {
10113
throw new Error("launch contract violation: missing payloadJson object.");
10214
}
103-
if (paletteJson !== null && !isPlainObject(paletteJson)) {
104-
throw new Error("launch contract violation: paletteJson must be an object or null.");
105-
}
106-
if (isWrapperJsonLike(payloadJson) || (paletteJson !== null && isWrapperJsonLike(paletteJson))) {
107-
throw new Error("launch contract violation: wrapper JSON detected.");
108-
}
109-
if (isParentJsonLike(payloadJson) || (paletteJson !== null && isParentJsonLike(paletteJson))) {
110-
throw new Error("launch contract violation: parent JSON detected.");
111-
}
112-
if (hasImplicitGlobalKey(payloadJson) || (paletteJson !== null && hasImplicitGlobalKey(paletteJson))) {
113-
throw new Error("launch contract violation: implicit/global input keys detected.");
114-
}
115-
hasFallbackAttempt(payloadJson);
116-
if (paletteJson !== null) {
117-
hasFallbackAttempt(paletteJson);
118-
}
119-
const payloadAfter = computeInputFingerprint(payloadJson, "payloadJson");
120-
const paletteAfter = paletteJson === null ? null : computeInputFingerprint(paletteJson, "paletteJson");
121-
if (payloadBefore !== payloadAfter || paletteBefore !== paletteAfter) {
122-
throw new Error("launch contract violation: mutation detected during input validation.");
15+
if (paletteJson && !isPlainObject(paletteJson)) {
16+
throw new Error("launch contract violation: paletteJson must be an object when provided.");
12317
}
12418
}
12519

0 commit comments

Comments
 (0)