CultLib/src/GameCult.Networking/CultNetSchemaMessages.cs
Meta Vens b4f494b7a0 CultNetDatabaseServer: a peer's put or delete commits only when its write authority grants it
CultNetDatabaseServerOptions.RemoteWriteAuthority is asked once per received
write, after the schema resolves and before the shard does; none configured
refuses every remote write; an authority that throws refuses and is logged.
A refusal applies, publishes, logs and forwards nothing. The host's own
CultNetDatabase.ApplyPutAsync/ApplyDeleteAsync ask no remote authority.
Existing server tests whose subject is not the grant pass a test-local
granting authority.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 00:47:24 +01:00

1804 lines
79 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>, <c>unowned_schema</c>, <c>write_not_authorized</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 write no shard owns: code <c>unowned_schema</c>, details <c>{ field: "schemaId", value }</c>.
/// </summary>
public static CultNetErrorMessage ForUnownedSchema(CultNetUnownedSchemaException ex) =>
new CultNetErrorMessage
{
Error = $"unowned_schema: {ex.Message}",
Code = "unowned_schema",
Details = new CultNetErrorDetails { Field = "schemaId", Value = ex.SchemaId }
};
/// <summary>
/// Builds the wire error for a peer write its authority refused: code <c>write_not_authorized</c>, details
/// <c>{ field: "recordKey", value }</c>.
/// </summary>
public static CultNetErrorMessage ForRemoteWriteRefused(CultNetRemoteWriteRequest request, string? reason) =>
new CultNetErrorMessage
{
Error = string.IsNullOrWhiteSpace(reason) ? "write_not_authorized" : $"write_not_authorized: {reason}",
Code = "write_not_authorized",
Details = new CultNetErrorDetails { Field = "recordKey", Value = request.RecordKey.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>();
}
}