#!/usr/bin/env python3 """Audit issue 66's appearance baking and initial-outfit boundary.""" from __future__ import annotations from pathlib import Path import re import generate_api_shims ROOT = Path(__file__).resolve().parents[1] APPEARANCE = ROOT / "crates" / "libremetaverse" / "src" / "appearance_manager.rs" BAKER = ROOT / "crates" / "libremetaverse" / "src" / "appearance_baker.rs" PROVIDER = ROOT / "crates" / "libremetaverse" / "src" / "baking_texture_provider.rs" OUTFIT = ROOT / "crates" / "libremetaverse" / "src" / "initial_outfit.rs" ASSETS = ROOT / "crates" / "libremetaverse" / "src" / "asset_models.rs" BAKER_TESTS = ROOT / "crates" / "libremetaverse" / "src" / "appearance_baker_semantics.rs" VISUAL_TESTS = ROOT / "crates" / "libremetaverse" / "tests" / "generated_catalogs.rs" COMPAT = ROOT / "tests" / "compat" / "tests" / "appearance_semantics.rs" DOC = ROOT / "docs" / "appearance.md" STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(") REQUIRED_TYPES = { "T:LibreMetaverse.AppearanceManager", "T:LibreMetaverse.Appearance.InitialOutfit", "T:LibreMetaverse.Appearance.InitialOutfit.InitialOutfitProgress", "T:LibreMetaverse.Appearance.InitialOutfitHandler", "T:LibreMetaverse.GridClientBakingTextureProvider", "T:LibreMetaverse.Imaging.Baker", } REQUIRED_MEMBERS = { "M:LibreMetaverse.AppearanceManager.DecodeWearableParams(LibreMetaverse.AppearanceManager.WearableData,LibreMetaverse.AppearanceManager.TextureData[]@)", "M:LibreMetaverse.AppearanceManager.MakeAppearancePacket", "M:LibreMetaverse.AppearanceManager.RequestCachedBakes", "M:LibreMetaverse.AppearanceManager.RequestSetAppearance(System.Boolean)", "M:LibreMetaverse.AppearanceManager.ServerBakingRegion", "M:LibreMetaverse.GridClientBakingTextureProvider.RequestTextureAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)", "M:LibreMetaverse.Imaging.Baker.Bake", "M:LibreMetaverse.Imaging.Baker.LoadResourceLayer(System.String)", "M:LibreMetaverse.Appearance.InitialOutfit.CopyFolderAsync(LibreMetaverse.InventoryFolder,LibreMetaverse.UUID,System.Threading.CancellationToken,System.IProgress{LibreMetaverse.Appearance.InitialOutfit.InitialOutfitProgress})", "M:LibreMetaverse.Appearance.InitialOutfit.SetInitialOutfitAsync(System.String,System.Threading.CancellationToken,System.IProgress{LibreMetaverse.Appearance.InitialOutfit.InitialOutfitProgress})", } 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 main() -> None: native = set(generate_api_shims.NATIVE_TYPES) | set(generate_api_shims.NATIVE_DECLARATIONS) missing_types = sorted(REQUIRED_TYPES - native) if missing_types: raise SystemExit("issue 66 native types missing: " + ", ".join(missing_types)) missing_members = sorted(REQUIRED_MEMBERS - set(generate_api_shims.NATIVE_MEMBER_BODIES)) if missing_members: raise SystemExit("issue 66 native members missing: " + ", ".join(missing_members)) for source in (APPEARANCE, BAKER, PROVIDER, OUTFIT, ASSETS): if STUB_RE.search(source.read_text()): raise SystemExit(f"issue 66 owned Rust stubs remain in {source.name}") require_markers(APPEARANCE, ( "baked_texture_hash", "wearable_bake_map", "AgentCachedTextureResponse", "AgentWearablesRequest", "AgentWearablesUpdate", "MAX_COF_ENTRIES", "RebakeAvatarTextures", "tokio::sync::Semaphore::new(5)", "tokio::sync::Semaphore::new(6)", "native_server_bake", "old_visual_parameters", "appearance_packet_contains_all_bakes", "legacy_wearables_packet_preserves_valid_item_asset_and_type_fields", )) require_markers(BAKER, ( "CLASSIC_BAKE_SIZE", "EYE_BAKE_SIZE", "self.textures.len() >= 60", "head_color.tga", "head_skingrain.tga", "apply_parameter_mask", "output.bump", "native_deep_clone", '#[cfg(feature = "jpeg2000")]', )) require_markers(PROVIDER, ("ClientWeakHandle", "request_image", "native_decode_image")) require_markers(OUTFIT, ( "MAX_FOLDERS", "Phase::Counting", "Phase::Copying", "Phase::Applying", "cleanup_folder", "compare_exchange", "native_replace_outfit", "handler_dispose_is_idempotent", )) require_markers(ASSETS, ( "native_from_asset", "parameters ", "textures ", "wearable_parser_preserves_parameters_and_texture_indices", )) require_markers(BAKER_TESTS, ("parity-case", "image.red[0]", "image.bump[0]")) require_markers(VISUAL_TESTS, ("visual_catalog_matches_the_pinned_character_fixture", "672", "253")) require_markers(COMPAT, ("baked_texture_hash", "wearable_bake_map", "texture_provider")) require_markers(DOC, ( "all 11", "downloads and six baked-texture uploads", "Counting`, `Copying`, `Applying`, then `Complete", "256-node", "big-endian", "218 normal or 251", "UpdateAvatarAppearance", )) print( "issue 66 audit: native bake composition, bounded texture transport, cache/server/local " "appearance paths, transactional initial outfit, documentation, and focused evidence are present" ) if __name__ == "__main__": main()