Three independent implementations of the third-generation Hydra
client — Rust + Python + Go — all produce byte-for-byte identical
BLAKE3 input/output hashes against the same 9-vector conformance
suite. Cross-language conformance is what makes the Hydra-client
surface a real open standard rather than a Rust house format.
What ships:
conformance/call-reports.json — 5 dispatch + 4 SHACL-validation
vectors. The Rust producer is
the oracle (regenerated via
examples/gen_conformance_vectors.rs).
clients/python/jclaw_hydra/ — Python reference client. Package
layout for `from jclaw_hydra
import HydraClient`. Uses the
blake3 PyPI package for BLAKE3.
Conformance test at
clients/python/tests/test_conformance.py:
9/9 PASS.
clients/go/ — Go reference client. Importable
as `jclawhydra`. Uses
lukechampine.com/blake3.
Conformance via `go test ./...`:
9/9 PASS across TestCallReportsConformance
+ TestValidationConformance.
examples/gen_conformance_vectors.rs — Rust regenerator. Produces
call-reports.json from the
canonical Rust client; the
other implementations
verify against this output.
conformance/README.md — vector description, how to run
the three implementations, scope.
The clients implement the same surface verbatim:
- parse Hydra ApiDocumentation from JSON-LD
- find operation by jc_tool_id / @id / title
- validate input against the linked SHACL shape (open-world
default if no shape registered; #Nothing-expects skips)
- dispatch via Transport — echo-mode MockTransport ships as the
test reference; transport returns { "echo": <input> } verbatim
(matches Rust core; no "op" sidecar like the WASM demo wrapper)
- canonical-JSON serialise the input + body (lexically-sorted
keys, no whitespace) and BLAKE3-hash → hex
- return CallReport with tool_id, status, input_hash, output_hash,
status_matches_contract, body, touch{tool_id, joules_uj,
energy_provenance}
The hashes match because the canonical-JSON form matches — that's
the spec primitive. The body match proves the MockTransport
agrees too. The status_matches_contract bit verifies the three
agree on how to walk an Operation's statusCodes menu.
Validation reports verify the same conforms-bit across the four
SHACL cases the conformance file declares: well-shaped input,
missing required field, bad enum, and open-world skip for an op
with no expects-shape.
Workspace: 107 native crates (+0; clients/go and clients/python
live outside Cargo), 2,635 lib tests pass, 0 failures.
Next wave-23 step: #3 — carry the vocab + SHACL pattern into the
four sister standards (ARL, OpenPay, Smart Byte, EOC, WAI) so the
whole TX-Science quintet speaks Gen-3 with stable IRIs.
320 lines
8.9 KiB
JSON
320 lines
8.9 KiB
JSON
{
|
|
"api": {
|
|
"@context": {
|
|
"ApiDocumentation": "hydra:ApiDocumentation",
|
|
"Class": "hydra:Class",
|
|
"Operation": "hydra:Operation",
|
|
"Status": "hydra:Status",
|
|
"SupportedProperty": "hydra:SupportedProperty",
|
|
"code": "hydra:code",
|
|
"description": "hydra:description",
|
|
"entrypoint": {
|
|
"@id": "hydra:entrypoint",
|
|
"@type": "@id"
|
|
},
|
|
"expects": {
|
|
"@id": "hydra:expects",
|
|
"@type": "@id"
|
|
},
|
|
"hydra": "http://www.w3.org/ns/hydra/core#",
|
|
"jc": "https://jouleclaw.transaction.science/vocab/v1#",
|
|
"jc_mutating": {
|
|
"@id": "jc:mutating",
|
|
"@type": "xsd:boolean"
|
|
},
|
|
"jc_tool_id": {
|
|
"@id": "jc:toolId",
|
|
"@type": "xsd:string"
|
|
},
|
|
"method": "hydra:method",
|
|
"property": {
|
|
"@id": "hydra:property",
|
|
"@type": "@id"
|
|
},
|
|
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
|
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
|
"readable": "hydra:readable",
|
|
"required": "hydra:required",
|
|
"returns": {
|
|
"@id": "hydra:returns",
|
|
"@type": "@id"
|
|
},
|
|
"statusCodes": {
|
|
"@id": "hydra:statusCodes"
|
|
},
|
|
"supportedClass": {
|
|
"@id": "hydra:supportedClass",
|
|
"@type": "@id"
|
|
},
|
|
"supportedOperation": {
|
|
"@id": "hydra:supportedOperation",
|
|
"@type": "@id"
|
|
},
|
|
"supportedProperty": {
|
|
"@id": "hydra:supportedProperty",
|
|
"@type": "@id"
|
|
},
|
|
"title": "hydra:title",
|
|
"writable": "hydra:writable",
|
|
"xsd": "http://www.w3.org/2001/XMLSchema#"
|
|
},
|
|
"@id": "https://example.com/api",
|
|
"@type": [
|
|
"ApiDocumentation"
|
|
],
|
|
"description": "Cross-language Hydra-client conformance vectors.",
|
|
"supportedClass": [
|
|
{
|
|
"@id": "_:JouleClawMcpServer",
|
|
"@type": [
|
|
"Class"
|
|
],
|
|
"description": "A JouleClaw tool surface carrying the operations published below.",
|
|
"supportedOperation": [
|
|
{
|
|
"@id": "_:op_jouleclaw_list_nodes",
|
|
"@type": [
|
|
"Operation"
|
|
],
|
|
"description": "List nodes",
|
|
"expects": "http://www.w3.org/2002/07/owl#Nothing",
|
|
"jc_mutating": false,
|
|
"jc_tool_id": "jouleclaw:list_nodes",
|
|
"method": "GET",
|
|
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
|
|
"statusCodes": [
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 200,
|
|
"description": "OK"
|
|
},
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 400,
|
|
"description": "Bad Request"
|
|
},
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 500,
|
|
"description": "Internal Server Error"
|
|
}
|
|
],
|
|
"title": "jouleclaw:list_nodes"
|
|
},
|
|
{
|
|
"@id": "_:op_jouleclaw_append_child",
|
|
"@type": [
|
|
"Operation"
|
|
],
|
|
"description": "Mutate node",
|
|
"expects": "https://example.com/Tool#AppendInput",
|
|
"jc_mutating": true,
|
|
"jc_tool_id": "jouleclaw:append_child",
|
|
"method": "POST",
|
|
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
|
|
"statusCodes": [
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 200,
|
|
"description": "OK"
|
|
},
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 400,
|
|
"description": "Bad Request"
|
|
},
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 500,
|
|
"description": "Internal Server Error"
|
|
}
|
|
],
|
|
"title": "jouleclaw:append_child"
|
|
},
|
|
{
|
|
"@id": "_:op_jouleclaw_noop",
|
|
"@type": [
|
|
"Operation"
|
|
],
|
|
"description": "Parameterless",
|
|
"expects": "http://www.w3.org/2002/07/owl#Nothing",
|
|
"jc_mutating": false,
|
|
"jc_tool_id": "jouleclaw:noop",
|
|
"method": "GET",
|
|
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
|
|
"statusCodes": [
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 200,
|
|
"description": "OK"
|
|
},
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 400,
|
|
"description": "Bad Request"
|
|
},
|
|
{
|
|
"@type": [
|
|
"Status"
|
|
],
|
|
"code": 500,
|
|
"description": "Internal Server Error"
|
|
}
|
|
],
|
|
"title": "jouleclaw:noop"
|
|
}
|
|
],
|
|
"title": "JouleClaw MCP server"
|
|
}
|
|
],
|
|
"title": "Conformance test"
|
|
},
|
|
"call_reports": [
|
|
{
|
|
"expected": {
|
|
"body": {
|
|
"echo": {}
|
|
},
|
|
"input_hash": "6e46dd10defc9b56c29a6ec56b508c21f54c08192194e4df25bf36f0c9c3c279",
|
|
"output_hash": "77278ccf46f29dfffe609f294474287740eed318bcb9fdf725d828586faae56d",
|
|
"status": 200,
|
|
"status_matches_contract": true,
|
|
"tool_id": "jouleclaw:list_nodes"
|
|
},
|
|
"input": {},
|
|
"label": "list_nodes_empty",
|
|
"operation": "jouleclaw:list_nodes"
|
|
},
|
|
{
|
|
"expected": {
|
|
"body": {
|
|
"echo": {
|
|
"completed": true
|
|
}
|
|
},
|
|
"input_hash": "6ddef95fc91972d07cbf56b0bc2ac94d8ef02bae51604822d5c9cc47817cb58d",
|
|
"output_hash": "307329d2fb010a49e9e6eb8acd7baf8c43d4da471fab8ce4ede73e04db2604f2",
|
|
"status": 200,
|
|
"status_matches_contract": true,
|
|
"tool_id": "jouleclaw:list_nodes"
|
|
},
|
|
"input": {
|
|
"completed": true
|
|
},
|
|
"label": "list_nodes_with_filter",
|
|
"operation": "jouleclaw:list_nodes"
|
|
},
|
|
{
|
|
"expected": {
|
|
"body": {
|
|
"echo": {
|
|
"kind": "blob",
|
|
"parent": "n1"
|
|
}
|
|
},
|
|
"input_hash": "baf3081ebc9851a0e3956f18b2ed3897e77631d9db52e40377f6adf2dddc9650",
|
|
"output_hash": "01a46ba1459176c427124780b57a296b6ae551566703efc01a75e3a090fa21bf",
|
|
"status": 200,
|
|
"status_matches_contract": true,
|
|
"tool_id": "jouleclaw:append_child"
|
|
},
|
|
"input": {
|
|
"kind": "blob",
|
|
"parent": "n1"
|
|
},
|
|
"label": "append_child_blob",
|
|
"operation": "jouleclaw:append_child"
|
|
},
|
|
{
|
|
"expected": {
|
|
"body": {
|
|
"echo": {
|
|
"kind": "text",
|
|
"parent": "n2"
|
|
}
|
|
},
|
|
"input_hash": "ca17ab517b1dc7242c12425156c7abe2fa603336268ccc3ccafb109f6888b5f1",
|
|
"output_hash": "2d3bcddb5d464cc9b136fe0e2178da564b91d3ec05040511330a058b7ecbe2da",
|
|
"status": 200,
|
|
"status_matches_contract": true,
|
|
"tool_id": "jouleclaw:append_child"
|
|
},
|
|
"input": {
|
|
"kind": "text",
|
|
"parent": "n2"
|
|
},
|
|
"label": "append_child_text",
|
|
"operation": "jouleclaw:append_child"
|
|
},
|
|
{
|
|
"expected": {
|
|
"body": {
|
|
"echo": {}
|
|
},
|
|
"input_hash": "6e46dd10defc9b56c29a6ec56b508c21f54c08192194e4df25bf36f0c9c3c279",
|
|
"output_hash": "77278ccf46f29dfffe609f294474287740eed318bcb9fdf725d828586faae56d",
|
|
"status": 200,
|
|
"status_matches_contract": true,
|
|
"tool_id": "jouleclaw:noop"
|
|
},
|
|
"input": {},
|
|
"label": "noop_parameterless",
|
|
"operation": "jouleclaw:noop"
|
|
}
|
|
],
|
|
"schema": "hydra-client/1",
|
|
"shapes_source": "minimal shapes for https://example.com/Tool#AppendInput; see gen_conformance_vectors.rs for the exact ShapeGraph used.",
|
|
"spec": "JouleClaw Hydra Client v1 — cross-language conformance vectors",
|
|
"validation_reports": [
|
|
{
|
|
"expected_conforms": true,
|
|
"input": {
|
|
"kind": "blob",
|
|
"parent": "n1"
|
|
},
|
|
"label": "append_child_valid",
|
|
"operation": "jouleclaw:append_child"
|
|
},
|
|
{
|
|
"expected_conforms": false,
|
|
"input": {
|
|
"kind": "blob"
|
|
},
|
|
"label": "append_child_missing_field",
|
|
"operation": "jouleclaw:append_child"
|
|
},
|
|
{
|
|
"expected_conforms": false,
|
|
"input": {
|
|
"kind": "video",
|
|
"parent": "n"
|
|
},
|
|
"label": "append_child_bad_enum",
|
|
"operation": "jouleclaw:append_child"
|
|
},
|
|
{
|
|
"expected_conforms": true,
|
|
"input": {
|
|
"random": 1
|
|
},
|
|
"label": "list_nodes_anything_passes",
|
|
"operation": "jouleclaw:list_nodes"
|
|
}
|
|
]
|
|
}
|