CultLib/packages/cultnet-py/src/cultnet_py/cultmesh_contracts.py
Meta Vens 95493862bd Split the Python runtime into cultcache-py, cultnet-py, cultmesh-py
One distribution named cultcache-py carried three libraries. Rust and
TypeScript layer them as cultcache < cultnet < cultmesh; Python now does
the same, one package per layer, module names unchanged so every
`from cultmesh_py import ...` keeps working.

Two imports ran against that layering and are resolved by moving code to
where the dependency direction says it lives, not by adding a shim:

- cultnet_py.interop_peer imported the Verse/peer catalog, authority
  lease, stream, and simulation-fact contracts from cultmesh_py. They are
  wire contracts a bare peer has to speak without owning a node, which is
  why cultnet-rs and cultnet-ts keep them in the net layer. They now live
  in cultnet_py.cultmesh_contracts; cultmesh_py re-exports them.
- cultcache_py.benchmark imported cultnet_py. It measures framed CultNet
  parse beside cache paths, so it and compare_csharp move to cultnet_py.
  verify checks all three packages and moves to cultmesh_py.

The single 6,693-line test module is split by what each test touches: a
test using any cultmesh_py name lands in cultmesh-py, else cultnet_py in
cultnet-py, else cultcache-py. Each suite runs with only its layer and the
layers below on the path, so a test that reaches up fails to import
rather than quietly binding the packages back together. 11 / 53 / 78 =
the same 142.

Workflows install all three; the publish job is one matrix over the
three packages keyed by tag prefix. The TS test harnesses put all three
src directories on PYTHONPATH. cultcache-py bumps to 0.2.0 because it no
longer contains cultnet_py or cultmesh_py; the new packages start at
0.1.0. Nothing was ever published, so no PyPI consumer moves.

  cultcache-py  11 tests, path: cultcache-py/src
  cultnet-py    53 tests, path: + cultnet-py/src
  cultmesh-py   78 tests, path: + cultmesh-py/src
  python -m cultmesh_py.verify -> ok, all five checks
  cultnet_py.interop_peer imports with cultmesh_py absent

Not run here: the cultnet-ts interop ring and cultcache-ts store matrix
need dotnet/kotlin peers; their PYTHONPATH change is four lines.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 13:10:47 +02:00

720 lines
26 KiB
Python

