Advertise Python CultNet error contract

This commit is contained in:
Meta Vens 2026-06-14 14:16:41 +01:00
commit 392a54bc80
5 changed files with 23 additions and 1 deletions

View file

@ -35,7 +35,10 @@ CultCache, CultNet, and CultMesh. It is evidence, not confetti.
messages they speak through the same catalog authority. Python callers can
also ingest and filter remote schema catalog responses through typed
`CultNetSchemaCatalog` and `CultNetSchemaDescriptor` helpers, including
`CultNetRawClient.sync_schema_catalog(...)`.
`CultNetRawClient.sync_schema_catalog(...)`. The catalog includes
`cultnet.error.v0`, and the local server advertises that version in hello
responses because oversized snapshots and other peer failures use that
contract on the wire.
- Python CultNet shard catalog:
Provides typed `CultNetShardCatalog` and `CultNetShardDescriptor` helpers for
ingesting, filtering, and emitting shard topology responses, plus

View file

@ -227,6 +227,7 @@ def _check_local_cultmesh_wire_smoke() -> dict[str, Any]:
failures.append("hello_runtime")
supported_versions = set(hello_response.get("supportedMessageVersions") or ())
for schema_version in (
"cultnet.error.v0",
"cultnet.document_put_raw.v0",
"cultnet.document_delete.v0",
"cultnet.shard_log_request.v0",

View file

@ -268,6 +268,7 @@ class CultMeshLocalServer:
],
"supportedMessageVersions": [
"cultnet.hello.v0",
"cultnet.error.v0",
"cultnet.schema_catalog_request.v0",
"cultnet.snapshot_request.v0",
"cultnet.database_subscribe.v0",

View file

@ -12,6 +12,7 @@ PEER_EXCHANGE_REQUEST = "cultmesh.peer_exchange_request.v0"
WIRE_MESSAGE_SCHEMA_VERSIONS = (
("cultnet.hello.v0", "CultNet Hello Message", f"{CULTNET_SCHEMA_BASE}/cultnet.hello.schema.json"),
("cultnet.error.v0", "CultNet Error Message", f"{CULTNET_SCHEMA_BASE}/cultnet.error.schema.json"),
("cultnet.document_delete.v0", "CultNet Document Delete Message", f"{CULTNET_SCHEMA_BASE}/cultnet.document-delete.schema.json"),
("cultnet.document_put_raw.v0", "CultNet Raw Document Put Message", f"{CULTNET_SCHEMA_BASE}/cultnet.document-put-raw.schema.json"),
("cultnet.snapshot_request.v0", "CultNet Snapshot Request Message", f"{CULTNET_SCHEMA_BASE}/cultnet.snapshot-request.schema.json"),
@ -182,6 +183,7 @@ def wire_message_schema_json(schema_id: str, title: str, schema_version: str) ->
def wire_message_required_fields(schema_version: str) -> list[str]:
required = {
"cultnet.hello.v0": ["schemaVersion", "runtimeId"],
"cultnet.error.v0": ["schemaVersion", "error"],
"cultnet.document_delete.v0": ["schemaVersion", "messageId", "schemaId", "recordKey"],
"cultnet.document_put_raw.v0": ["schemaVersion", "messageId", "document"],
"cultnet.snapshot_request.v0": ["schemaVersion", "messageId"],
@ -256,6 +258,12 @@ def wire_message_schema_properties(schema_version: str) -> dict[str, Any]:
"supportedMessageVersions": string_array,
"supportsSchemaCatalog": {"type": "boolean"},
},
"cultnet.error.v0": {
"messageId": common["messageId"],
"error": {"type": "string"},
"code": {"type": "string"},
"details": {"type": "object", "additionalProperties": True},
},
"cultnet.document_delete.v0": {
**common,
},

View file

@ -1053,6 +1053,7 @@ class CultCacheTests(unittest.TestCase):
descriptors = wire_message_schema_descriptors(include_schema_json=True)
by_version = {descriptor["schemaVersion"]: descriptor for descriptor in descriptors}
for schema_version in [
"cultnet.error.v0",
"cultnet.document_delete.v0",
"cultnet.database_change_raw.v0",
"cultnet.shard_log_response.v0",
@ -1072,6 +1073,11 @@ class CultCacheTests(unittest.TestCase):
)
self.assertEqual(delete_schema["properties"]["recordKey"]["type"], "string")
error_schema = json.loads(by_version["cultnet.error.v0"]["schemaJson"])
self.assertEqual(error_schema["required"], ["schemaVersion", "error"])
self.assertEqual(error_schema["properties"]["error"]["type"], "string")
self.assertIn("details", error_schema["properties"])
change_schema = json.loads(by_version["cultnet.database_change_raw.v0"]["schemaJson"])
self.assertEqual(change_schema["properties"]["changeKind"]["enum"], ["added", "updated", "removed"])
self.assertIn("document", change_schema["properties"])
@ -3077,6 +3083,7 @@ class CultCacheTests(unittest.TestCase):
self.assertEqual(hello_response["runtimeId"], "mesh-server")
self.assertEqual(hello_response["displayName"], "Mesh Server")
self.assertIn("cultnet.database_subscribe.v0", hello_response["supportedMessageVersions"])
self.assertIn("cultnet.error.v0", hello_response["supportedMessageVersions"])
self.assertIn("cultnet.document_put_raw.v0", hello_response["supportedMessageVersions"])
self.assertIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"])
self.assertEqual(hello_response["supportedMutationContracts"][0]["documentType"], "mesh.server_note")
@ -3087,9 +3094,11 @@ class CultCacheTests(unittest.TestCase):
self.assertIn("cultnet.document_delete.v0", schema_response["schemas"][0]["wireContracts"])
self.assertIn("cultnet.shard_log_response.v0", schema_response["schemas"][0]["wireContracts"])
wire_descriptors = {schema["schemaVersion"]: schema for schema in wire_schema_response["schemas"]}
self.assertEqual(wire_descriptors["cultnet.error.v0"]["kind"], "wire_message")
self.assertEqual(wire_descriptors["cultnet.document_put_raw.v0"]["kind"], "wire_message")
self.assertIn("schemaJson", wire_descriptors["cultnet.document_put_raw.v0"])
self.assertIn("cultmesh.peer_exchange_response.v0", wire_descriptors)
self.assertIn("cultnet.error.v0", {descriptor.schema_version for descriptor in synced_wire_descriptors})
self.assertIn("cultnet.document_put_raw.v0", {descriptor.schema_version for descriptor in synced_wire_descriptors})
self.assertIsNotNone(synced_schema_catalog.get("https://github.com/GameCult/cultnet-ts/contracts/cultnet.document-put-raw.schema.json"))
self.assertEqual(snapshot_response["documents"][0]["recordKey"], "note:1")