Implement native RLV callback service integration (#80)
This commit is contained in:
148
tools/check_milestone_10_issue_80.py
Normal file
148
tools/check_milestone_10_issue_80.py
Normal file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Audit issue 80's native RLV callback and service orchestration boundary."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import generate_api_shims
|
||||
import generate_surface
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SOURCE = ROOT / "crates" / "libremetaverse-rlv" / "src" / "service.rs"
|
||||
STATE = ROOT / "crates" / "libremetaverse-rlv" / "src" / "state.rs"
|
||||
GENERATED = ROOT / "crates" / "libremetaverse-rlv" / "src" / "generated.rs"
|
||||
SUPPORT = ROOT / "tests" / "compat" / "src" / "rlv_support.rs"
|
||||
QUERY_TESTS = ROOT / "tests" / "compat" / "tests" / "rlv_query_basics_semantics.rs"
|
||||
ACTION_TESTS = ROOT / "tests" / "compat" / "tests" / "rlv_attach_commands_semantics.rs"
|
||||
NOTIFY_TESTS = ROOT / "tests" / "compat" / "tests" / "rlv_notify_semantics.rs"
|
||||
DOC = ROOT / "crates" / "libremetaverse-rlv" / "README.md"
|
||||
WORKFLOW = ROOT / ".gitea" / "workflows" / "rust-workspace.yml"
|
||||
CATALOG = ROOT / "api" / "public-api.json"
|
||||
STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(")
|
||||
|
||||
TYPES = {
|
||||
"T:LibreMetaverse.RLV.AttachmentRequest": "crate::service::AttachmentRequest",
|
||||
"T:LibreMetaverse.RLV.RlvActionCallbacksDefault":
|
||||
"crate::service::RlvActionCallbacksDefault",
|
||||
"T:LibreMetaverse.RLV.RlvCallbacksDefault": "crate::service::RlvCallbacksDefault",
|
||||
"T:LibreMetaverse.RLV.RlvCommandProcessor": "crate::service::RlvCommandProcessor",
|
||||
"T:LibreMetaverse.RLV.RlvService": "crate::service::RlvService",
|
||||
}
|
||||
|
||||
|
||||
def require_markers(path: Path, markers: tuple[str, ...]) -> None:
|
||||
text = path.read_text()
|
||||
missing = [marker for marker in markers if marker not in text]
|
||||
if missing:
|
||||
raise SystemExit(f"{path.name}: audit evidence missing: " + ", ".join(missing))
|
||||
|
||||
|
||||
def catalog_members() -> set[str]:
|
||||
catalog = json.loads(CATALOG.read_text())
|
||||
assembly = next(
|
||||
value for value in catalog["assemblies"]
|
||||
if value["identity"]["name"] == "LibreMetaverse.RLV"
|
||||
)
|
||||
return {
|
||||
member["doc_id"]
|
||||
for api_type in assembly["types"]
|
||||
if api_type["doc_id"] in TYPES
|
||||
for member in api_type["members"]
|
||||
}
|
||||
|
||||
|
||||
def generated_type_block(text: str, doc_id: str) -> str:
|
||||
marker = f"/// C# type: `{doc_id}`."
|
||||
start = text.find(marker)
|
||||
if start < 0:
|
||||
raise SystemExit(f"generated declaration is missing for {doc_id}")
|
||||
next_type = text.find("/// C# type:", start + len(marker))
|
||||
return text[start:] if next_type < 0 else text[start:next_type]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
for api_type, declaration in TYPES.items():
|
||||
if generate_api_shims.NATIVE_TYPES.get(api_type) != declaration:
|
||||
raise SystemExit(f"issue 80 native type mapping is missing for {api_type}")
|
||||
members = catalog_members()
|
||||
if len(members) != 53:
|
||||
raise SystemExit(f"issue 80 expected 53 mapped members, found {len(members)}")
|
||||
|
||||
source = SOURCE.read_text()
|
||||
if STUB_RE.search(source):
|
||||
raise SystemExit("issue 80 owned Rust stubs remain in service.rs")
|
||||
if re.search(r"\b(?:Mutex|RwLock|read_lock|write_lock)\b", source):
|
||||
raise SystemExit("service.rs must not acquire internal locks around host callbacks")
|
||||
generated = GENERATED.read_text()
|
||||
for api_type in TYPES:
|
||||
if STUB_RE.search(generated_type_block(generated, api_type)):
|
||||
raise SystemExit(f"issue 80 owned generated stubs remain for {api_type}")
|
||||
if "pub trait IRlvActionCallbacks: Send + Sync" not in generated:
|
||||
raise SystemExit("action callbacks are not thread-safe")
|
||||
if "pub trait IRlvQueryCallbacks: Send + Sync" not in generated:
|
||||
raise SystemExit("query callbacks are not thread-safe")
|
||||
|
||||
catalog = json.loads((ROOT / "tests" / "upstream-tests.json").read_text())
|
||||
rlv_cases = [
|
||||
case for case in catalog["tests"]
|
||||
if case.get("rust_file", "").startswith("tests/compat/tests/rlv_")
|
||||
]
|
||||
if len(rlv_cases) != 616 or len({case["rust_file"] for case in rlv_cases}) != 24:
|
||||
raise SystemExit("issue 80 RLV parity catalog is not the complete 616-case slice")
|
||||
markers = generate_surface.scan_parity_markers(ROOT)
|
||||
evidence_keys = ("status", "rust_file", "rust_line", "rust_test", "rust_body_sha256")
|
||||
for case in rlv_cases:
|
||||
marker = markers.get(case["id"], [])
|
||||
if len(marker) != 1 or any(marker[0][key] != case[key] for key in evidence_keys):
|
||||
raise SystemExit(f"issue 80 parity metadata is stale for {case['id']}")
|
||||
|
||||
require_markers(SOURCE, (
|
||||
"MAX_RLV_MESSAGE_BYTES", "MAX_RLV_COMMANDS", "pub struct AttachmentRequest",
|
||||
"pub struct RlvActionCallbacksDefault", "pub struct RlvCallbacksDefault",
|
||||
"pub struct RlvCommandProcessor", "pub struct RlvService",
|
||||
"process_instant_message", "process_message", "process_restriction",
|
||||
"send_restriction_notification", "send_notification", "refresh_inventory",
|
||||
"report_inventory_offer_accepted", "report_item_attached",
|
||||
"report_send_public_message", "report_sit", "throw_if_cancellation_requested",
|
||||
"default_callbacks_observe_cancellation_without_side_effects",
|
||||
"attachment_request_hash_is_stable_and_value_based",
|
||||
))
|
||||
require_markers(STATE, (
|
||||
"set_action_callbacks", "notify_removed_restriction",
|
||||
"let removed = {", "let callbacks = read_lock", ".send_reply(",
|
||||
))
|
||||
require_markers(SUPPORT, (
|
||||
"struct RecordingActions", "struct RecordingQueries", "struct RlvHarness",
|
||||
"inventory_map.clone()", "RlvService::new",
|
||||
))
|
||||
require_markers(QUERY_TESTS, (
|
||||
"manual_blacklist_all", "manual_version", "get_environment_known_setting",
|
||||
"get_status_all_senders", "get_current_sit_id",
|
||||
))
|
||||
require_markers(ACTION_TESTS, (
|
||||
"attach_this_by_id", "attach_all_this_recursive",
|
||||
"attach_over_or_replace_uses_position_from_folder_name",
|
||||
))
|
||||
require_markers(NOTIFY_TESTS, (
|
||||
"notify_every_restriction", "notify_multiple_channels_filtered",
|
||||
"notify_inventory_offer", "notify_sit_and_stand_legal",
|
||||
))
|
||||
require_markers(DOC, (
|
||||
"Callback and service contract", "Send + Sync",
|
||||
"after releasing every manager lock", "completed inventory and agent",
|
||||
"616", "ubuntu-latest",
|
||||
))
|
||||
require_markers(WORKFLOW, ("python3 tools/check_milestone_10_issue_80.py",))
|
||||
print(
|
||||
"issue 80 audit: native callbacks, typed actions and queries, bounded service "
|
||||
"dispatch, inventory/agent adapters, cancellation, post-lock notifications, "
|
||||
"recording-fake workflows, compatibility evidence, and docs are present"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -38,6 +38,11 @@ TARGETS = {
|
||||
# implementations. The generated module keeps catalog markers and re-exports
|
||||
# the hand-written type so coverage remains deterministic.
|
||||
NATIVE_TYPES = {
|
||||
"T:LibreMetaverse.RLV.AttachmentRequest": "crate::service::AttachmentRequest",
|
||||
"T:LibreMetaverse.RLV.RlvActionCallbacksDefault": "crate::service::RlvActionCallbacksDefault",
|
||||
"T:LibreMetaverse.RLV.RlvCallbacksDefault": "crate::service::RlvCallbacksDefault",
|
||||
"T:LibreMetaverse.RLV.RlvCommandProcessor": "crate::service::RlvCommandProcessor",
|
||||
"T:LibreMetaverse.RLV.RlvService": "crate::service::RlvService",
|
||||
"T:LibreMetaverse.AISResponseMeta": "crate::inventory_ais::AISResponseMeta",
|
||||
"T:LibreMetaverse.AccountLevelBenefits": "crate::login::AccountLevelBenefits",
|
||||
"T:LibreMetaverse.AgentDisplayName": "crate::message_decoder::AgentDisplayName",
|
||||
@@ -2817,6 +2822,8 @@ TRAIT_SUPERTRAITS = {
|
||||
"T:LibreMetaverse.IBakingTextureProvider": "std::any::Any + Send + Sync",
|
||||
"T:LibreMetaverse.Interfaces.IMessage": "std::any::Any",
|
||||
"T:LibreMetaverse.Appearance.ICurrentOutfitPolicy": "Send + Sync",
|
||||
"T:LibreMetaverse.RLV.IRlvActionCallbacks": "Send + Sync",
|
||||
"T:LibreMetaverse.RLV.IRlvQueryCallbacks": "Send + Sync",
|
||||
}
|
||||
CORE_NAMESPACES = (
|
||||
"LibreMetaverse.Http",
|
||||
|
||||
Reference in New Issue
Block a user