from __future__ import annotations
import base64
import hashlib
import hmac
from dataclasses import dataclass, field, replace
from datetime import UTC, datetime
from hashlib import sha256
from typing import Any, Callable, Mapping
import msgpack
from cultcache_py import define_database_entry_type
from cultcache_py.documents import DocumentDefinition
VERSE_CATALOG_REQUEST = "cultmesh.verse_catalog_request.v0"
VERSE_CATALOG_RESPONSE = "cultmesh.verse_catalog_response.v0"
PEER_EXCHANGE_REQUEST = "cultmesh.peer_exchange_request.v0"
PEER_EXCHANGE_RESPONSE = "cultmesh.peer_exchange_response.v0"
@dataclass(frozen=True)
class CultMeshVerseCompatibility:
transport_version: str
rules_hash: str
compatible_verse_ids: tuple[str, ...] = ()
required_plugin_ids: tuple[str, ...] = ()
optional_plugin_ids: tuple[str, ...] = ()
def to_wire(self) -> dict[str, Any]:
return {
"transportVersion": self.transport_version,
"rulesHash": self.rules_hash,
"compatibleVerseIds": list(self.compatible_verse_ids),
"requiredPluginIds": list(self.required_plugin_ids),
"optionalPluginIds": list(self.optional_plugin_ids),
}
@dataclass(frozen=True)
class CultMeshVerseDescriptor:
verse_id: str
display_name: str
authority_model: str
compatibility: CultMeshVerseCompatibility
discovery_endpoints: tuple[str, ...] = ()
authority_runtime_ids: tuple[str, ...] = ()
parent_verse_id: str | None = None
description: str | None = None
def to_wire(self) -> dict[str, Any]:
return {
"verseId": self.verse_id,
"displayName": self.display_name,
"authorityModel": self.authority_model,
"compatibility": self.compatibility.to_wire(),
"discoveryEndpoints": list(self.discovery_endpoints),
"authorityRuntimeIds": list(self.authority_runtime_ids),
"parentVerseId": self.parent_verse_id,
"description": self.description,
}
def can_transfer_from(self, source: "CultMeshVerseDescriptor") -> bool:
return (
self.compatibility.transport_version == source.compatibility.transport_version
and (
self.compatibility.rules_hash == source.compatibility.rules_hash
or source.verse_id in self.compatibility.compatible_verse_ids
)
)
@dataclass(frozen=True)
class CultMeshPeerCard:
peer_id: str
verse_id: str
endpoints: tuple[str, ...]
roles: tuple[str, ...] = ()
shard_ids: tuple[str, ...] = ()
region: str | None = None
authority_lease_id: str | None = None
expires_at: str | None = None
signature: str | None = None
def to_wire(self) -> dict[str, Any]:
return {
"peerId": self.peer_id,
"verseId": self.verse_id,
"endpoints": list(self.endpoints),
"roles": list(self.roles),
"shardIds": list(self.shard_ids),
"region": self.region,
"authorityLeaseId": self.authority_lease_id,
"expiresAt": self.expires_at,
"signature": self.signature,
}
def has_role(self, role: str) -> bool:
require_non_empty(role, "role")
return role in self.roles
@dataclass
class CultMeshVerseCatalog:
_verses: dict[str, CultMeshVerseDescriptor] = field(default_factory=dict)
_subscribers: list[Callable[[CultMeshVerseDescriptor], None]] = field(default_factory=list)
@property
def verses(self) -> list[CultMeshVerseDescriptor]:
return [self._verses[key] for key in sorted(self._verses)]
def watch(self, callback: Callable[[CultMeshVerseDescriptor], None]) -> Callable[[], None]:
self._subscribers.append(callback)
def unsubscribe() -> None:
if callback in self._subscribers:
self._subscribers.remove(callback)
return unsubscribe
def upsert(self, verse: CultMeshVerseDescriptor) -> None:
require_non_empty(verse.verse_id, "verse.verse_id")
self._verses[verse.verse_id] = verse
self._publish(verse)
def create_response(self, request: dict[str, Any]) -> dict[str, Any]:
requested = set(request.get("verseIds") or [])
transport_version = request.get("transportVersion")
verses = []
for verse in sorted(self._verses.values(), key=lambda item: item.verse_id):
if requested and verse.verse_id not in requested:
continue
if transport_version and verse.compatibility.transport_version != transport_version:
continue
verses.append(verse.to_wire())
return {
"schemaVersion": VERSE_CATALOG_RESPONSE,
"messageId": request.get("messageId", ""),
"verses": verses,
}
def apply_response(self, response: dict[str, Any]) -> list[CultMeshVerseDescriptor]:
if response.get("schemaVersion") != VERSE_CATALOG_RESPONSE:
raise ValueError(f"Expected {VERSE_CATALOG_RESPONSE}, received {response.get('schemaVersion')!r}")
applied = [verse_from_wire(verse) for verse in response.get("verses", [])]
for verse in applied:
self.upsert(verse)
return applied
def get(self, verse_id: str) -> CultMeshVerseDescriptor | None:
require_non_empty(verse_id, "verse_id")
return self._verses.get(verse_id)
def find_transfer_targets(self, source: CultMeshVerseDescriptor) -> list[CultMeshVerseDescriptor]:
return [
verse
for verse in self.verses
if verse.verse_id != source.verse_id and verse.can_transfer_from(source)
]
def _publish(self, verse: CultMeshVerseDescriptor) -> None:
for callback in list(self._subscribers):
callback(verse)
@dataclass
class CultMeshPeerCatalog:
_peers: dict[str, CultMeshPeerCard] = field(default_factory=dict)
_subscribers: list[Callable[[CultMeshPeerCard], None]] = field(default_factory=list)
@property
def peers(self) -> list[CultMeshPeerCard]:
return [self._peers[key] for key in sorted(self._peers)]
def watch(self, callback: Callable[[CultMeshPeerCard], None]) -> Callable[[], None]:
self._subscribers.append(callback)
def unsubscribe() -> None:
if callback in self._subscribers:
self._subscribers.remove(callback)
return unsubscribe
def upsert(self, peer: CultMeshPeerCard) -> None:
require_non_empty(peer.peer_id, "peer.peer_id")
require_non_empty(peer.verse_id, "peer.verse_id")
self._peers[peer.peer_id] = peer
self._publish(peer)
def create_response(self, request: dict[str, Any]) -> dict[str, Any]:
verse_id = request.get("verseId", "")
roles = set(request.get("roles") or [])
known_peer_ids = set(request.get("knownPeerIds") or [])
limit = request.get("limit")
peers = []
for peer in sorted(self._peers.values(), key=lambda item: item.peer_id):
if peer.verse_id != verse_id:
continue
if peer.peer_id in known_peer_ids:
continue
if roles and not roles.intersection(peer.roles):
continue
peers.append(peer.to_wire())
if isinstance(limit, int) and len(peers) >= limit:
break
return {
"schemaVersion": PEER_EXCHANGE_RESPONSE,
"messageId": request.get("messageId", ""),
"peers": peers,
}
def apply_response(self, response: dict[str, Any]) -> list[CultMeshPeerCard]:
if response.get("schemaVersion") != PEER_EXCHANGE_RESPONSE:
raise ValueError(f"Expected {PEER_EXCHANGE_RESPONSE}, received {response.get('schemaVersion')!r}")
applied = [peer_from_wire(peer) for peer in response.get("peers", [])]
for peer in applied:
self.upsert(peer)
return applied
def find(self, verse_id: str, role: str | None = None) -> list[CultMeshPeerCard]:
require_non_empty(verse_id, "verse_id")
return [
peer
for peer in self.peers
if peer.verse_id == verse_id and (role is None or peer.has_role(role))
]
def find_authorized(
self,
verse_id: str,
role: str,
leases: "CultMeshAuthorityLeaseCatalog",
shard_id: str | None = None,
at: datetime | None = None,
) -> list[CultMeshPeerCard]:
require_non_empty(verse_id, "verse_id")
require_non_empty(role, "role")
return [
peer
for peer in self.find(verse_id, role)
if leases.is_authorized(peer, role, shard_id=shard_id, at=at)
]
def first_authorized(
self,
verse_id: str,
role: str,
leases: "CultMeshAuthorityLeaseCatalog",
shard_id: str | None = None,
at: datetime | None = None,
) -> CultMeshPeerCard | None:
return next(iter(self.find_authorized(verse_id, role, leases, shard_id, at)), None)
def get(self, peer_id: str) -> CultMeshPeerCard | None:
require_non_empty(peer_id, "peer_id")
return self._peers.get(peer_id)
def _publish(self, peer: CultMeshPeerCard) -> None:
for callback in list(self._subscribers):
callback(peer)
@dataclass(frozen=True)
class CultMeshAuthorityLease:
lease_id: str
verse_id: str
peer_id: str
roles: tuple[str, ...]
valid_from: datetime
expires_at: datetime
shard_ids: tuple[str, ...] = ()
issuer_runtime_id: str = "local"
signature: str | None = None
def __post_init__(self) -> None:
object.__setattr__(self, "roles", _clean_tuple(self.roles))
object.__setattr__(self, "shard_ids", _clean_tuple(self.shard_ids))
def signature_payload(self) -> bytes:
return msgpack.packb([
"cultmesh.authority_lease.v0",
self.lease_id,
self.verse_id,
self.peer_id,
list(self.roles),
self.valid_from.isoformat(),
self.expires_at.isoformat(),
list(self.shard_ids),
self.issuer_runtime_id,
], use_bin_type=True)
def with_signature(self, signature: str) -> "CultMeshAuthorityLease":
require_non_empty(signature, "signature")
return replace(self, signature=signature)
def is_valid_at(self, at: datetime) -> bool:
return self.valid_from <= at < self.expires_at
def covers(
self,
peer: CultMeshPeerCard,
role: str,
shard_id: str | None = None,
at: datetime | None = None,
) -> bool:
require_non_empty(role, "role")
checked_at = at or datetime.now(self.valid_from.tzinfo)
return (
self.is_valid_at(checked_at)
and self.verse_id == peer.verse_id
and self.peer_id == peer.peer_id
and self.lease_id == peer.authority_lease_id
and role in self.roles
and role in peer.roles
and (shard_id is None or not self.shard_ids or shard_id in self.shard_ids)
)
AuthorityLeaseVerifier = Callable[[CultMeshAuthorityLease], bool]
@dataclass(frozen=True)
class CultMeshHmacAuthorityLeaseVerifier:
keys_by_issuer: Mapping[str, bytes | str]
def sign(self, lease: CultMeshAuthorityLease) -> str:
key = self._key_for(lease.issuer_runtime_id)
digest = hmac.new(key, lease.signature_payload(), sha256).digest()
encoded = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii")
return f"hmac-sha256:{encoded}"
def issue(self, lease: CultMeshAuthorityLease) -> CultMeshAuthorityLease:
return lease.with_signature(self.sign(lease))
def verify(self, lease: CultMeshAuthorityLease) -> bool:
signature = lease.signature or ""
if not signature:
return False
try:
expected = self.sign(lease)
except KeyError:
return False
return hmac.compare_digest(signature, expected)
def _key_for(self, issuer_runtime_id: str) -> bytes:
key = self.keys_by_issuer[issuer_runtime_id]
return key.encode("utf-8") if isinstance(key, str) else key
@dataclass
class CultMeshAuthorityLeaseCatalog:
_leases: dict[str, CultMeshAuthorityLease] = field(default_factory=dict)
signature_verifier: AuthorityLeaseVerifier | None = None
require_verified_signatures: bool = False
@property
def leases(self) -> tuple[CultMeshAuthorityLease, ...]:
return tuple(sorted(self._leases.values(), key=lambda lease: lease.lease_id))
def upsert(self, lease: CultMeshAuthorityLease) -> None:
require_non_empty(lease.lease_id, "lease.lease_id")
require_non_empty(lease.verse_id, "lease.verse_id")
require_non_empty(lease.peer_id, "lease.peer_id")
require_non_empty(lease.issuer_runtime_id, "lease.issuer_runtime_id")
if lease.expires_at <= lease.valid_from:
raise ValueError("CultMesh authority lease expiry must be after valid_from")
self._leases[lease.lease_id] = lease
def get(self, lease_id: str) -> CultMeshAuthorityLease | None:
require_non_empty(lease_id, "lease_id")
return self._leases.get(lease_id)
def is_authorized(
self,
peer: CultMeshPeerCard,
role: str,
shard_id: str | None = None,
at: datetime | None = None,
) -> bool:
require_non_empty(role, "role")
if not peer.authority_lease_id:
return False
lease = self._leases.get(peer.authority_lease_id)
if lease is None:
return False
if not self._is_verified(lease):
return False
return lease.covers(peer, role, shard_id, at)
def is_verified(self, lease_id: str) -> bool:
lease = self.get(lease_id)
return False if lease is None else self._is_verified(lease)
def _is_verified(self, lease: CultMeshAuthorityLease) -> bool:
if self.signature_verifier is None:
return not self.require_verified_signatures
return self.signature_verifier(lease)
ZERO_COPY_TRANSPORTS = {
"shared-memory",
"shared-d3d12-texture",
"shared-d3d11-texture",
"dma-buf",
"iosurface",
"ahardwarebuffer",
}
@dataclass(frozen=True)
class CultMeshStreamDescriptor:
stream_id: str
verse_id: str
owner_peer_id: str
kind: str
clock: dict[str, Any]
preferred_transports: tuple[str, ...]
label: str | None = None
audio: dict[str, Any] | None = None
video: dict[str, Any] | None = None
required_access: str = "read"
max_in_flight_frames: int | None = None
metadata_schema_id: str | None = None
@dataclass(frozen=True)
class CultMeshStreamConsumerProfile:
peer_id: str
verse_id: str
supported_transports: tuple[str, ...]
accepted_kinds: tuple[str, ...] = ()
can_import_gpu_handles: bool = False
can_map_shared_memory: bool = False
max_in_flight_frames: int | None = None
@dataclass(frozen=True)
class CultMeshStreamNegotiation:
stream_id: str
producer_peer_id: str
consumer_peer_id: str
transport: str
access: str
max_in_flight_frames: int
copy_budget: str
@dataclass(frozen=True)
class CultMeshStreamFrameHandle:
stream_id: str
sequence: int
timestamp_ns: int
transport: str
duration_ns: int | None = None
byte_length: int | None = None
native_handle: str | None = None
resource_key: str | None = None
page_ref: str | None = None
fence_handle: str | None = None
fence_value: int | None = None
unavoidable_copy_count: int | None = None
metadata: dict[str, Any] | None = None
@dataclass
class CultMeshStreamCatalog:
_streams: dict[str, CultMeshStreamDescriptor] = field(default_factory=dict)
_latest_frames: dict[str, CultMeshStreamFrameHandle] = field(default_factory=dict)
@property
def streams(self) -> list[CultMeshStreamDescriptor]:
return [self._streams[key] for key in sorted(self._streams)]
def declare(self, stream: CultMeshStreamDescriptor) -> CultMeshStreamDescriptor:
require_non_empty(stream.stream_id, "stream.stream_id")
require_non_empty(stream.verse_id, "stream.verse_id")
require_non_empty(stream.owner_peer_id, "stream.owner_peer_id")
require_non_empty(str(stream.clock.get("clockDomainId", "")), "stream.clock.clockDomainId")
if not stream.preferred_transports:
raise ValueError("stream.preferred_transports must not be empty")
self._streams[stream.stream_id] = stream
return stream
def get(self, stream_id: str) -> CultMeshStreamDescriptor | None:
require_non_empty(stream_id, "stream_id")
return self._streams.get(stream_id)
def find(self, verse_id: str, kind: str | None = None) -> list[CultMeshStreamDescriptor]:
require_non_empty(verse_id, "verse_id")
return [
stream
for stream in self.streams
if stream.verse_id == verse_id and (kind is None or stream.kind == kind)
]
def negotiate(self, stream_id: str, consumer: CultMeshStreamConsumerProfile) -> CultMeshStreamNegotiation:
stream = self.get(stream_id)
if stream is None:
raise ValueError(f"Unknown CultMesh stream {stream_id!r}")
if consumer.verse_id != stream.verse_id:
raise ValueError("stream and consumer must belong to the same Verse")
if consumer.accepted_kinds and stream.kind not in consumer.accepted_kinds:
raise ValueError(f"consumer does not accept {stream.kind} streams")
transport = next(
(candidate for candidate in stream.preferred_transports if candidate in consumer.supported_transports),
None,
)
if transport is None:
raise ValueError("stream and consumer have no compatible body transport")
stream_max = stream.max_in_flight_frames if stream.max_in_flight_frames is not None else 2**53 - 1
consumer_max = consumer.max_in_flight_frames if consumer.max_in_flight_frames is not None else 2**53 - 1
return CultMeshStreamNegotiation(
stream_id=stream.stream_id,
producer_peer_id=stream.owner_peer_id,
consumer_peer_id=consumer.peer_id,
transport=transport,
access=stream.required_access,
max_in_flight_frames=min(stream_max, consumer_max),
copy_budget=copy_budget_for(transport),
)
def publish_frame(self, frame: CultMeshStreamFrameHandle) -> CultMeshStreamFrameHandle:
require_non_empty(frame.stream_id, "frame.stream_id")
if frame.stream_id not in self._streams:
raise ValueError(f"Unknown CultMesh stream {frame.stream_id!r}")
self._latest_frames[frame.stream_id] = frame
return frame
def latest_frame(self, stream_id: str) -> CultMeshStreamFrameHandle | None:
require_non_empty(stream_id, "stream_id")
return self._latest_frames.get(stream_id)
def verse_catalog_request(message_id: str, *, verse_ids: list[str] | None = None, transport_version: str | None = None) -> dict[str, Any]:
return {
"schemaVersion": VERSE_CATALOG_REQUEST,
"messageId": message_id,
"verseIds": verse_ids,
"transportVersion": transport_version,
}
def peer_exchange_request(
message_id: str,
*,
verse_id: str,
roles: list[str] | None = None,
known_peer_ids: list[str] | None = None,
limit: int | None = None,
) -> dict[str, Any]:
return {
"schemaVersion": PEER_EXCHANGE_REQUEST,
"messageId": message_id,
"verseId": verse_id,
"roles": roles,
"knownPeerIds": known_peer_ids,
"limit": limit,
}
def verse_from_wire(value: dict[str, Any]) -> CultMeshVerseDescriptor:
compatibility = value.get("compatibility") or {}
return CultMeshVerseDescriptor(
verse_id=str(value["verseId"]),
display_name=str(value.get("displayName") or value["verseId"]),
authority_model=str(value.get("authorityModel") or ""),
compatibility=CultMeshVerseCompatibility(
transport_version=str(compatibility.get("transportVersion") or ""),
rules_hash=str(compatibility.get("rulesHash") or ""),
compatible_verse_ids=tuple(compatibility.get("compatibleVerseIds") or ()),
required_plugin_ids=tuple(compatibility.get("requiredPluginIds") or ()),
optional_plugin_ids=tuple(compatibility.get("optionalPluginIds") or ()),
),
discovery_endpoints=tuple(value.get("discoveryEndpoints") or ()),
authority_runtime_ids=tuple(value.get("authorityRuntimeIds") or ()),
parent_verse_id=value.get("parentVerseId"),
description=value.get("description"),
)
def peer_from_wire(value: dict[str, Any]) -> CultMeshPeerCard:
return CultMeshPeerCard(
peer_id=str(value["peerId"]),
verse_id=str(value["verseId"]),
endpoints=tuple(value.get("endpoints") or ()),
roles=tuple(value.get("roles") or ()),
shard_ids=tuple(value.get("shardIds") or ()),
region=value.get("region"),
authority_lease_id=value.get("authorityLeaseId"),
expires_at=value.get("expiresAt"),
signature=value.get("signature"),
)
def require_non_empty(value: str, name: str) -> None:
if not value or not value.strip():
raise ValueError(f"{name} must be non-empty")
def _clean_tuple(values: tuple[str, ...]) -> tuple[str, ...]:
cleaned: list[str] = []
seen: set[str] = set()
for value in values:
if not value or not value.strip() or value in seen:
continue
cleaned.append(value)
seen.add(value)
return tuple(cleaned)
def copy_budget_for(transport: str) -> str:
if transport in ZERO_COPY_TRANSPORTS:
return "zero-copy-target"
if transport == "cultcache-page":
return "one-copy-fallback"
if transport == "inline-bytes":
return "opaque-runtime"
return "opaque-runtime"
SIMULATION_FACT_DOCUMENT_TYPE = "gamecult.mesh.simulation_fact"
SIMULATION_FACT_SCHEMA_VERSION = "gamecult.mesh.simulation_fact.v1"
@dataclass(frozen=True)
class CultMeshSimulationFact:
fact_id: str
shard_id: str
shard_epoch: int
frame: int
subject_id: str
claim_kind: str
claim_hash: str
claim_summary: str | None
witness_count: int
support_weight: float
total_weight: float
confidence: float
committed_at: str
@staticmethod
def compute_fact_id(candidate: dict[str, Any]) -> str:
canonical = "\x1f".join([
_candidate_string(candidate, "shardId", "shard_id"),
str(_candidate_int(candidate, "shardEpoch", "shard_epoch")),
str(_candidate_int(candidate, "frame", "frame")),
_candidate_string(candidate, "subjectId", "subject_id"),
_candidate_string(candidate, "claimKind", "claim_kind"),
])
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
@staticmethod
def create_record_key(candidate: dict[str, Any]) -> str:
return f"simulation:{CultMeshSimulationFact.compute_fact_id(candidate)}"
@staticmethod
def from_candidate(candidate: dict[str, Any], *, committed_at: str | None = None) -> "CultMeshSimulationFact":
return CultMeshSimulationFact(
fact_id=CultMeshSimulationFact.compute_fact_id(candidate),
shard_id=_candidate_string(candidate, "shardId", "shard_id"),
shard_epoch=_candidate_int(candidate, "shardEpoch", "shard_epoch"),
frame=_candidate_int(candidate, "frame", "frame"),
subject_id=_candidate_string(candidate, "subjectId", "subject_id"),
claim_kind=_candidate_string(candidate, "claimKind", "claim_kind"),
claim_hash=_candidate_string(candidate, "claimHash", "claim_hash"),
claim_summary=_candidate_optional_string(candidate, "claimSummary", "claim_summary"),
witness_count=_candidate_int(candidate, "witnessCount", "witness_count"),
support_weight=_candidate_float(candidate, "supportWeight", "support_weight"),
total_weight=_candidate_float(candidate, "totalWeight", "total_weight"),
confidence=_candidate_float(candidate, "confidence", "confidence"),
committed_at=committed_at or datetime.now(UTC).isoformat(),
)
simulation_fact_document: DocumentDefinition[CultMeshSimulationFact] = define_database_entry_type(
SIMULATION_FACT_DOCUMENT_TYPE,
[
("fact_id", 0),
("shard_id", 1),
("shard_epoch", 2),
("frame", 3),
("subject_id", 4),
("claim_kind", 5),
("claim_hash", 6),
("claim_summary", 7, None),
("witness_count", 8),
("support_weight", 9),
("total_weight", 10),
("confidence", 11),
("committed_at", 12),
],
cls=CultMeshSimulationFact,
name="fact_id",
indexes={"shard": "shard_id", "frame": "frame", "subject": "subject_id", "claim_kind": "claim_kind"},
schema_name=SIMULATION_FACT_DOCUMENT_TYPE,
schema_version=SIMULATION_FACT_SCHEMA_VERSION,
)
def _candidate_string(candidate: dict[str, Any], camel: str, snake: str) -> str:
value = candidate.get(camel, candidate.get(snake, ""))
if value is None:
return ""
return str(value)
def _candidate_optional_string(candidate: dict[str, Any], camel: str, snake: str) -> str | None:
value = candidate.get(camel, candidate.get(snake))
if value is None:
return None
return str(value)
def _candidate_int(candidate: dict[str, Any], camel: str, snake: str) -> int:
return int(candidate.get(camel, candidate.get(snake, 0)))
def _candidate_float(candidate: dict[str, Any], camel: str, snake: str) -> float:
return float(candidate.get(camel, candidate.get(snake, 0.0)))