Add Python CultMesh global document facade

This commit is contained in:
Meta Vens 2026-06-14 02:24:21 +01:00
commit 4d9474036d
3 changed files with 60 additions and 3 deletions

View file

@ -24,9 +24,12 @@ CultCache, CultNet, and CultMesh. It is evidence, not confetti.
- Python CultMesh database facade:
`node.database` owns the local typed document read/write/snapshot/sync surface
so Python callers do not need to reach through the node composition wrapper.
It also exposes local `watch(...)`, `watch_record(...)`, `watch_by_name(...)`,
and `watch_by_index(...)` callbacks for database changes, including
authoritative shard-log reconciliation applied through the session facade.
It includes global document helpers that delegate through the same singleton
key invariant as `CultCache`.
It also exposes local `watch(...)`, `watch_record(...)`, `watch_global(...)`,
`watch_by_name(...)`, and `watch_by_index(...)` callbacks for database changes,
including authoritative shard-log reconciliation applied through the session
facade.
Change notifications carry previous values when the database can observe the
old record before local or replicated application.
- Python CultMesh committed simulation facts:

View file

@ -44,6 +44,9 @@ class CultMeshNode:
def put(self, document: DocumentDefinition[Any], key: str, value: Any) -> None:
self.database.put(document, key, value)
def put_global(self, document: DocumentDefinition[Any], value: Any) -> None:
self.database.put_global(document, value)
def put_raw_message(
self,
document: DocumentDefinition[Any],
@ -69,9 +72,18 @@ class CultMeshNode:
def get_required(self, document: DocumentDefinition[Any], key: str) -> Any:
return self.database.get_required(document, key)
def get_global(self, document: DocumentDefinition[Any]) -> Any:
return self.database.get_global(document)
def get_required_global(self, document: DocumentDefinition[Any]) -> Any:
return self.database.get_required_global(document)
def delete(self, document: DocumentDefinition[Any], key: str) -> None:
self.database.delete(document, key)
def delete_global(self, document: DocumentDefinition[Any]) -> None:
self.database.delete_global(document)
def delete_raw_message(
self,
document: DocumentDefinition[Any],
@ -171,6 +183,13 @@ class CultMeshDatabase:
) -> Callable[[], None]:
return self.watch(callback, document=document, key=key)
def watch_global(
self,
document: DocumentDefinition[Any],
callback: Callable[[CultMeshDatabaseChange], None],
) -> Callable[[], None]:
return self.watch_record(document, self.cache.GLOBAL_KEY, callback)
def watch_by_name(
self,
document: DocumentDefinition[Any],
@ -224,6 +243,9 @@ class CultMeshDatabase:
self.cache.put(document, key, value)
self._publish_local_change(document, key, "added" if previous is None else "updated", value, previous)
def put_global(self, document: DocumentDefinition[Any], value: Any) -> None:
self.put(document, self.cache.GLOBAL_KEY, value)
def put_raw_message(
self,
document: DocumentDefinition[Any],
@ -262,12 +284,21 @@ class CultMeshDatabase:
def get_required(self, document: DocumentDefinition[Any], key: str) -> Any:
return self.cache.get_required(document, key)
def get_global(self, document: DocumentDefinition[Any]) -> Any:
return self.cache.get_global(document)
def get_required_global(self, document: DocumentDefinition[Any]) -> Any:
return self.cache.get_required_global(document)
def delete(self, document: DocumentDefinition[Any], key: str) -> None:
previous = self.cache.get(document, key)
self.cache.delete(document, key)
if previous is not None:
self._publish_local_change(document, key, "removed", None, previous)
def delete_global(self, document: DocumentDefinition[Any]) -> None:
self.delete(document, self.cache.GLOBAL_KEY)
def delete_raw_message(
self,
document: DocumentDefinition[Any],

View file

@ -917,6 +917,29 @@ class CultCacheTests(unittest.TestCase):
with self.assertRaises(ValueError):
node.database.register_document(conflicting)
def test_cultmesh_database_global_document_facade_uses_singleton_key_and_watchers(self) -> None:
document = define_database_entry_type(
"mesh.global_settings",
[("theme", 0)],
global_document=True,
)
node = CultMesh.create_node(runtime_id="mesh-global")
node.database.register_document(document)
changes: list[CultMeshDatabaseChange] = []
node.database.watch_global(document, changes.append)
node.database.put_global(document, {"theme": "ash"})
node.put_global(document, {"theme": "ember"})
node.delete_global(document)
self.assertIsNone(node.database.get_global(document))
self.assertEqual([change.record_key for change in changes], [node.cache.GLOBAL_KEY] * 3)
self.assertEqual([change.change_kind for change in changes], ["added", "updated", "removed"])
self.assertEqual(changes[1].previous_value, {"theme": "ash"})
self.assertEqual(changes[2].previous_value, {"theme": "ember"})
with self.assertRaises(Exception):
node.database.put(document, "settings:wrong", {"theme": "bad"})
def test_cultmesh_database_watchers_observe_name_and_index_changes(self) -> None:
document = define_database_entry_type(
"mesh.named_watch",