CultLib/src/GameCult.Networking/CultNetSchemaMessages.cs
Meta Vens cbd3b4f3ce CultNet: a withdrawn hop subscription is refused with a typed error and its rows are withdrawn
Reconcile's withdrawal sent an untyped error with no subscription id and left the
peer holding the rows the subscription had delivered. It now sends removals for
those rows, then a variant_unsupported error whose details carry
field "subscriptionId" and the id (the existing details slots; no new wire key).
The subscribe and per-change paths use the same code. The error schema and the
Rust CultNetErrorCode accept variant_unsupported, so a Rust peer decodes it
instead of refusing an unknown code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 10:12:20 +02:00

1781 lines
78 KiB
C#

using System;
using MessagePack;
namespace GameCult.Networking
{
/// <summary>
/// Shared wire-contract identifiers understood by the CultNet family.
/// </summary>
public static class CultNetWireContracts
{
/// <summary>
/// schema v0 contract identifier.
/// </summary>
public const string SchemaV0 = "cultnet.schema.v0";
/// <summary>
/// game cult networking v0 contract identifier.
/// </summary>
public const string GameCultNetworkingV0 = "gamecult.networking.v0";
}
/// <summary>
/// Canonical schema-version strings for the modern CultNet message family.
/// </summary>
public static class CultNetSchemaVersions
{
/// <summary>
/// hello contract identifier.
/// </summary>
public const string Hello = "cultnet.hello.v0";
/// <summary>
/// login contract identifier.
/// </summary>
public const string Login = "cultnet.login.v0";
/// <summary>
/// register contract identifier.
/// </summary>
public const string Register = "cultnet.register.v0";
/// <summary>
/// verify contract identifier.
/// </summary>
public const string Verify = "cultnet.verify.v0";
/// <summary>
/// login success contract identifier.
/// </summary>
public const string LoginSuccess = "cultnet.login_success.v0";
/// <summary>
/// error contract identifier.
/// </summary>
public const string Error = "cultnet.error.v0";
/// <summary>
/// sample change name contract identifier.
/// </summary>
public const string SampleChangeName = "cultnet.sample.change_name.v0";
/// <summary>
/// sample chat contract identifier.
/// </summary>
public const string SampleChat = "cultnet.sample.chat.v0";
/// <summary>
/// Generic typed service operation request contract identifier.
/// </summary>
public const string OperationRequest = "cultnet.operation_request.v0";
/// <summary>
/// Generic typed service operation response contract identifier.
/// </summary>
public const string OperationResponse = "cultnet.operation_response.v0";
/// <summary>
/// document delete contract identifier.
/// </summary>
public const string DocumentDelete = "cultnet.document_delete.v0";
/// <summary>
/// document put raw contract identifier.
/// </summary>
public const string DocumentPutRaw = "cultnet.document_put_raw.v0";
/// <summary>
/// snapshot request contract identifier.
/// </summary>
public const string SnapshotRequest = "cultnet.snapshot_request.v0";
/// <summary>
/// snapshot response raw contract identifier.
/// </summary>
public const string SnapshotResponseRaw = "cultnet.snapshot_response_raw.v0";
/// <summary>
/// typed-selection snapshot request contract identifier (docs/cultnet-selection-cut.md).
/// </summary>
public const string SnapshotRequestV1 = "cultnet.snapshot_request.v1";
/// <summary>
/// typed-selection database subscription request contract identifier (docs/cultnet-selection-cut.md).
/// </summary>
public const string DatabaseSubscribeV1 = "cultnet.database_subscribe.v1";
/// <summary>
/// typed-selection snapshot response contract identifier (docs/cultnet-selection-cut.md).
/// </summary>
public const string SnapshotResponseRawV1 = "cultnet.snapshot_response_raw.v1";
/// <summary>
/// schema catalog request contract identifier.
/// </summary>
public const string SchemaCatalogRequest = "cultnet.schema_catalog_request.v0";
/// <summary>
/// schema catalog response contract identifier.
/// </summary>
public const string SchemaCatalogResponse = "cultnet.schema_catalog_response.v0";
/// <summary>
/// database subscription request contract identifier.
/// </summary>
public const string DatabaseSubscribe = "cultnet.database_subscribe.v0";
/// <summary>
/// database subscription cancel contract identifier.
/// </summary>
public const string DatabaseUnsubscribe = "cultnet.database_unsubscribe.v0";
/// <summary>
/// database subscription change contract identifier.
/// </summary>
public const string DatabaseChangeRaw = "cultnet.database_change_raw.v0";
/// <summary>
/// shard catalog request contract identifier.
/// </summary>
public const string ShardCatalogRequest = "cultnet.shard_catalog_request.v0";
/// <summary>
/// shard catalog response contract identifier.
/// </summary>
public const string ShardCatalogResponse = "cultnet.shard_catalog_response.v0";
/// <summary>
/// shard mutation log request contract identifier.
/// </summary>
public const string ShardLogRequest = "cultnet.shard_log_request.v0";
/// <summary>
/// shard mutation log response contract identifier.
/// </summary>
public const string ShardLogResponse = "cultnet.shard_log_response.v0";
/// <summary>
/// simulation observation gossip contract identifier.
/// </summary>
public const string SimulationObservation = "cultnet.simulation_observation.v0";
/// <summary>
/// simulation consensus candidate gossip contract identifier.
/// </summary>
public const string SimulationConsensusCandidate = "cultnet.simulation_consensus_candidate.v0";
/// <summary>
/// witness artifact bundle document contract identifier.
/// </summary>
public const string WitnessArtifactBundle = "cultnet.witness_artifact_bundle.v0";
/// <summary>
/// CultMesh Verse catalog request contract identifier.
/// </summary>
public const string VerseCatalogRequest = "cultmesh.verse_catalog_request.v0";
/// <summary>
/// CultMesh Verse catalog response contract identifier.
/// </summary>
public const string VerseCatalogResponse = "cultmesh.verse_catalog_response.v0";
/// <summary>CultMesh session identity request contract identifier.</summary>
public const string SessionOpen = "cultmesh.session_open.v2";
/// <summary>CultMesh verified session identity response contract identifier.</summary>
public const string SessionAccepted = "cultmesh.session_accepted.v2";
/// <summary>
/// CultMesh peer exchange request contract identifier.
/// </summary>
public const string PeerExchangeRequest = "cultmesh.peer_exchange_request.v0";
/// <summary>
/// CultMesh peer exchange response contract identifier.
/// </summary>
public const string PeerExchangeResponse = "cultmesh.peer_exchange_response.v0";
/// <summary>
/// CultMesh content chunk request contract identifier.
/// </summary>
public const string ContentChunkRequest = "cultmesh.content_chunk_request.v1";
/// <summary>
/// CultMesh content chunk response contract identifier.
/// </summary>
public const string ContentChunkResponse = "cultmesh.content_chunk_response.v1";
/// <summary>
/// CultMesh ephemeral body read request contract identifier.
/// </summary>
public const string BodyReadRequest = "cultmesh.body_read_request.v1";
/// <summary>
/// CultMesh ephemeral body read response contract identifier.
/// </summary>
public const string BodyReadResponse = "cultmesh.body_read_response.v1";
}
/// <summary>
/// Mutation authority owner identifiers advertised through CultNet mutation contracts.
/// </summary>
public static class CultNetMutationAuthorities
{
/// <summary>
/// The document is inspectable but not writable through CultNet.
/// </summary>
public const string ReadOnly = "readOnly";
/// <summary>
/// The local human operator may submit the corresponding mutation intent.
/// </summary>
public const string LocalUser = "localUser";
/// <summary>
/// A coordinator-owned Epiphany control surface owns the mutation path.
/// </summary>
public const string Coordinator = "coordinator";
/// <summary>
/// The runtime itself may write this document directly.
/// </summary>
public const string Runtime = "runtime";
/// <summary>
/// The document should not be mutated through CultNet.
/// </summary>
public const string Denied = "denied";
}
/// <summary>
/// Declares how a document or surface may be inspected and mutated over CultNet.
/// </summary>
[MessagePackObject]
public class CultNetDocumentMutationContract
{
/// <summary>
/// Gets or sets the stable document type governed by this contract.
/// </summary>
[Key("documentType")] public string DocumentType { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the payload schema version when the contract governs a versioned document payload.
/// </summary>
[Key("payloadSchemaVersion")] public string? PayloadSchemaVersion { get; set; }
/// <summary>
/// Gets or sets the CultNet operations this document accepts.
/// </summary>
[Key("operations")] public string[] Operations { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets which actor is allowed to drive those operations.
/// </summary>
[Key("authority")] public string Authority { get; set; } = CultNetMutationAuthorities.ReadOnly;
/// <summary>
/// Gets or sets the intent document types a client may submit to request mutation.
/// </summary>
[Key("intentDocumentTypes")] public string[]? IntentDocumentTypes { get; set; }
/// <summary>
/// Gets or sets the receipt document types emitted after a successful mutation path.
/// </summary>
[Key("receiptDocumentTypes")] public string[]? ReceiptDocumentTypes { get; set; }
/// <summary>
/// Gets or sets freeform notes that explain local mutation guardrails or posture.
/// </summary>
[Key("notes")] public string[]? Notes { get; set; }
}
/// <summary>
/// Marker interface for the explicit modern CultNet schema-v0 message family.
/// </summary>
public interface ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version carried by this message.
/// </summary>
string SchemaVersion { get; set; }
}
/// <summary>
/// CultNet hello message used to announce a runtime and its supported contracts.
/// </summary>
[MessagePackObject]
public class CultNetHelloMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Hello;
/// <summary>
/// Gets or sets the runtime id.
/// </summary>
[Key("runtimeId")] public string RuntimeId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the runtime kind.
/// </summary>
[Key("runtimeKind")] public string RuntimeKind { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the agent id.
/// </summary>
[Key("agentId")] public string? AgentId { get; set; }
/// <summary>
/// Gets or sets the role.
/// </summary>
[Key("role")] public string? Role { get; set; }
/// <summary>
/// Gets or sets the display name.
/// </summary>
[Key("displayName")] public string? DisplayName { get; set; }
/// <summary>
/// Gets or sets the supported document types.
/// </summary>
[Key("supportedDocumentTypes")] public string[]? SupportedDocumentTypes { get; set; }
/// <summary>
/// Gets or sets the supported mutation contracts.
/// </summary>
[Key("supportedMutationContracts")] public CultNetDocumentMutationContract[]? SupportedMutationContracts { get; set; }
/// <summary>
/// Gets or sets the supported message versions.
/// </summary>
[Key("supportedMessageVersions")] public string[]? SupportedMessageVersions { get; set; }
/// <summary>
/// Gets or sets the transport profiles advertised by this peer.
/// </summary>
[Key("transportProfiles")] public CultNetTransportProfile[]? TransportProfiles { get; set; }
/// <summary>
/// Gets or sets the supports schema catalog.
/// </summary>
[Key("supportsSchemaCatalog")] public bool SupportsSchemaCatalog { get; set; }
}
/// <summary>
/// Describes the transports a runtime can speak.
/// </summary>
[MessagePackObject]
public class CultNetTransportProfile
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = "cultnet.transport_profile.v0";
/// <summary>
/// Gets or sets the runtime id.
/// </summary>
[Key("runtimeId")] public string RuntimeId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the transport descriptors.
/// </summary>
[Key("transports")] public CultNetTransportDescriptor[] Transports { get; set; } = Array.Empty<CultNetTransportDescriptor>();
}
/// <summary>
/// Describes one transport endpoint.
/// </summary>
[MessagePackObject]
public class CultNetTransportDescriptor
{
/// <summary>
/// Gets or sets the transport id.
/// </summary>
[Key("transportId")] public string TransportId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the protocol name.
/// </summary>
[Key("protocol")] public string Protocol { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the host.
/// </summary>
[Key("host")] public string? Host { get; set; }
/// <summary>
/// Gets or sets the port.
/// </summary>
[Key("port")] public int? Port { get; set; }
/// <summary>
/// Gets or sets the path.
/// </summary>
[Key("path")] public string? Path { get; set; }
/// <summary>
/// Gets or sets the discovery group.
/// </summary>
[Key("discoveryGroup")] public string? DiscoveryGroup { get; set; }
/// <summary>
/// Gets or sets the wire contracts.
/// </summary>
[Key("wireContracts")] public string[]? WireContracts { get; set; }
/// <summary>
/// Gets or sets the transport reconnect policy, when the transport owns reconnect posture.
/// </summary>
[Key("reconnectPolicy")] public CultNetReconnectPolicy? ReconnectPolicy { get; set; }
/// <summary>
/// Gets or sets the channels.
/// </summary>
[Key("channels")] public CultNetTransportChannel[] Channels { get; set; } = Array.Empty<CultNetTransportChannel>();
}
/// <summary>
/// Describes one transport channel.
/// </summary>
[MessagePackObject]
public class CultNetTransportChannel
{
/// <summary>
/// Gets or sets the channel id.
/// </summary>
[Key("channelId")] public string ChannelId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the delivery semantics.
/// </summary>
[Key("delivery")] public string Delivery { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the ordering semantics.
/// </summary>
[Key("ordering")] public string Ordering { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the maximum payload bytes.
/// </summary>
[Key("maxPayloadBytes")] public int? MaxPayloadBytes { get; set; }
/// <summary>
/// Gets or sets the maximum fragment bytes.
/// </summary>
[Key("maxFragmentBytes")] public int? MaxFragmentBytes { get; set; }
/// <summary>
/// Gets or sets the maximum pending reliable packet count.
/// </summary>
[Key("maxPendingReliablePackets")] public int? MaxPendingReliablePackets { get; set; }
}
/// <summary>
/// CultNet login request message.
/// </summary>
[MessagePackObject]
public class CultNetLoginMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Login;
/// <summary>
/// Gets or sets the nonce.
/// </summary>
[Key("nonce")] public string Nonce { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the auth.
/// </summary>
[Key("auth")] public string Auth { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the password.
/// </summary>
[Key("password")] public string Password { get; set; } = string.Empty;
}
/// <summary>
/// CultNet registration request message.
/// </summary>
[MessagePackObject]
public class CultNetRegisterMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Register;
/// <summary>
/// Gets or sets the nonce.
/// </summary>
[Key("nonce")] public string Nonce { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the email.
/// </summary>
[Key("email")] public string Email { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the password.
/// </summary>
[Key("password")] public string Password { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the name.
/// </summary>
[Key("name")] public string Name { get; set; } = string.Empty;
}
/// <summary>
/// CultNet session verification request message.
/// </summary>
[MessagePackObject]
public class CultNetVerifyMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Verify;
/// <summary>
/// Gets or sets the nonce.
/// </summary>
[Key("nonce")] public string Nonce { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the session.
/// </summary>
[Key("session")] public string Session { get; set; } = string.Empty;
}
/// <summary>
/// CultNet message returned after successful session verification.
/// </summary>
[MessagePackObject]
public class CultNetLoginSuccessMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.LoginSuccess;
/// <summary>
/// Gets or sets the nonce.
/// </summary>
[Key("nonce")] public string Nonce { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the session.
/// </summary>
[Key("session")] public string Session { get; set; } = string.Empty;
}
/// <summary>
/// CultNet error response message.
/// </summary>
[MessagePackObject]
public class CultNetErrorMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Error;
/// <summary>
/// Gets or sets the error.
/// </summary>
[Key("error")] public string Error { get; set; } = string.Empty;
/// <summary>
/// Gets or sets optional shard routing details for authority failures.
/// </summary>
[Key("routingHint")] public CultNetShardRoutingHint? RoutingHint { get; set; }
/// <summary>
/// Gets or sets the machine-readable refusal code (R-N), e.g. <c>selection_invalid</c>,
/// <c>cursor_stale</c>, <c>cursor_invalid</c>, <c>reference_outside_target</c>. Additive to
/// <c>cultnet.error.v0</c>; a v0 peer that does not know this field ignores it.
/// </summary>
[Key("code")] public string? Code { get; set; }
/// <summary>
/// Gets or sets the code-specific structured detail (R-N). Additive to <c>cultnet.error.v0</c>.
/// </summary>
[Key("details")] public CultNetErrorDetails? Details { get; set; }
/// <summary>
/// Builds the wire error for a door refusal (R-N): code <c>selection_invalid</c>, details
/// <c>{ field, value }</c>.
/// </summary>
public static CultNetErrorMessage ForSelectionInvalid(CultNetSelectionInvalidException ex) =>
new CultNetErrorMessage
{
Error = $"selection_invalid: {ex.Message}",
Code = "selection_invalid",
Details = new CultNetErrorDetails { Field = ex.Field, Value = ex.Value }
};
/// <summary>
/// Builds the wire error for a cursor refusal (R-N): code <c>cursor_stale</c> with details
/// <c>{ asOf, current }</c>, or code <c>cursor_invalid</c> with no details.
/// </summary>
public static CultNetErrorMessage ForCursor(CultNetSelectionCursorException ex) =>
new CultNetErrorMessage
{
Error = $"{ex.Code}: {ex.Message}",
Code = ex.Code,
Details = ex.Code == "cursor_stale"
? new CultNetErrorDetails { AsOf = ex.AsOf, Current = ex.Current }
: null
};
/// <summary>
/// Builds the wire error for a selection that selects a document variant, which CultNet does not carry yet: code
/// <c>variant_unsupported</c>, details <c>{ field: "subscriptionId", value }</c> when a subscription was ended by it.
/// </summary>
public static CultNetErrorMessage ForVariantUnsupported(string message, string? subscriptionId = null) =>
new CultNetErrorMessage
{
Error = message,
Code = "variant_unsupported",
Details = subscriptionId == null ? null : new CultNetErrorDetails { Field = "subscriptionId", Value = subscriptionId }
};
/// <summary>
/// Builds the wire error for an out-of-target reference refusal (R-N): code
/// <c>reference_outside_target</c>, no details.
/// </summary>
public static CultNetErrorMessage ForReferenceOutsideTarget(CultNetSelectionReferenceOutsideTargetException ex) =>
new CultNetErrorMessage
{
// ex.Message already begins "reference_outside_target: " (the exception's own
// constructor prefixes it) - this used to prefix it a second time, so a peer received
// "reference_outside_target: reference_outside_target: ...". Rust's ForReferenceOutsideTarget
// (packages/cultnet-rs) emits the single-prefixed form; this now matches it.
Error = ex.Message,
Code = "reference_outside_target"
};
}
/// <summary>
/// Code-specific structured detail carried on <see cref="CultNetErrorMessage"/> (R-N). Fields are
/// populated only for the code that defines them; every field is otherwise omitted (nil on the wire).
/// </summary>
[MessagePackObject]
public class CultNetErrorDetails
{
/// <summary>The selection field that failed (<c>selection_invalid</c>).</summary>
[Key("field")] public string? Field { get; set; }
/// <summary>The offending value, when there is one string worth naming (<c>selection_invalid</c>).</summary>
[Key("value")] public string? Value { get; set; }
/// <summary>The cursor's own minted asOf (<c>cursor_stale</c>).</summary>
[Key("asOf")] public ulong? AsOf { get; set; }
/// <summary>The answering server's current asOf (<c>cursor_stale</c>).</summary>
[Key("current")] public ulong? Current { get; set; }
}
/// <summary>
/// Describes where a shard write should be routed.
/// </summary>
[MessagePackObject]
public class CultNetShardRoutingHint
{
/// <summary>
/// Gets or sets the shard descriptor.
/// </summary>
[Key("shard")] public CultNetShardDescriptorMessage? Shard { get; set; }
/// <summary>
/// Gets or sets a machine-readable routing reason.
/// </summary>
[Key("reason")] public string Reason { get; set; } = string.Empty;
}
/// <summary>
/// Sample CultNet message used by development clients to change a display name.
/// </summary>
[MessagePackObject]
public class CultNetSampleChangeNameMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SampleChangeName;
/// <summary>
/// Gets or sets the name.
/// </summary>
[Key("name")] public string Name { get; set; } = string.Empty;
}
/// <summary>
/// Sample CultNet chat message used by development clients.
/// </summary>
[MessagePackObject]
public class CultNetSampleChatMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SampleChat;
/// <summary>
/// Gets or sets the text.
/// </summary>
[Key("text")] public string Text { get; set; } = string.Empty;
}
/// <summary>
/// Invokes one typed operation on an advertised service.
/// </summary>
[MessagePackObject]
public class CultNetOperationRequestMessage : ICultNetSchemaMessage
{
/// <summary>Gets or sets the wire schema version.</summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.OperationRequest;
/// <summary>Gets or sets the correlation id.</summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>Gets or sets the advertised service id.</summary>
[Key("serviceId")] public string ServiceId { get; set; } = string.Empty;
/// <summary>Gets or sets the requested operation.</summary>
[Key("operation")] public string Operation { get; set; } = string.Empty;
/// <summary>Gets or sets the inner payload schema.</summary>
[Key("payloadSchema")] public string PayloadSchema { get; set; } = string.Empty;
/// <summary>Gets or sets the inner payload encoding.</summary>
[Key("payloadEncoding")] public string PayloadEncoding { get; set; } = "messagepack-base64";
/// <summary>Gets or sets the encoded inner payload.</summary>
[Key("payload")] public string Payload { get; set; } = string.Empty;
/// <summary>Gets or sets the calling runtime id.</summary>
[Key("sourceRuntimeId")] public string? SourceRuntimeId { get; set; }
/// <summary>Gets or sets an optional target runtime id.</summary>
[Key("targetRuntimeId")] public string? TargetRuntimeId { get; set; }
}
/// <summary>
/// Returns the correlated result of one typed service operation.
/// </summary>
[MessagePackObject]
public class CultNetOperationResponseMessage : ICultNetSchemaMessage
{
/// <summary>Gets or sets the wire schema version.</summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.OperationResponse;
/// <summary>Gets or sets the request correlation id.</summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>Gets or sets the advertised service id.</summary>
[Key("serviceId")] public string ServiceId { get; set; } = string.Empty;
/// <summary>Gets or sets the completed operation.</summary>
[Key("operation")] public string Operation { get; set; } = string.Empty;
/// <summary>Gets or sets the operation status.</summary>
[Key("status")] public string Status { get; set; } = string.Empty;
/// <summary>Gets or sets the inner payload schema.</summary>
[Key("payloadSchema")] public string PayloadSchema { get; set; } = string.Empty;
/// <summary>Gets or sets the inner payload encoding.</summary>
[Key("payloadEncoding")] public string PayloadEncoding { get; set; } = "messagepack-base64";
/// <summary>Gets or sets the encoded inner payload.</summary>
[Key("payload")] public string Payload { get; set; } = string.Empty;
/// <summary>Gets or sets transport-level diagnostics.</summary>
[Key("diagnostics")] public string[] Diagnostics { get; set; } = Array.Empty<string>();
/// <summary>Gets or sets the responding runtime id.</summary>
[Key("sourceRuntimeId")] public string? SourceRuntimeId { get; set; }
}
/// <summary>
/// Raw document record carried over CultNet.
/// </summary>
[MessagePackObject]
public class CultNetRawDocumentRecord
{
/// <summary>
/// Gets or sets the schema id.
/// </summary>
[Key("schemaId")] public string SchemaId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the stable schema family name when the publisher has a typed descriptor.
/// </summary>
[Key("schemaName")] public string? SchemaName { get; set; }
/// <summary>
/// Gets or sets the portable versioned schema contract when the publisher has a typed descriptor.
/// </summary>
[Key("schemaVersion")] public string? SchemaVersion { get; set; }
/// <summary>
/// Gets or sets the canonical schema content hash when the publisher has a typed descriptor.
/// </summary>
[Key("schemaContentHash")] public string? SchemaContentHash { get; set; }
/// <summary>
/// Gets or sets the record key.
/// </summary>
[Key("recordKey")] public string RecordKey { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the stored at.
/// </summary>
[Key("storedAt")] public string StoredAt { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the payload encoding.
/// </summary>
[Key("payloadEncoding")] public string PayloadEncoding { get; set; } = "messagepack";
/// <summary>
/// Gets or sets the payload.
/// </summary>
[Key("payload")] public byte[] Payload { get; set; } = Array.Empty<byte>();
/// <summary>
/// Gets or sets the source runtime id.
/// </summary>
[Key("sourceRuntimeId")] public string? SourceRuntimeId { get; set; }
/// <summary>
/// Gets or sets the source agent id.
/// </summary>
[Key("sourceAgentId")] public string? SourceAgentId { get; set; }
/// <summary>
/// Gets or sets the source role.
/// </summary>
[Key("sourceRole")] public string? SourceRole { get; set; }
/// <summary>
/// Gets or sets the tags.
/// </summary>
[Key("tags")] public string[]? Tags { get; set; }
}
/// <summary>
/// CultNet message requesting deletion of a document record.
/// </summary>
[MessagePackObject]
public class CultNetDocumentDeleteMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DocumentDelete;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the schema id.
/// </summary>
[Key("schemaId")] public string SchemaId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the record key.
/// </summary>
[Key("recordKey")] public string RecordKey { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the shard id the sender targeted.
/// </summary>
[Key("shardId")] public string? ShardId { get; set; }
/// <summary>
/// Gets or sets the shard epoch the sender targeted.
/// </summary>
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
}
/// <summary>
/// CultNet message carrying one raw document record.
/// </summary>
[MessagePackObject]
public class CultNetDocumentPutRawMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DocumentPutRaw;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the document.
/// </summary>
[Key("document")] public CultNetRawDocumentRecord Document { get; set; } = new CultNetRawDocumentRecord();
/// <summary>
/// Gets or sets the shard id the sender targeted.
/// </summary>
[Key("shardId")] public string? ShardId { get; set; }
/// <summary>
/// Gets or sets the shard epoch the sender targeted.
/// </summary>
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
}
/// <summary>
/// CultNet message requesting a document snapshot.
/// </summary>
[MessagePackObject]
public class CultNetSnapshotRequestMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SnapshotRequest;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the schema ids.
/// </summary>
[Key("schemaIds")] public string[]? SchemaIds { get; set; }
/// <summary>
/// Gets or sets the record keys.
/// </summary>
[Key("recordKeys")] public string[]? RecordKeys { get; set; }
/// <summary>
/// Gets or sets the shard id requested for a shard-bounded snapshot.
/// </summary>
[Key("shardId")] public string? ShardId { get; set; }
/// <summary>
/// Gets or sets the expected shard epoch.
/// </summary>
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
}
/// <summary>
/// CultNet message returning raw document records from a snapshot request.
/// </summary>
[MessagePackObject]
public class CultNetSnapshotResponseRawMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SnapshotResponseRaw;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the documents.
/// </summary>
[Key("documents")] public CultNetRawDocumentRecord[] Documents { get; set; } = Array.Empty<CultNetRawDocumentRecord>();
/// <summary>
/// Gets or sets the shard id represented by this snapshot.
/// </summary>
[Key("shardId")] public string? ShardId { get; set; }
/// <summary>
/// Gets or sets the shard epoch represented by this snapshot.
/// </summary>
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
/// <summary>
/// Gets or sets the shard-log sequence represented by this snapshot.
/// </summary>
[Key("shardLogSequence")] public long? ShardLogSequence { get; set; }
}
/// <summary>
/// Requests a live database subscription.
/// </summary>
[MessagePackObject]
public class CultNetDatabaseSubscribeMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DatabaseSubscribe;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the live subscription id.
/// </summary>
[Key("subscriptionId")] public string SubscriptionId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets optional schema ids to watch.
/// </summary>
[Key("schemaIds")] public string[]? SchemaIds { get; set; }
/// <summary>
/// Gets or sets optional record keys to watch.
/// </summary>
[Key("recordKeys")] public string[]? RecordKeys { get; set; }
/// <summary>
/// Gets or sets whether the server should send a matching snapshot before live changes.
/// </summary>
[Key("includeSnapshot")] public bool IncludeSnapshot { get; set; } = true;
/// <summary>
/// Gets or sets the stable consumer runtime identity used for subscription diagnostics and body-plane demand.
/// </summary>
[Key("consumerRuntimeId")] public string? ConsumerRuntimeId { get; set; }
/// <summary>
/// Gets or sets logical hot-body identities needed by this exact state subscription.
/// </summary>
[Key("bodyIds")] public string[]? BodyIds { get; set; }
/// <summary>
/// Gets or sets body transports the consumer can open, ordered by consumer preference.
/// </summary>
[Key("supportedBodyTransports")] public string[]? SupportedBodyTransports { get; set; }
}
/// <summary>
/// CultNet message requesting a document snapshot through a typed selection (docs/cultnet-selection-cut.md).
/// </summary>
[MessagePackObject]
public class CultNetSnapshotRequestV1Message : ICultNetSchemaMessage
{
/// <summary>Gets or sets the schema version.</summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SnapshotRequestV1;
/// <summary>Gets or sets the message id.</summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>Gets or sets the selection.</summary>
[Key("selection")] public CultNetSelection Selection { get; set; } = new CultNetSelection();
/// <summary>Gets or sets the shard id requested for a shard-bounded snapshot.</summary>
[Key("shardId")] public string? ShardId { get; set; }
/// <summary>Gets or sets the expected shard epoch.</summary>
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
}
/// <summary>
/// Requests a live database subscription through a typed selection (docs/cultnet-selection-cut.md).
/// </summary>
[MessagePackObject]
public class CultNetDatabaseSubscribeV1Message : ICultNetSchemaMessage
{
/// <summary>Gets or sets the schema version.</summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DatabaseSubscribeV1;
/// <summary>Gets or sets the request id.</summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>Gets or sets the live subscription id.</summary>
[Key("subscriptionId")] public string SubscriptionId { get; set; } = string.Empty;
/// <summary>Gets or sets the selection.</summary>
[Key("selection")] public CultNetSelection Selection { get; set; } = new CultNetSelection();
/// <summary>Gets or sets whether the server should send a matching snapshot before live changes.</summary>
[Key("includeSnapshot")] public bool IncludeSnapshot { get; set; } = true;
/// <summary>Gets or sets the stable consumer runtime identity used for subscription diagnostics and body-plane demand.</summary>
[Key("consumerRuntimeId")] public string? ConsumerRuntimeId { get; set; }
/// <summary>Gets or sets logical hot-body identities needed by this exact state subscription.</summary>
[Key("bodyIds")] public string[]? BodyIds { get; set; }
/// <summary>Gets or sets body transports the consumer can open, ordered by consumer preference.</summary>
[Key("supportedBodyTransports")] public string[]? SupportedBodyTransports { get; set; }
}
/// <summary>
/// CultNet message returning a typed selection's page (docs/cultnet-selection-cut.md).
/// </summary>
[MessagePackObject]
public class CultNetSnapshotResponseRawV1Message : ICultNetSchemaMessage
{
/// <summary>Gets or sets the schema version.</summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SnapshotResponseRawV1;
/// <summary>Gets or sets the message id.</summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>Gets or sets the number of rows on this page.</summary>
[Key("matched")] public uint Matched { get; set; }
/// <summary>Gets or sets the snapshot this page is exact as of.</summary>
[Key("asOf")] public ulong AsOf { get; set; }
/// <summary>Gets or sets the cursor for the next page, absent on the last page.</summary>
[Key("next")] public string? Next { get; set; }
/// <summary>Gets or sets the headers, present under header projection.</summary>
[Key("headers")] public CultNetRawDocumentHeader[]? Headers { get; set; }
/// <summary>Gets or sets the documents, present under document projection.</summary>
[Key("documents")] public CultNetRawDocumentRecord[]? Documents { get; set; }
/// <summary>Gets or sets the edges a hop-bearing selection traversed.</summary>
[Key("edges")] public CultNetEdge[]? Edges { get; set; }
/// <summary>Gets or sets the shard id represented by this snapshot.</summary>
[Key("shardId")] public string? ShardId { get; set; }
/// <summary>Gets or sets the shard epoch represented by this snapshot.</summary>
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
/// <summary>Gets or sets the shard-log sequence represented by this snapshot.</summary>
[Key("shardLogSequence")] public long? ShardLogSequence { get; set; }
}
/// <summary>
/// Cancels a live database subscription.
/// </summary>
[MessagePackObject]
public class CultNetDatabaseUnsubscribeMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DatabaseUnsubscribe;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the live subscription id.
/// </summary>
[Key("subscriptionId")] public string SubscriptionId { get; set; } = string.Empty;
}
/// <summary>
/// Streams one raw document change for a live database subscription.
/// </summary>
[MessagePackObject]
public class CultNetDatabaseChangeRawMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DatabaseChangeRaw;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the live subscription id.
/// </summary>
[Key("subscriptionId")] public string SubscriptionId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the change kind.
/// </summary>
[Key("changeKind")] public string ChangeKind { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the current document for added or updated changes.
/// </summary>
[Key("document")] public CultNetRawDocumentRecord? Document { get; set; }
/// <summary>
/// Gets or sets the deleted record key for removed changes.
/// </summary>
[Key("recordKey")] public string? RecordKey { get; set; }
/// <summary>
/// Gets or sets the deleted schema id for removed changes.
/// </summary>
[Key("schemaId")] public string? SchemaId { get; set; }
}
/// <summary>
/// Describes one shard advertised by a CultNet database node.
/// </summary>
[MessagePackObject]
public class CultNetShardDescriptorMessage
{
/// <summary>
/// Gets or sets the shard id.
/// </summary>
[Key("shardId")] public string ShardId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the owner runtime id.
/// </summary>
[Key("ownerRuntimeId")] public string OwnerRuntimeId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the shard authority epoch.
/// </summary>
[Key("epoch")] public long Epoch { get; set; }
/// <summary>
/// Gets or sets whether the responding node is primary for this shard.
/// </summary>
[Key("isPrimary")] public bool IsPrimary { get; set; }
/// <summary>
/// Gets or sets schema ids governed by this shard. Empty means all schemas.
/// </summary>
[Key("schemaIds")] public string[] SchemaIds { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets the record-key prefix governed by this shard.
/// </summary>
[Key("keyPrefix")] public string? KeyPrefix { get; set; }
/// <summary>
/// Gets or sets endpoints that accept authoritative writes.
/// </summary>
[Key("primaryEndpoints")] public string[] PrimaryEndpoints { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets authoritative replica endpoints.
/// </summary>
[Key("replicaEndpoints")] public string[] ReplicaEndpoints { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets low-latency read replica endpoints.
/// </summary>
[Key("readReplicaEndpoints")] public string[] ReadReplicaEndpoints { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets an optional locality label.
/// </summary>
[Key("region")] public string? Region { get; set; }
}
/// <summary>
/// Requests shard ownership and routing metadata.
/// </summary>
[MessagePackObject]
public class CultNetShardCatalogRequestMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ShardCatalogRequest;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets optional schema filters.
/// </summary>
[Key("schemaIds")] public string[]? SchemaIds { get; set; }
/// <summary>
/// Gets or sets optional record-key filters.
/// </summary>
[Key("recordKeys")] public string[]? RecordKeys { get; set; }
}
/// <summary>
/// Returns shard ownership and routing metadata.
/// </summary>
[MessagePackObject]
public class CultNetShardCatalogResponseMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ShardCatalogResponse;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets shard descriptors.
/// </summary>
[Key("shards")] public CultNetShardDescriptorMessage[] Shards { get; set; } = Array.Empty<CultNetShardDescriptorMessage>();
}
/// <summary>
/// Requests accepted mutation log entries for a shard.
/// </summary>
[MessagePackObject]
public class CultNetShardLogRequestMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ShardLogRequest;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the shard id.
/// </summary>
[Key("shardId")] public string ShardId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the shard epoch expected by the requester.
/// </summary>
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
/// <summary>
/// Gets or sets the last sequence already held by the requester.
/// </summary>
[Key("afterSequence")] public long AfterSequence { get; set; }
/// <summary>
/// Gets or sets the maximum number of entries to return.
/// </summary>
[Key("limit")] public int? Limit { get; set; }
}
/// <summary>
/// Returns accepted mutation log entries for a shard.
/// </summary>
[MessagePackObject]
public class CultNetShardLogResponseMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ShardLogResponse;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the shard id.
/// </summary>
[Key("shardId")] public string ShardId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the shard epoch.
/// </summary>
[Key("shardEpoch")] public long ShardEpoch { get; set; }
/// <summary>
/// Gets or sets mutation log entries.
/// </summary>
[Key("entries")] public CultNetShardLogEntryMessage[] Entries { get; set; } = Array.Empty<CultNetShardLogEntryMessage>();
/// <summary>
/// Gets or sets whether the requester must fall back to a shard snapshot.
/// </summary>
[Key("resyncRequired")] public bool ResyncRequired { get; set; }
/// <summary>
/// Gets or sets a machine-readable resync reason.
/// </summary>
[Key("reason")] public string? Reason { get; set; }
/// <summary>
/// Gets or sets the highest sequence compacted out of the retained log.
/// </summary>
[Key("compactedThrough")] public long? CompactedThrough { get; set; }
}
/// <summary>
/// Describes one accepted shard mutation for replica catch-up.
/// </summary>
[MessagePackObject]
public class CultNetShardLogEntryMessage
{
/// <summary>
/// Gets or sets the per-shard sequence.
/// </summary>
[Key("sequence")] public long Sequence { get; set; }
/// <summary>
/// Gets or sets the commit timestamp.
/// </summary>
[Key("committedAt")] public string CommittedAt { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the mutation kind.
/// </summary>
[Key("changeKind")] public string ChangeKind { get; set; } = string.Empty;
/// <summary>
/// Gets or sets a raw put message for added/updated entries.
/// </summary>
[Key("put")] public CultNetDocumentPutRawMessage? Put { get; set; }
/// <summary>
/// Gets or sets a raw delete message for removed entries.
/// </summary>
[Key("delete")] public CultNetDocumentDeleteMessage? Delete { get; set; }
}
/// <summary>
/// Carries one witness observation about a simulation fact.
/// </summary>
[MessagePackObject]
public class CultNetSimulationObservationMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SimulationObservation;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the observation.
/// </summary>
[Key("observation")] public CultNetSimulationObservation Observation { get; set; } = new CultNetSimulationObservation();
}
/// <summary>
/// Carries one deterministic consensus candidate derived from witness observations.
/// </summary>
[MessagePackObject]
public class CultNetSimulationConsensusCandidateMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SimulationConsensusCandidate;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the shard id.
/// </summary>
[Key("shardId")] public string ShardId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the shard epoch.
/// </summary>
[Key("shardEpoch")] public long ShardEpoch { get; set; }
/// <summary>
/// Gets or sets the simulation frame.
/// </summary>
[Key("frame")] public long Frame { get; set; }
/// <summary>
/// Gets or sets the subject id.
/// </summary>
[Key("subjectId")] public string SubjectId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the claim kind.
/// </summary>
[Key("claimKind")] public string ClaimKind { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the selected claim hash.
/// </summary>
[Key("claimHash")] public string ClaimHash { get; set; } = string.Empty;
/// <summary>
/// Gets or sets optional claim detail.
/// </summary>
[Key("claimSummary")] public string? ClaimSummary { get; set; }
/// <summary>
/// Gets or sets distinct supporting witnesses.
/// </summary>
[Key("witnessCount")] public int WitnessCount { get; set; }
/// <summary>
/// Gets or sets supporting witness weight.
/// </summary>
[Key("supportWeight")] public double SupportWeight { get; set; }
/// <summary>
/// Gets or sets total observed witness weight.
/// </summary>
[Key("totalWeight")] public double TotalWeight { get; set; }
/// <summary>
/// Gets or sets whether the candidate crossed quorum.
/// </summary>
[Key("hasQuorum")] public bool HasQuorum { get; set; }
/// <summary>
/// Gets or sets support divided by total observed weight.
/// </summary>
[Key("confidence")] public double Confidence { get; set; }
/// <summary>
/// Creates a wire candidate message from a local candidate.
/// </summary>
public static CultNetSimulationConsensusCandidateMessage FromCandidate(
string messageId,
CultNetSimulationConsensusCandidate candidate)
{
if (candidate == null) throw new ArgumentNullException(nameof(candidate));
return new CultNetSimulationConsensusCandidateMessage
{
MessageId = string.IsNullOrWhiteSpace(messageId) ? Guid.NewGuid().ToString("N") : messageId,
ShardId = candidate.ShardId,
ShardEpoch = candidate.ShardEpoch,
Frame = candidate.Frame,
SubjectId = candidate.SubjectId,
ClaimKind = candidate.ClaimKind,
ClaimHash = candidate.ClaimHash,
ClaimSummary = candidate.ClaimSummary,
WitnessCount = candidate.WitnessCount,
SupportWeight = candidate.SupportWeight,
TotalWeight = candidate.TotalWeight,
HasQuorum = candidate.HasQuorum,
Confidence = candidate.Confidence
};
}
}
/// <summary>Requests an identity-bound CultMesh session before application traffic begins.</summary>
[MessagePackObject]
public class CultMeshSessionOpenMessage : ICultNetSchemaMessage
{
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SessionOpen;
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
[Key("sourceRuntimeId")] public string SourceRuntimeId { get; set; } = string.Empty;
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
[Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty;
[Key("protocolId")] public string ProtocolId { get; set; } = string.Empty;
[Key("routeGeneration")] public string RouteGeneration { get; set; } = string.Empty;
[Key("clientNonce")] public string ClientNonce { get; set; } = string.Empty;
}
/// <summary>Accepts or rejects a CultMesh session with the server's actual identity.</summary>
[MessagePackObject]
public class CultMeshSessionAcceptedMessage : ICultNetSchemaMessage
{
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SessionAccepted;
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
[Key("accepted")] public bool Accepted { get; set; }
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
[Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty;
[Key("protocolId")] public string ProtocolId { get; set; } = string.Empty;
[Key("routeGeneration")] public string RouteGeneration { get; set; } = string.Empty;
[Key("clientNonce")] public string ClientNonce { get; set; } = string.Empty;
[Key("providerKeyId")] public string ProviderKeyId { get; set; } = string.Empty;
[Key("providerSignature")] public string ProviderSignature { get; set; } = string.Empty;
[Key("error")] public string? Error { get; set; }
}
/// <summary>
/// Requests known CultMesh Verses from a peer.
/// </summary>
[MessagePackObject]
public class CultMeshVerseCatalogRequestMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.VerseCatalogRequest;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets optional Verse ids to request.
/// </summary>
[Key("verseIds")] public string[]? VerseIds { get; set; }
/// <summary>
/// Gets or sets an optional transport compatibility filter.
/// </summary>
[Key("transportVersion")] public string? TransportVersion { get; set; }
}
/// <summary>
/// Returns known CultMesh Verses.
/// </summary>
[MessagePackObject]
public class CultMeshVerseCatalogResponseMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.VerseCatalogResponse;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets discovered Verses.
/// </summary>
[Key("verses")] public CultMeshVerseDescriptorMessage[] Verses { get; set; } = Array.Empty<CultMeshVerseDescriptorMessage>();
}
/// <summary>
/// Wire representation of a CultMesh Verse.
/// </summary>
[MessagePackObject]
public class CultMeshVerseDescriptorMessage
{
/// <summary>
/// Gets or sets the stable Verse id.
/// </summary>
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the display name.
/// </summary>
[Key("displayName")] public string DisplayName { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the authority model name.
/// </summary>
[Key("authorityModel")] public string AuthorityModel { get; set; } = string.Empty;
/// <summary>
/// Gets or sets compatibility metadata.
/// </summary>
[Key("compatibility")] public CultMeshVerseCompatibilityMessage Compatibility { get; set; } = new CultMeshVerseCompatibilityMessage();
/// <summary>
/// Gets or sets endpoints that can answer discovery for this Verse.
/// </summary>
[Key("discoveryEndpoints")] public string[] DiscoveryEndpoints { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets known authoritative runtime ids.
/// </summary>
[Key("authorityRuntimeIds")] public string[] AuthorityRuntimeIds { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets exact authoritative-runtime route bindings. This is the
/// routing authority; the parallel legacy arrays are projections only.
/// </summary>
[Key("authorityRoutes")] public CultMeshAuthorityRouteMessage[] AuthorityRoutes { get; set; } = Array.Empty<CultMeshAuthorityRouteMessage>();
/// <summary>
/// Gets or sets the parent Verse id for overlays or branches.
/// </summary>
[Key("parentVerseId")] public string? ParentVerseId { get; set; }
/// <summary>
/// Gets or sets an optional public description.
/// </summary>
[Key("description")] public string? Description { get; set; }
}
/// <summary>Wire representation of one authority-bound CultMesh route.</summary>
[MessagePackObject]
public class CultMeshAuthorityRouteMessage
{
[Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty;
[Key("endpoint")] public string Endpoint { get; set; } = string.Empty;
[Key("protocolIds")] public string[] ProtocolIds { get; set; } = Array.Empty<string>();
[Key("priority")] public int Priority { get; set; }
[Key("generation")] public string Generation { get; set; } = string.Empty;
[Key("certificate")] public CultMeshRouteCertificateMessage? Certificate { get; set; }
}
[MessagePackObject]
public class CultMeshRouteCertificateMessage
{
[Key("providerKeyId")] public string ProviderKeyId { get; set; } = string.Empty;
[Key("providerPublicKeyX")] public string ProviderPublicKeyX { get; set; } = string.Empty;
[Key("providerPublicKeyY")] public string ProviderPublicKeyY { get; set; } = string.Empty;
[Key("odinKeyId")] public string OdinKeyId { get; set; } = string.Empty;
[Key("issuedAtUnixMilliseconds")] public long IssuedAtUnixMilliseconds { get; set; }
[Key("expiresAtUnixMilliseconds")] public long ExpiresAtUnixMilliseconds { get; set; }
[Key("signature")] public string Signature { get; set; } = string.Empty;
}
/// <summary>
/// Wire representation of CultMesh Verse compatibility.
/// </summary>
[MessagePackObject]
public class CultMeshVerseCompatibilityMessage
{
/// <summary>
/// Gets or sets the CultMesh transport compatibility version.
/// </summary>
[Key("transportVersion")] public string TransportVersion { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the stable rules hash.
/// </summary>
[Key("rulesHash")] public string RulesHash { get; set; } = string.Empty;
/// <summary>
/// Gets or sets Verse ids this Verse can transfer from or subscribe to.
/// </summary>
[Key("compatibleVerseIds")] public string[] CompatibleVerseIds { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets required plugin ids.
/// </summary>
[Key("requiredPluginIds")] public string[] RequiredPluginIds { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets optional plugin ids.
/// </summary>
[Key("optionalPluginIds")] public string[] OptionalPluginIds { get; set; } = Array.Empty<string>();
}
/// <summary>
/// Requests known peers for a CultMesh Verse.
/// </summary>
[MessagePackObject]
public class CultMeshPeerExchangeRequestMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.PeerExchangeRequest;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the Verse id to discover peers for.
/// </summary>
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets optional role filters.
/// </summary>
[Key("roles")] public string[]? Roles { get; set; }
/// <summary>
/// Gets or sets peer ids the requester already knows.
/// </summary>
[Key("knownPeerIds")] public string[]? KnownPeerIds { get; set; }
/// <summary>
/// Gets or sets the maximum number of peer cards to return.
/// </summary>
[Key("limit")] public int? Limit { get; set; }
}
/// <summary>
/// Returns known peers for a CultMesh Verse.
/// </summary>
[MessagePackObject]
public class CultMeshPeerExchangeResponseMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.PeerExchangeResponse;
/// <summary>
/// Gets or sets the request id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets peer cards.
/// </summary>
[Key("peers")] public CultMeshPeerCardMessage[] Peers { get; set; } = Array.Empty<CultMeshPeerCardMessage>();
}
/// <summary>
/// Requests one bounded content-addressed chunk over a managed CultMesh content session.
/// </summary>
[MessagePackObject]
public class CultMeshContentChunkRequestMessage : ICultNetSchemaMessage
{
/// <summary>Gets or sets the wire schema identity.</summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ContentChunkRequest;
/// <summary>Gets or sets the request correlation identity.</summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>Gets or sets the canonical SHA-256 chunk identity.</summary>
[Key("chunkHash")] public string ChunkHash { get; set; } = string.Empty;
/// <summary>Gets or sets the optional canonical CultCache record key.</summary>
[Key("recordKey")] public string RecordKey { get; set; } = string.Empty;
/// <summary>Gets or sets the manifest-bound expected payload size.</summary>
[Key("expectedSizeBytes")] public int ExpectedSizeBytes { get; set; }
}
/// <summary>
/// Returns one bounded content-addressed chunk without publishing it as snapshot state.
/// </summary>
[MessagePackObject]
public class CultMeshContentChunkResponseMessage : ICultNetSchemaMessage
{
/// <summary>Gets or sets the wire schema identity.</summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ContentChunkResponse;
/// <summary>Gets or sets the matching request correlation identity.</summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>Gets or sets whether a validated chunk is present.</summary>
[Key("found")] public bool Found { get; set; }
/// <summary>Gets or sets the canonical SHA-256 chunk identity.</summary>
[Key("chunkHash")] public string ChunkHash { get; set; } = string.Empty;
/// <summary>Gets or sets the payload byte count.</summary>
[Key("sizeBytes")] public int SizeBytes { get; set; }
/// <summary>Gets or sets the bounded content payload.</summary>
[Key("payload")] public byte[] Payload { get; set; } = Array.Empty<byte>();
/// <summary>Gets or sets a typed-boundary failure description when the chunk is unavailable.</summary>
[Key("error")] public string Error { get; set; } = string.Empty;
}
/// <summary>
/// Requests one immutable body generation from its capability owner. Body bytes travel on this
/// dedicated plane; they are never database snapshot records.
/// </summary>
[MessagePackObject]
public class CultMeshBodyReadRequestMessage : ICultNetSchemaMessage
{
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.BodyReadRequest;
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
[Key("capabilityToken")] public string CapabilityToken { get; set; } = string.Empty;
[Key("bodyId")] public string BodyId { get; set; } = string.Empty;
[Key("bodySchemaId")] public string BodySchemaId { get; set; } = string.Empty;
[Key("layoutVersion")] public int LayoutVersion { get; set; }
[Key("producerEpoch")] public long ProducerEpoch { get; set; }
[Key("sequence")] public long Sequence { get; set; }
[Key("expectedSizeBytes")] public long ExpectedSizeBytes { get; set; }
[Key("semanticHash")] public string SemanticHash { get; set; } = string.Empty;
}
/// <summary>Returns one bounded immutable body generation directly to its subscriber.</summary>
[MessagePackObject]
public class CultMeshBodyReadResponseMessage : ICultNetSchemaMessage
{
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.BodyReadResponse;
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
[Key("found")] public bool Found { get; set; }
[Key("capabilityToken")] public string CapabilityToken { get; set; } = string.Empty;
[Key("bodyId")] public string BodyId { get; set; } = string.Empty;
[Key("producerEpoch")] public long ProducerEpoch { get; set; }
[Key("sequence")] public long Sequence { get; set; }
[Key("sizeBytes")] public long SizeBytes { get; set; }
[Key("semanticHash")] public string SemanticHash { get; set; } = string.Empty;
[Key("payload")] public byte[] Payload { get; set; } = Array.Empty<byte>();
[Key("error")] public string Error { get; set; } = string.Empty;
}
/// <summary>
/// Wire representation of a CultMesh peer candidate.
/// </summary>
[MessagePackObject]
public class CultMeshPeerCardMessage
{
/// <summary>
/// Gets or sets the stable peer id.
/// </summary>
[Key("peerId")] public string PeerId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the Verse id this peer participates in.
/// </summary>
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets reachable endpoints.
/// </summary>
[Key("endpoints")] public string[] Endpoints { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets advertised peer roles.
/// </summary>
[Key("roles")] public string[] Roles { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets shard ids this peer can serve or observe.
/// </summary>
[Key("shardIds")] public string[] ShardIds { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets an optional region/locality label.
/// </summary>
[Key("region")] public string? Region { get; set; }
/// <summary>
/// Gets or sets the authority lease id, when the card advertises authority.
/// </summary>
[Key("authorityLeaseId")] public string? AuthorityLeaseId { get; set; }
/// <summary>
/// Gets or sets the expiry timestamp for this card.
/// </summary>
[Key("expiresAt")] public string? ExpiresAt { get; set; }
/// <summary>
/// Gets or sets an optional signature over the card.
/// </summary>
[Key("signature")] public string? Signature { get; set; }
}
/// <summary>
/// Describes one schema exposed through the CultNet schema catalog.
/// </summary>
[MessagePackObject]
public class CultNetSchemaDescriptor
{
/// <summary>
/// Gets or sets the schema id.
/// </summary>
[Key("schemaId")] public string SchemaId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the kind.
/// </summary>
[Key("kind")] public string Kind { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string? SchemaVersion { get; set; }
/// <summary>
/// Gets or sets the document type.
/// </summary>
[Key("documentType")] public string? DocumentType { get; set; }
/// <summary>
/// Gets or sets the title.
/// </summary>
[Key("title")] public string? Title { get; set; }
/// <summary>
/// Gets or sets the wire contracts.
/// </summary>
[Key("wireContracts")] public string[] WireContracts { get; set; } = Array.Empty<string>();
/// <summary>
/// Gets or sets the content hash.
/// </summary>
[Key("contentHash")] public string ContentHash { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the schema json.
/// </summary>
[Key("schemaJson")] public string? SchemaJson { get; set; }
}
/// <summary>
/// CultNet message requesting schema catalog entries.
/// </summary>
[MessagePackObject]
public class CultNetSchemaCatalogRequestMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SchemaCatalogRequest;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the include schema json.
/// </summary>
[Key("includeSchemaJson")] public bool IncludeSchemaJson { get; set; }
/// <summary>
/// Gets or sets the schema ids.
/// </summary>
[Key("schemaIds")] public string[]? SchemaIds { get; set; }
/// <summary>
/// Gets or sets the kinds.
/// </summary>
[Key("kinds")] public string[]? Kinds { get; set; }
}
/// <summary>
/// CultNet message returning schema catalog entries.
/// </summary>
[MessagePackObject]
public class CultNetSchemaCatalogResponseMessage : ICultNetSchemaMessage
{
/// <summary>
/// Gets or sets the schema version.
/// </summary>
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SchemaCatalogResponse;
/// <summary>
/// Gets or sets the message id.
/// </summary>
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the schemas.
/// </summary>
[Key("schemas")] public CultNetSchemaDescriptor[] Schemas { get; set; } = Array.Empty<CultNetSchemaDescriptor>();
}
}