From 729b05f4317de75be1b5df2ed58979fd3c914865 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 11 May 2026 15:11:53 +0100 Subject: [PATCH] Publish CultNet mutation contract schema --- ...net.document-mutation-contract.schema.json | 40 +++++++++++ .../Contracts/cultnet.hello.schema.json | 6 ++ .../CultNetSchemaMessages.cs | 67 +++++++++++++++++++ .../CultNetSchemaRegistry.cs | 6 ++ 4 files changed, 119 insertions(+) create mode 100644 src/GameCult.Networking/Contracts/cultnet.document-mutation-contract.schema.json diff --git a/src/GameCult.Networking/Contracts/cultnet.document-mutation-contract.schema.json b/src/GameCult.Networking/Contracts/cultnet.document-mutation-contract.schema.json new file mode 100644 index 00000000..e444fef0 --- /dev/null +++ b/src/GameCult.Networking/Contracts/cultnet.document-mutation-contract.schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultnet.document-mutation-contract.schema.json", + "title": "CultNet Document Mutation Contract", + "type": "object", + "required": [ + "documentType", + "operations", + "authority" + ], + "additionalProperties": false, + "properties": { + "documentType": { "type": "string", "minLength": 1 }, + "payloadSchemaVersion": { "type": "string", "minLength": 1 }, + "operations": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "enum": ["snapshot", "documentPut", "documentDelete", "intentSubmit", "receiptWatch"] + } + }, + "authority": { + "type": "string", + "enum": ["readOnly", "localUser", "coordinator", "runtime", "denied"] + }, + "intentDocumentTypes": { + "type": "array", + "items": { "type": "string", "minLength": 1 } + }, + "receiptDocumentTypes": { + "type": "array", + "items": { "type": "string", "minLength": 1 } + }, + "notes": { + "type": "array", + "items": { "type": "string", "minLength": 1 } + } + } +} diff --git a/src/GameCult.Networking/Contracts/cultnet.hello.schema.json b/src/GameCult.Networking/Contracts/cultnet.hello.schema.json index f15f7452..bced7577 100644 --- a/src/GameCult.Networking/Contracts/cultnet.hello.schema.json +++ b/src/GameCult.Networking/Contracts/cultnet.hello.schema.json @@ -20,6 +20,12 @@ "type": "array", "items": { "type": "string", "minLength": 1 } }, + "supportedMutationContracts": { + "type": "array", + "items": { + "$ref": "./cultnet.document-mutation-contract.schema.json" + } + }, "supportedMessageVersions": { "type": "array", "items": { "type": "string", "minLength": 1 } diff --git a/src/GameCult.Networking/CultNetSchemaMessages.cs b/src/GameCult.Networking/CultNetSchemaMessages.cs index 69ff8694..5281fb79 100644 --- a/src/GameCult.Networking/CultNetSchemaMessages.cs +++ b/src/GameCult.Networking/CultNetSchemaMessages.cs @@ -81,6 +81,69 @@ namespace GameCult.Networking public const string SchemaCatalogResponse = "cultnet.schema_catalog_response.v0"; } + /// + /// Mutation authority owner identifiers advertised through CultNet mutation contracts. + /// + public static class CultNetMutationAuthorities + { + /// + /// The document is inspectable but not writable through CultNet. + /// + public const string ReadOnly = "readOnly"; + /// + /// The local human operator may submit the corresponding mutation intent. + /// + public const string LocalUser = "localUser"; + /// + /// A coordinator-owned Epiphany control surface owns the mutation path. + /// + public const string Coordinator = "coordinator"; + /// + /// The runtime itself may write this document directly. + /// + public const string Runtime = "runtime"; + /// + /// The document should not be mutated through CultNet. + /// + public const string Denied = "denied"; + } + + /// + /// Declares how a document or surface may be inspected and mutated over CultNet. + /// + [MessagePackObject] + public class CultNetDocumentMutationContract + { + /// + /// Gets or sets the stable document type governed by this contract. + /// + [Key("documentType")] public string DocumentType { get; set; } = string.Empty; + /// + /// Gets or sets the payload schema version when the contract governs a versioned document payload. + /// + [Key("payloadSchemaVersion")] public string? PayloadSchemaVersion { get; set; } + /// + /// Gets or sets the CultNet operations this document accepts. + /// + [Key("operations")] public string[] Operations { get; set; } = Array.Empty(); + /// + /// Gets or sets which actor is allowed to drive those operations. + /// + [Key("authority")] public string Authority { get; set; } = CultNetMutationAuthorities.ReadOnly; + /// + /// Gets or sets the intent document types a client may submit to request mutation. + /// + [Key("intentDocumentTypes")] public string[]? IntentDocumentTypes { get; set; } + /// + /// Gets or sets the receipt document types emitted after a successful mutation path. + /// + [Key("receiptDocumentTypes")] public string[]? ReceiptDocumentTypes { get; set; } + /// + /// Gets or sets freeform notes that explain local mutation guardrails or posture. + /// + [Key("notes")] public string[]? Notes { get; set; } + } + /// /// Marker interface for the explicit modern CultNet schema-v0 message family. /// @@ -127,6 +190,10 @@ namespace GameCult.Networking /// [Key("supportedDocumentTypes")] public string[]? SupportedDocumentTypes { get; set; } /// + /// Gets or sets the supported mutation contracts. + /// + [Key("supportedMutationContracts")] public CultNetDocumentMutationContract[]? SupportedMutationContracts { get; set; } + /// /// Gets or sets the supported message versions. /// [Key("supportedMessageVersions")] public string[]? SupportedMessageVersions { get; set; } diff --git a/src/GameCult.Networking/CultNetSchemaRegistry.cs b/src/GameCult.Networking/CultNetSchemaRegistry.cs index 90c2a273..025afa3f 100644 --- a/src/GameCult.Networking/CultNetSchemaRegistry.cs +++ b/src/GameCult.Networking/CultNetSchemaRegistry.cs @@ -260,6 +260,12 @@ namespace GameCult.Networking WireContracts = new[] { CultNetWireContracts.SchemaV0 } }, new SchemaResourceSpec + { + FileName = "cultnet.document-mutation-contract.schema.json", + Kind = "shared_contract", + WireContracts = new[] { CultNetWireContracts.SchemaV0 } + }, + new SchemaResourceSpec { FileName = "cultnet.login.schema.json", Kind = "wire_message",