This commit is contained in:
33333-33333 2026-06-03 18:47:09 +09:00
commit 06ab438d7b
13 changed files with 1167 additions and 3747 deletions

View file

@ -119,6 +119,18 @@ class WorldPolicyTest(unittest.TestCase):
self.assertIn("obj-a", state["tombstones"]["objects"])
self.assertEqual(len(state["dynamicSummons"]), 1)
def test_non_owner_can_delete_asset_and_all_placements(self):
state = base_state()
allowed, _ = can_delete_asset(state, {"id": "alice"}, "asset-b")
self.assertTrue(allowed)
result = apply_command(state, {"id": "alice"}, {"type": "asset.delete", "assetId": "asset-b"}, at=100)
self.assertTrue(result["accepted"])
self.assertTrue(apply_server_event(state, result["event"]))
self.assertNotIn("asset-b", [asset["id"] for asset in state["assets"]])
self.assertEqual(state["dynamicSummons"], [])
self.assertIn("asset-b", state["tombstones"]["assets"])
self.assertIn("dyn-b", state["tombstones"]["objects"])
def test_world_phase_event_updates_authoritative_clock(self):
state = base_state()

View file

@ -88,9 +88,7 @@ def can_delete_asset(state: MutableMapping[str, Any], account: MutableMapping[st
if not asset:
return False, {"reason": "asset_not_found"}
owner = str(asset.get("ownerAccountId") or "")
if actor == owner or is_admin(account):
return True, {"reason": None, "ownerAccountId": owner}
return False, {"reason": "not_asset_owner", "ownerAccountId": owner}
return True, {"reason": None, "ownerAccountId": owner}
def is_object_tombstoned(state: MutableMapping[str, Any], object_id: str, version: int = 0) -> bool:
@ -277,7 +275,7 @@ def apply_command(state: MutableMapping[str, Any], account: MutableMapping[str,
version = int(asset.get("version") or 0) + 1
object_tombstones: List[Dict[str, Any]] = []
for _, obj in iter_objects(state):
if str(obj.get("assetId") or "") == asset_id and (is_admin(account) or owner_of_object(state, obj) == actor):
if str(obj.get("assetId") or "") == asset_id:
object_tombstones.append({"id": str(obj["id"]), "deletedAt": at or now_ms(), "deletedBy": actor, "version": int(obj.get("version") or 0) + 1})
tombstone = {"id": asset_id, "deletedAt": at or now_ms(), "deletedBy": actor, "version": version}
return _accepted(_server_event("asset.delete", actor, {"assetId": asset_id, "assetVersion": version, "tombstone": tombstone, "objectTombstones": object_tombstones}, at))