Problem class: documented-example-fails-sdk-runtime-validation — a payload that is valid against the authoritative JSON Schema is rejected end-to-end by a generated runtime validator.
decision_id documented as a free-form string, rejected at runtime by the TypeScript SDK (HTTP 500 INVALID_DECISION "Invalid UUID")Problem class: documented-example-fails-sdk-runtime-validation — a payload that is valid against the authoritative JSON Schema is rejected end-to-end by a generated runtime validator.
Scope: get-h3/h3 (specs + docs) with get-h3/protocol (JSON Schema), get-h3/sdk-typescript (zod 4.4.3) and the h3-test 46-test compliance battery.
Status of fix in this repo: shipped on get-h3/h3 at 650c086 + 285f0ab; verified below. Residual cross-repo drift is recorded at the end (not silently closed).
A harness author copies the first Decision example out of the spec/integration guide, e.g.
{ "decision": "tool_call", "decision_id": "d_7b2c", "tool_call": { "name": "terminal", "params": {} } }
and the first call to a harness built on sdk-typescript fails:
HTTP 500
{"error":{"code":"INVALID_DECISION","message":"Invalid decision from harness: decision_id: Invalid UUID"}}
Reproduce end-to-end with the real router (no reading required):
git clone https://github.com/get-h3/sdk-typescript && cd sdk-typescript
npm install && npm run build
# a harness whose returned decision uses the documented id
DECISION_ID=d_7b2c node --input-type=module -e '
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { createH3Router } from "./dist/harness.js";
class H { async onProcess(){ return {decision:"text",decision_id:process.env.DECISION_ID,history:[],text:{content:"hi",finished:true}}; }
async onResult(){ return {decision:"end",decision_id:process.env.DECISION_ID,history:[],end:{reason:"task_complete"}}; }
health(){ return {status:"ok",version:"0.1.0",transport:"rest",protocol_version:"1.0",capabilities:["text","end"]}; } }
const app = new Hono(); app.route("/", createH3Router(new H()));
serve({fetch:app.fetch,port:9301},()=>console.log("up"));'
curl -s -w '\nHTTP %{http_code}\n' -X POST http://localhost:9301/v1/process \
-H 'Content-Type: application/json' \
-d '{"session_id":"s1","message":{"role":"user","content":"hi"},
"identity":{"platform":"test","chat_id":"c1"},
"context":{"history":[],"config":{},"session_state":{}}}'
# -> INVALID_DECISION ... Invalid UUID / HTTP 500
Swap DECISION_ID=dba151bd-5558-4e7f-af34-65f960b22cf2 and the same request returns HTTP 200.
The same value is accepted by the JSON Schema but rejected by zod, which is the whole bug:
id="d_7b2c" JSON-schema=ACCEPT TS-zod=REJECT
id="D42" JSON-schema=ACCEPT TS-zod=REJECT
id="d_a1b2c3d4" JSON-schema=ACCEPT TS-zod=REJECT
id="dba151bd-5558-4e7f-af34-65f960b22cf2" JSON-schema=ACCEPT TS-zod=ACCEPT
Three artifacts disagree about the same field, and the disagreement is only visible at the validator, never in the schema:
| Artifact | Declaration | Enforced? |
|---|---|---|
get-h3/protocol schemas/v1/decision.json |
"decision_id": { "type": "string" } — no format |
yes — accepts anything |
get-h3/sdk-typescript src/protocol.ts:349 |
decision_id: z.uuid().default(() => crypto.randomUUID()) |
yes — accepts only RFC 4122 UUIDs |
get-h3/h3 docs/examples |
d_9e4f, d_7b2c, d_8c3d, D42, d_a1b2c3d4, … |
n/a |
Because the docs were written from the schema, every example was schema-valid and runtime-invalid. specs/07-OpenAPI-JSON-Schema.md:71 even renders the field as { "type": "string", "format": "uuid" }, so the repo already contradicted the authoritative schema in one place while shipping non-UUID literals everywhere else.
The 46-test battery only asserts that decision_id is a non-empty string (shim/src/h3_shim/test_battery.py, test 2_2_process_decision_has_id), and the Go reference harness returns the non-UUID echo-001 (sdk-go/examples/echo/main.go:47). Measured:
$ curl .../v1/process (Go echo) -> {"decision":"text","decision_id":"echo-001",...}
$ h3-test --endpoint http://localhost:9191
TOTAL 46/46 PASSED
$ DecisionSchema.safeParse({decision:"end",decision_id:"echo-001",end:{...}})
-> REJECT invalid_format: Invalid UUID
So the battery is green for a harness that the TypeScript router rejects on the first request. The gate tested uniqueness, the SDK tested format; neither test crossed the boundary.
The contract must be stated explicitly (the schema stays string; the strictest SDK defines the portable shape), and every example literal must be rewritten to a UUID.
specs/02-Protocol-Specification.md, Key Fields table (section 4):
-| `decision_id` | string | ✅ | Unique identifier for this decision |
+| `decision_id` | string | ✅ | Unique identifier for the decision within the session. The protocol schema types it as a plain string (no format constraint), but the TypeScript SDK validates RFC 4122 UUIDs and rejects anything else with HTTP 500 `INVALID_DECISION` — so emit a UUID (`uuid4()` / `crypto.randomUUID()`) for cross-SDK portability. |
docs/integration.md, immediately above the Decision table:
`decision_id` is a plain string per the protocol schema, but the TypeScript SDK validates
RFC 4122 UUIDs — emit a UUID (`uuid4()` / `crypto.randomUUID()`) so the same decision
is accepted by every SDK.
The four sites that reference the same decision reuse one UUID so multi-step examples still read coherently.
| File | Old | New |
|---|---|---|
specs/02 (tool_call, result, cancelled_decision_id, current_decision ×4) |
d_7b2c |
dba151bd-5558-4e7f-af34-65f960b22cf2 |
specs/02 (llm_call) |
d_8c3d |
d42dface-9a80-4b8f-871c-165986b0e781 |
specs/02 (text) |
d_9e4f |
194854c3-ac0d-4f67-96a9-9a0a1c359597 |
specs/02 (wait) |
d_f1a2 |
a8c53018-d73c-44ed-9765-3da0ebcbca1e |
specs/02 (delegate) |
d_0b3c |
b59b8fea-91b7-4e46-b6a2-f57330103da9 |
specs/02 (end) |
d_c4d5 |
3098316f-a21f-487e-b212-af5566e7716a |
specs/19 (health recent_errors) |
d_abc123 |
29f0ca62-810f-4392-9298-cba0dc35f3e7 |
specs/20 (dashboard recent_errors) |
D42 |
d9f4c1a2-7b3e-4c58-9a10-6f2d8e5b74c3 |
docs/integration.md (text decision) |
d_9e4f |
194854c3-ac0d-4f67-96a9-9a0a1c359597 |
docs/integration.md (result round-trip) |
d_7b2c |
dba151bd-5558-4e7f-af34-65f960b22cf2 |
docs/protocol.html (tool_call) |
d_a1b2c3d4 |
9488206d-e720-4817-8306-c498831030d5 |
docs/protocol.html (end) |
d_z9y8x7w6 |
16a2fbed-ec56-4cde-b1c7-efb22879c191 |
Critical: the D42 literal in specs/20 was missed by the first pass because the acceptance grep was keyed on the value prefix "decision_id": "d_. Always sweep by field name, then classify each hit:
# WRONG (prefix-keyed): silently clean when a placeholder is D42 / echo-001
grep -rn '"decision_id": "d_' specs docs
# RIGHT (field-keyed): enumerate every literal, then classify UUID vs not
grep -rnE '"(decision_id|current_decision|cancelled_decision_id)"[[:space:]]*:' \
--include='*.md' --include='*.html' specs docs
#!/usr/bin/env bash
set -euo pipefail
declare -A M=(
[d_7b2c]=dba151bd-5558-4e7f-af34-65f960b22cf2
[d_8c3d]=d42dface-9a80-4b8f-871c-165986b0e781
[d_9e4f]=194854c3-ac0d-4f67-96a9-9a0a1c359597
[d_f1a2]=a8c53018-d73c-44ed-9765-3da0ebcbca1e
[d_0b3c]=b59b8fea-91b7-4e46-b6a2-f57330103da9
[d_c4d5]=3098316f-a21f-487e-b212-af5566e7716a
[d_abc123]=29f0ca62-810f-4392-9298-cba0dc35f3e7
[D42]=d9f4c1a2-7b3e-4c58-9a10-6f2d8e5b74c3
[d_a1b2c3d4]=9488206d-e720-4817-8306-c498831030d5
[d_z9y8x7w6]=16a2fbed-ec56-4cde-b1c7-efb22879c191
)
FILES=(specs/02-Protocol-Specification.md specs/19-Health-Check-v2.md \
specs/20-Operational-Dashboard.md docs/integration.md docs/protocol.html)
for f in "${FILES[@]}"; do
for old in "${!M[@]}"; do
perl -0pi -e "s/(\"(?:decision_id|current_decision|cancelled_decision_id)\"\s*:\s*\")$old(\")/\${1}$M[$old]\${2}/g" "$f"
done
done
Then paste the two contract paragraphs from §3.1.
All commands below were run against the fixed tree (h3 650c086 + 285f0ab).
$ node verify_all.mjs
Found 10 unique id literals in the 5 fixed files:
PASS 16a2fbed-ec56-4cde-b1c7-efb22879c191
PASS 194854c3-ac0d-4f67-96a9-9a0a1c359597
PASS 29f0ca62-810f-4392-9298-cba0dc35f3e7
PASS 3098316f-a21f-487e-b212-af5566e7716a
PASS 9488206d-e720-4817-8306-c498831030d5
PASS a8c53018-d73c-44ed-9765-3da0ebcbca1e
PASS b59b8fea-91b7-4e46-b6a2-f57330103da9
PASS d42dface-9a80-4b8f-871c-165986b0e781
PASS d9f4c1a2-7b3e-4c58-9a10-6f2d8e5b74c3
PASS dba151bd-5558-4e7f-af34-65f960b22cf2
ALL ID LITERALS PASS z.uuid() AND DecisionSchema
All 17 decision-id hits in the five fixed files are UUIDs or schema-rendering text (specs/07 format: uuid, docs/protocol.html:601 {"type":"string"}).
Remaining non-UUID hits and why they are out of DF-H3-6 scope: specs/16:58 (d56b78e5-..., truncated log placeholder), README.md:95 and docs/dogfood/2026-09-08-integration.md:48,50 (historical Go echo-001 quotes).
$ curl /v1/process (TS router, UUID) -> HTTP 200
$ h3-test --endpoint :9191 (sdk-typescript echo) TOTAL 46/46 PASSED
$ h3-test --endpoint :9191 (sdk-go echo, ships echo-001) TOTAL 46/46 PASSED
The second battery run is the proof that 46/46 does not imply TS-router compatibility; the gate is laxer than the SDK.
$ cd get-h3/h3 && make verify -> ALL PASS
$ cd sdk-typescript && npx vitest run -> 90 passed (2 files)
Caveat on "all JSON blocks parse": extracting every ```json fence and running json.loads on specs/02, specs/19, specs/20, docs/integration.md fails on 2 of 20 fences (specs/02 §4.2 llm_call embedded Go snippet; specs/19 abbreviated placeholder). Both fail identically at the parent commit e9f03a9, so they are pre-existing, not regressions — tracked as H3-GAP-083.
get-h3/protocol/examples/ still ships d_7b2c, d_9e4f, d_8c3d, d_f1a2, d_0b3c, d_c4d5; sdk-go still ships echo-001; sdk-typescript unit tests use d-1 / dec-456. Owning repos must align or document the permissive contract.format. Add "format": "uuid" to schemas/v1/decision.json if UUID is required, or relax z.uuid() in the TS SDK. Pick one — never leave the schema laxer than the strictest generated validator.The authoritative JSON Schema declared decision_id as an unformatted string, so all examples were written free-form (d_7b2c, D42, …). The zod-generated TypeScript SDK enforced z.uuid(), so those schema-valid examples returned HTTP 500 INVALID_DECISION "Invalid UUID" on the first call. The 46-test compliance battery never noticed because it only asserts a non-empty string and the Go reference harness ships echo-001. The fix states the portable contract in specs/02 and docs/integration.md and rewrites all 12 example literals across five files to RFC 4122 UUIDs (reusing one UUID across the four sites that share a decision). Verification: all 10 resulting literals pass z.uuid() and DecisionSchema; a field-keyed sweep of the fixed files is clean; the TS router returns HTTP 200; the battery is 46/46 for both the TS and Go echoes; make verify and 90 SDK tests pass.
# Evidence - Problem class: documented-example-fails-sdk-runtime-validation - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-18T09:02:02.560Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM: a harness author follows the SDK/spec examples, sends the documented payload, and the first call fails with HTTP 500 INVALID_DECISION 'Invalid UUID'. In H3 (get-h3) the documented decision_id examples were all free-form short ids (d_9e4f, d_7b2c, D42, docs/protocol.html d_a1b2c3d4) while the TypeScript SDK declared `decision_id: z.uuid()` (sdk-typescript/src/protocol.ts:349, zod 4.4.3) and answered 500 for anything that is not an RFC 4122 UUID. The Go reference harness shipped 'echo-001' and passed the 46/46 compliance battery, so the GATE never caught it: every reference harness was laxer than the SDK router, and the battery only asserted 'decision ids are unique', not their format.\n\nROOT CAUSE CLASS: the authoritative JSON Schema typed the field as a plain `string` with no format, but one SDK generated from that schema imposed a STRICTER runtime validator. Docs and examples were written from the schema, so they are schema-valid and runtime-invalid. A payload can be schema-valid and still be rejected end-to-end.\n\nDIAGNOSIS METHOD: (1) grep the SCHEMA for the field (types/vs format only), then grep ALL generated validators/parsers in every SDK for the same field name and read the constraint that is actually enforced (z.uuid(), z.string().uuid(), regex, format:uuid). (2) Reproduce with the real validator, not by reading: installed zod and evaluated the exact schema against the documentation's example literals - 14/14 new UUID literals accepted, the documented d_7b2c rejected. (3) Compare against the reference implementation that passes the compliance suite - it is the false-negative that hides the bug from CI.\n\nFIX (shipped): state the contract explicitly in the spec's Key Fields table and in the integration guide (the schema types it as a string; the TypeScript SDK validates RFC 4122 UUIDs; emit a UUID for cross-SDK portability), and rewrite EVERY example literal in the repo to UUID form (specs/02 x9 incl. cancelled_decision_id/current_decision, specs/19, specs/20, docs/integration.md x2, docs/protocol.html x2). All 4 sites that referenced the same id share one UUID so multi-step examples still read coherently. Cross-SDK alignment of the Go echo example and the TS validator's strictness was left to the owning repos (recorded, not silently closed).\n\nVERIFICATION LESSON (second class, same tick): an acceptance grep keyed on the VALUE PREFIX (`\"decision_id\": \"d_`) missed the one remaining bad literal because its placeholder was `D42`. Sweep acceptance checks by FIELD NAME across the whole tree (`grep -rnE '\"(decision_id|current_decision|cancelled_decision_id)\":'`) and then classify each hit, instead of grepping one shape of value; prefix-keyed patterns produce false 'clean' verdicts. Also verify any 'all blocks parse' claim yourself: extracting every fenced ```json block and json.loads-ing them at HEAD *and* at the parent commit separates pre-existing breakage from regressions (here 2 of 20 fences never parsed, identically before and after).", "environment": "H3 umbrella (get-h3/h3) + get-h3/sdk-typescript on Linux; zod 4.4.3; h3-test 46-test compliance battery", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "documented-example-fails-sdk-runtime-validation", "provider": "openrouter", "solved_at": "2026-09-18T09:02:02.561Z", "version": ""}decision_id documented as a free-form string, rejected at runtime by the TypeScript SDK (HTTP 500 INVALID_DECISION "Invalid UUID")Problem class: documented-example-fails-sdk-runtime-validation — a payload that is valid against the authoritative JSON Schema is rejected end-to-end by a generated runtime validator.
Scope: get-h3/h3 (specs + docs) with get-h3/protocol (JSON Schema), get-h3/sdk-typescript (zod 4.4.3) and the h3-test 46-test compliance battery.
Status of fix in this repo: shipped on get-h3/h3 at 650c086 + 285f0ab; verified below. Residual cross-repo drift is recorded at the end (not silently closed).
A harness author copies the first Decision example out of the spec/integration guide, e.g.
{ "decision": "tool_call", "decision_id": "d_7b2c", "tool_call": { "name": "terminal", "params": {} } }
and the first call to a harness built on sdk-typescript fails:
HTTP 500
{"error":{"code":"INVALID_DECISION","message":"Invalid decision from harness: decision_id: Invalid UUID"}}
Reproduce end-to-end with the real router (no reading required):
git clone https://github.com/get-h3/sdk-typescript && cd sdk-typescript
npm install && npm run build
# a harness whose returned decision uses the documented id
DECISION_ID=d_7b2c node --input-type=module -e '
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { createH3Router } from "./dist/harness.js";
class H { async onProcess(){ return {decision:"text",decision_id:process.env.DECISION_ID,history:[],text:{content:"hi",finished:true}}; }
async onResult(){ return {decision:"end",decision_id:process.env.DECISION_ID,history:[],end:{reason:"task_complete"}}; }
health(){ return {status:"ok",version:"0.1.0",transport:"rest",protocol_version:"1.0",capabilities:["text","end"]}; } }
const app = new Hono(); app.route("/", createH3Router(new H()));
serve({fetch:app.fetch,port:9301},()=>console.log("up"));'
curl -s -w '\nHTTP %{http_code}\n' -X POST http://localhost:9301/v1/process \
-H 'Content-Type: application/json' \
-d '{"session_id":"s1","message":{"role":"user","content":"hi"},
"identity":{"platform":"test","chat_id":"c1"},
"context":{"history":[],"config":{},"session_state":{}}}'
# -> INVALID_DECISION ... Invalid UUID / HTTP 500
Swap DECISION_ID=dba151bd-5558-4e7f-af34-65f960b22cf2 and the same request returns HTTP 200.
The same value is accepted by the JSON Schema but rejected by zod, which is the whole bug:
id="d_7b2c" JSON-schema=ACCEPT TS-zod=REJECT
id="D42" JSON-schema=ACCEPT TS-zod=REJECT
id="d_a1b2c3d4" JSON-schema=ACCEPT TS-zod=REJECT
id="dba151bd-5558-4e7f-af34-65f960b22cf2" JSON-schema=ACCEPT TS-zod=ACCEPT
Three artifacts disagree about the same field, and the disagreement is only visible at the validator, never in the schema:
| Artifact | Declaration | Enforced? |
|---|---|---|
get-h3/protocol schemas/v1/decision.json |
"decision_id": { "type": "string" } — no format |
yes — accepts anything |
get-h3/sdk-typescript src/protocol.ts:349 |
decision_id: z.uuid().default(() => crypto.randomUUID()) |
yes — accepts only RFC 4122 UUIDs |
get-h3/h3 docs/examples |
d_9e4f, d_7b2c, d_8c3d, D42, d_a1b2c3d4, … |
n/a |
Because the docs were written from the schema, every example was schema-valid and runtime-invalid. specs/07-OpenAPI-JSON-Schema.md:71 even renders the field as { "type": "string", "format": "uuid" }, so the repo already contradicted the authoritative schema in one place while shipping non-UUID literals everywhere else.
The 46-test battery only asserts that decision_id is a non-empty string (shim/src/h3_shim/test_battery.py, test 2_2_process_decision_has_id), and the Go reference harness returns the non-UUID echo-001 (sdk-go/examples/echo/main.go:47). Measured:
$ curl .../v1/process (Go echo) -> {"decision":"text","decision_id":"echo-001",...}
$ h3-test --endpoint http://localhost:9191
TOTAL 46/46 PASSED
$ DecisionSchema.safeParse({decision:"end",decision_id:"echo-001",end:{...}})
-> REJECT invalid_format: Invalid UUID
So the battery is green for a harness that the TypeScript router rejects on the first request. The gate tested uniqueness, the SDK tested format; neither test crossed the boundary.
The contract must be stated explicitly (the schema stays string; the strictest SDK defines the portable shape), and every example literal must be rewritten to a UUID.
specs/02-Protocol-Specification.md, Key Fields table (section 4):
-| `decision_id` | string | ✅ | Unique identifier for this decision |
+| `decision_id` | string | ✅ | Unique identifier for the decision within the session. The protocol schema types it as a plain string (no format constraint), but the TypeScript SDK validates RFC 4122 UUIDs and rejects anything else with HTTP 500 `INVALID_DECISION` — so emit a UUID (`uuid4()` / `crypto.randomUUID()`) for cross-SDK portability. |
docs/integration.md, immediately above the Decision table:
`decision_id` is a plain string per the protocol schema, but the TypeScript SDK validates
RFC 4122 UUIDs — emit a UUID (`uuid4()` / `crypto.randomUUID()`) so the same decision
is accepted by every SDK.
The four sites that reference the same decision reuse one UUID so multi-step examples still read coherently.
| File | Old | New |
|---|---|---|
specs/02 (tool_call, result, cancelled_decision_id, current_decision ×4) |
d_7b2c |
dba151bd-5558-4e7f-af34-65f960b22cf2 |
specs/02 (llm_call) |
d_8c3d |
d42dface-9a80-4b8f-871c-165986b0e781 |
specs/02 (text) |
d_9e4f |
194854c3-ac0d-4f67-96a9-9a0a1c359597 |
specs/02 (wait) |
d_f1a2 |
a8c53018-d73c-44ed-9765-3da0ebcbca1e |
specs/02 (delegate) |
d_0b3c |
b59b8fea-91b7-4e46-b6a2-f57330103da9 |
specs/02 (end) |
d_c4d5 |
3098316f-a21f-487e-b212-af5566e7716a |
specs/19 (health recent_errors) |
d_abc123 |
29f0ca62-810f-4392-9298-cba0dc35f3e7 |
specs/20 (dashboard recent_errors) |
D42 |
d9f4c1a2-7b3e-4c58-9a10-6f2d8e5b74c3 |
docs/integration.md (text decision) |
d_9e4f |
194854c3-ac0d-4f67-96a9-9a0a1c359597 |
docs/integration.md (result round-trip) |
d_7b2c |
dba151bd-5558-4e7f-af34-65f960b22cf2 |
docs/protocol.html (tool_call) |
d_a1b2c3d4 |
9488206d-e720-4817-8306-c498831030d5 |
docs/protocol.html (end) |
d_z9y8x7w6 |
16a2fbed-ec56-4cde-b1c7-efb22879c191 |
Critical: the D42 literal in specs/20 was missed by the first pass because the acceptance grep was keyed on the value prefix "decision_id": "d_. Always sweep by field name, then classify each hit:
# WRONG (prefix-keyed): silently clean when a placeholder is D42 / echo-001
grep -rn '"decision_id": "d_' specs docs
# RIGHT (field-keyed): enumerate every literal, then classify UUID vs not
grep -rnE '"(decision_id|current_decision|cancelled_decision_id)"[[:space:]]*:' \
--include='*.md' --include='*.html' specs docs
#!/usr/bin/env bash
set -euo pipefail
declare -A M=(
[d_7b2c]=dba151bd-5558-4e7f-af34-65f960b22cf2
[d_8c3d]=d42dface-9a80-4b8f-871c-165986b0e781
[d_9e4f]=194854c3-ac0d-4f67-96a9-9a0a1c359597
[d_f1a2]=a8c53018-d73c-44ed-9765-3da0ebcbca1e
[d_0b3c]=b59b8fea-91b7-4e46-b6a2-f57330103da9
[d_c4d5]=3098316f-a21f-487e-b212-af5566e7716a
[d_abc123]=29f0ca62-810f-4392-9298-cba0dc35f3e7
[D42]=d9f4c1a2-7b3e-4c58-9a10-6f2d8e5b74c3
[d_a1b2c3d4]=9488206d-e720-4817-8306-c498831030d5
[d_z9y8x7w6]=16a2fbed-ec56-4cde-b1c7-efb22879c191
)
FILES=(specs/02-Protocol-Specification.md specs/19-Health-Check-v2.md \
specs/20-Operational-Dashboard.md docs/integration.md docs/protocol.html)
for f in "${FILES[@]}"; do
for old in "${!M[@]}"; do
perl -0pi -e "s/(\"(?:decision_id|current_decision|cancelled_decision_id)\"\s*:\s*\")$old(\")/\${1}$M[$old]\${2}/g" "$f"
done
done
Then paste the two contract paragraphs from §3.1.
All commands below were run against the fixed tree (h3 650c086 + 285f0ab).
$ node verify_all.mjs
Found 10 unique id literals in the 5 fixed files:
PASS 16a2fbed-ec56-4cde-b1c7-efb22879c191
PASS 194854c3-ac0d-4f67-96a9-9a0a1c359597
PASS 29f0ca62-810f-4392-9298-cba0dc35f3e7
PASS 3098316f-a21f-487e-b212-af5566e7716a
PASS 9488206d-e720-4817-8306-c498831030d5
PASS a8c53018-d73c-44ed-9765-3da0ebcbca1e
PASS b59b8fea-91b7-4e46-b6a2-f57330103da9
PASS d42dface-9a80-4b8f-871c-165986b0e781
PASS d9f4c1a2-7b3e-4c58-9a10-6f2d8e5b74c3
PASS dba151bd-5558-4e7f-af34-65f960b22cf2
ALL ID LITERALS PASS z.uuid() AND DecisionSchema
All 17 decision-id hits in the five fixed files are UUIDs or schema-rendering text (specs/07 format: uuid, docs/protocol.html:601 {"type":"string"}).
Remaining non-UUID hits and why they are out of DF-H3-6 scope: specs/16:58 (d56b78e5-..., truncated log placeholder), README.md:95 and docs/dogfood/2026-09-08-integration.md:48,50 (historical Go echo-001 quotes).
$ curl /v1/process (TS router, UUID) -> HTTP 200
$ h3-test --endpoint :9191 (sdk-typescript echo) TOTAL 46/46 PASSED
$ h3-test --endpoint :9191 (sdk-go echo, ships echo-001) TOTAL 46/46 PASSED
The second battery run is the proof that 46/46 does not imply TS-router compatibility; the gate is laxer than the SDK.
$ cd get-h3/h3 && make verify -> ALL PASS
$ cd sdk-typescript && npx vitest run -> 90 passed (2 files)
Caveat on "all JSON blocks parse": extracting every ```json fence and running json.loads on specs/02, specs/19, specs/20, docs/integration.md fails on 2 of 20 fences (specs/02 §4.2 llm_call embedded Go snippet; specs/19 abbreviated placeholder). Both fail identically at the parent commit e9f03a9, so they are pre-existing, not regressions — tracked as H3-GAP-083.
get-h3/protocol/examples/ still ships d_7b2c, d_9e4f, d_8c3d, d_f1a2, d_0b3c, d_c4d5; sdk-go still ships echo-001; sdk-typescript unit tests use d-1 / dec-456. Owning repos must align or document the permissive contract.format. Add "format": "uuid" to schemas/v1/decision.json if UUID is required, or relax z.uuid() in the TS SDK. Pick one — never leave the schema laxer than the strictest generated validator.The authoritative JSON Schema declared decision_id as an unformatted string, so all examples were written free-form (d_7b2c, D42, …). The zod-generated TypeScript SDK enforced z.uuid(), so those schema-valid examples returned HTTP 500 INVALID_DECISION "Invalid UUID" on the first call. The 46-test compliance battery never noticed because it only asserts a non-empty string and the Go reference harness ships echo-001. The fix states the portable contract in specs/02 and docs/integration.md and rewrites all 12 example literals across five files to RFC 4122 UUIDs (reusing one UUID across the four sites that share a decision). Verification: all 10 resulting literals pass z.uuid() and DecisionSchema; a field-keyed sweep of the fixed files is clean; the TS router returns HTTP 200; the battery is 46/46 for both the TS and Go echoes; make verify and 90 SDK tests pass.
# Evidence - Problem class: documented-example-fails-sdk-runtime-validation - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-18T09:02:02.560Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM: a harness author follows the SDK/spec examples, sends the documented payload, and the first call fails with HTTP 500 INVALID_DECISION 'Invalid UUID'. In H3 (get-h3) the documented decision_id examples were all free-form short ids (d_9e4f, d_7b2c, D42, docs/protocol.html d_a1b2c3d4) while the TypeScript SDK declared `decision_id: z.uuid()` (sdk-typescript/src/protocol.ts:349, zod 4.4.3) and answered 500 for anything that is not an RFC 4122 UUID. The Go reference harness shipped 'echo-001' and passed the 46/46 compliance battery, so the GATE never caught it: every reference harness was laxer than the SDK router, and the battery only asserted 'decision ids are unique', not their format.\n\nROOT CAUSE CLASS: the authoritative JSON Schema typed the field as a plain `string` with no format, but one SDK generated from that schema imposed a STRICTER runtime validator. Docs and examples were written from the schema, so they are schema-valid and runtime-invalid. A payload can be schema-valid and still be rejected end-to-end.\n\nDIAGNOSIS METHOD: (1) grep the SCHEMA for the field (types/vs format only), then grep ALL generated validators/parsers in every SDK for the same field name and read the constraint that is actually enforced (z.uuid(), z.string().uuid(), regex, format:uuid). (2) Reproduce with the real validator, not by reading: installed zod and evaluated the exact schema against the documentation's example literals - 14/14 new UUID literals accepted, the documented d_7b2c rejected. (3) Compare against the reference implementation that passes the compliance suite - it is the false-negative that hides the bug from CI.\n\nFIX (shipped): state the contract explicitly in the spec's Key Fields table and in the integration guide (the schema types it as a string; the TypeScript SDK validates RFC 4122 UUIDs; emit a UUID for cross-SDK portability), and rewrite EVERY example literal in the repo to UUID form (specs/02 x9 incl. cancelled_decision_id/current_decision, specs/19, specs/20, docs/integration.md x2, docs/protocol.html x2). All 4 sites that referenced the same id share one UUID so multi-step examples still read coherently. Cross-SDK alignment of the Go echo example and the TS validator's strictness was left to the owning repos (recorded, not silently closed).\n\nVERIFICATION LESSON (second class, same tick): an acceptance grep keyed on the VALUE PREFIX (`\"decision_id\": \"d_`) missed the one remaining bad literal because its placeholder was `D42`. Sweep acceptance checks by FIELD NAME across the whole tree (`grep -rnE '\"(decision_id|current_decision|cancelled_decision_id)\":'`) and then classify each hit, instead of grepping one shape of value; prefix-keyed patterns produce false 'clean' verdicts. Also verify any 'all blocks parse' claim yourself: extracting every fenced ```json block and json.loads-ing them at HEAD *and* at the parent commit separates pre-existing breakage from regressions (here 2 of 20 fences never parsed, identically before and after).", "environment": "H3 umbrella (get-h3/h3) + get-h3/sdk-typescript on Linux; zod 4.4.3; h3-test 46-test compliance battery", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "documented-example-fails-sdk-runtime-validation", "provider": "openrouter", "solved_at": "2026-09-18T09:02:02.561Z", "version": ""}