param([string]$Python = "python") $ErrorActionPreference = "Stop" $Root = Split-Path -Parent $PSScriptRoot $ModelName = "anima-mixbit-6.44-proportional-vram.safetensors" $ExpectedBytes = 2264786514 $ExpectedSha = "e270d7e0cbeacd810030cfc6c4fd009ca7438eee46533bce0857d0e069d7054a" $ExpectedSeed = 260806701 $ExpectedPositive = "masterpiece, best quality, year 2025, newest, highres, absurdres, anime screenshot, official art, safe, 1girl, solo, original character, adult woman, short pink hair, teal eyes, futuristic magical courier, black and cyan jacket, pleated skirt over leggings, glowing star wand, leaping between neon city rooftops at night, dramatic foreshortening, colorful billboards, crescent moon, speed lines, energetic expression, vibrant colors, clean lineart, detailed cel shading" $ExpectedNegative = "worst quality, low quality, artist name, blurry, jpeg artifacts, chromatic aberration, photorealistic, realistic, 3d, monochrome, grayscale, simple background, malformed face, asymmetrical eyes, bad anatomy, bad hands, malformed hands, fused fingers, extra fingers, missing fingers, detached fingers, duplicated limbs, extra limbs, deformed, nsfw, explicit, watermark, signature, logo, text" try { $Required = @( ".gitattributes", ".gitignore", "README.md", $ModelName, "checksums\SHA256SUMS.txt", "comfyui\custom_nodes\AnimaMixBit\__init__.py", "comfyui\custom_nodes\AnimaMixBit\LICENSE", "comfyui\custom_nodes\AnimaMixBit\README.md", "comfyui\custom_nodes\AnimaMixBit\requirements.txt", "comfyui\custom_nodes\AnimaVRAMFusion\__init__.py", "comfyui\custom_nodes\AnimaVRAMFusion\LICENSE", "comfyui\custom_nodes\AnimaVRAMFusion\README.md", "comfyui\workflows\anima_mixbit_6_44_standard.json", "comfyui\workflows\anima_mixbit_6_44_standard_api.json", "comfyui\workflows\anima_mixbit_6_44_low_vram.json", "comfyui\workflows\anima_mixbit_6_44_proportional_vram_api.json", "docs\KNOWN_LIMITATIONS.md", "docs\contact_sheets\bf16_int8_mixbit_rtx3090.png", "licenses\LICENSE_CIRCLESTONE.md", "licenses\LICENSE_NVIDIA.md", "licenses\LICENSE_NVIDIA.pdf", "licenses\LICENSE_QWEN_APACHE_2.0.md", "licenses\NOTICE.md", "licenses\THIRD_PARTY_MODEL_COMPONENTS.md", "manifests\evaluation_manifest.json", "manifests\model_manifest.json", "scripts\check_gpu_compatibility.py", "scripts\verify_release.ps1" ) foreach ($Relative in $Required) { if (-not (Test-Path -LiteralPath (Join-Path $Root $Relative) -PathType Leaf)) { throw "Required file is missing: $Relative" } } $Removed = @( "README_JA.md", "README_EN.md", "PUBLICATION_STATUS.md", "RELEASE_NOTES.md", "HF_UPLOAD_GUIDE_JA.md", "docs\ANIMA_MIXBIT_6_44_REPORT_JA.html", "docs\contact_sheets\official_03.jpg", "manifests\rtx3090_standard_smoke.json" ) foreach ($Relative in $Removed) { if (Test-Path -LiteralPath (Join-Path $Root $Relative)) { throw "Retired release artifact remains: $Relative" } } $Model = Join-Path $Root $ModelName if ((Get-Item -LiteralPath $Model).Length -ne $ExpectedBytes) { throw "Model byte length mismatch." } $Hash = (Get-FileHash -LiteralPath $Model -Algorithm SHA256).Hash.ToLowerInvariant() if ($Hash -ne $ExpectedSha) { throw "Model SHA-256 mismatch: $Hash" } $HashCache = @{$Model = $Hash} foreach ($JsonFile in Get-ChildItem -LiteralPath $Root -Recurse -File -Filter "*.json") { $null = Get-Content -LiteralPath $JsonFile.FullName -Raw -Encoding utf8 | ConvertFrom-Json } $StandardApi = Get-Content -LiteralPath ( Join-Path $Root "comfyui\workflows\anima_mixbit_6_44_standard_api.json" ) -Raw -Encoding utf8 | ConvertFrom-Json if ($StandardApi."1".class_type -ne "AnimaMixedLowBitLoader" -or $StandardApi."1".inputs.model_name -ne $ModelName -or $StandardApi."4".inputs.text -ne $ExpectedPositive -or $StandardApi."5".inputs.text -ne $ExpectedNegative -or $StandardApi."8".inputs.seed -ne $ExpectedSeed -or $StandardApi."9".class_type -ne "VAEDecode") { throw "Standard API workflow contract is invalid." } $LowVramApi = Get-Content -LiteralPath ( Join-Path $Root "comfyui\workflows\anima_mixbit_6_44_proportional_vram_api.json" ) -Raw -Encoding utf8 | ConvertFrom-Json if ($LowVramApi."1".class_type -ne "AnimaVRAMProportionalLoader" -or $LowVramApi."1".inputs.model_name -ne $ModelName -or $LowVramApi."4".inputs.text -ne $ExpectedPositive -or $LowVramApi."5".inputs.text -ne $ExpectedNegative -or $LowVramApi."8".inputs.seed -ne $ExpectedSeed -or $LowVramApi."9".class_type -ne "VAEDecodeTiled" -or $LowVramApi."9".inputs.tile_size -ne 192 -or $LowVramApi."9".inputs.overlap -ne 64) { throw "Low-VRAM API workflow contract is invalid." } foreach ($UiContract in @( @{ Path = "comfyui\workflows\anima_mixbit_6_44_standard.json" Loader = "AnimaMixedLowBitLoader" Decode = "VAEDecode" }, @{ Path = "comfyui\workflows\anima_mixbit_6_44_low_vram.json" Loader = "AnimaVRAMProportionalLoader" Decode = "VAEDecodeTiled" } )) { $Workflow = Get-Content -LiteralPath (Join-Path $Root $UiContract.Path) -Raw -Encoding utf8 | ConvertFrom-Json $LoaderNode = $Workflow.nodes | Where-Object id -eq 44 $PositiveNode = $Workflow.nodes | Where-Object id -eq 11 $NegativeNode = $Workflow.nodes | Where-Object id -eq 12 $SamplerNode = $Workflow.nodes | Where-Object id -eq 19 $DecodeNode = $Workflow.nodes | Where-Object id -eq 8 if ($LoaderNode.type -ne $UiContract.Loader -or $LoaderNode.widgets_values[0] -ne $ModelName -or $PositiveNode.widgets_values[0] -ne $ExpectedPositive -or $NegativeNode.widgets_values[0] -ne $ExpectedNegative -or $SamplerNode.widgets_values[0] -ne $ExpectedSeed -or $DecodeNode.type -ne $UiContract.Decode) { throw "UI workflow contract is invalid: $($UiContract.Path)" } } $Requirements = Get-Content -LiteralPath ( Join-Path $Root "comfyui\custom_nodes\AnimaMixBit\requirements.txt" ) -Raw -Encoding utf8 if ($Requirements -notmatch "(?m)^comfy-kitchen>=0\.2\.26,<0\.3$") { throw "The tested comfy-kitchen dependency range is missing." } $Notice = Get-Content -LiteralPath ( Join-Path $Root "licenses\NOTICE.md" ) -Raw -Encoding utf8 foreach ($Attribution in @( "The CircleStone Model is licensed by CircleStone Labs LLC under the CircleStone Non-Commercial License.", "Copyright CircleStone Labs LLC.", "Licensed by NVIDIA Corporation under the NVIDIA Open Model License.", "Built on NVIDIA Cosmos." )) { if (-not $Notice.Contains($Attribution)) { throw "Required attribution is missing from NOTICE: $Attribution" } } $Evaluation = Get-Content -LiteralPath ( Join-Path $Root "manifests\evaluation_manifest.json" ) -Raw -Encoding utf8 | ConvertFrom-Json if ($Evaluation.schema -ne "anima.mixbit-6.44.public-evaluation.v5" -or $Evaluation.standard_comparison.hardware.gpu -ne "NVIDIA GeForce RTX 3090" -or $Evaluation.standard_comparison.inputs.cases[0].seed -ne $ExpectedSeed -or $Evaluation.standard_comparison.inputs.cases[0].positive -ne $ExpectedPositive -or $Evaluation.standard_comparison.inputs.negative -ne $ExpectedNegative -or $Evaluation.standard_comparison.variants.bf16.cold_start_baseline_mib -ne 4739 -or $Evaluation.standard_comparison.variants.bf16.overall_peak_mib_max -ne 10575 -or $Evaluation.standard_comparison.variants.bf16.required_additional_vram_mib -ne 5836 -or $Evaluation.standard_comparison.variants.int8.cold_start_baseline_mib -ne 4740 -or $Evaluation.standard_comparison.variants.int8.overall_peak_mib_max -ne 8838 -or $Evaluation.standard_comparison.variants.int8.required_additional_vram_mib -ne 4098 -or $Evaluation.standard_comparison.variants.int8.elapsed_seconds_median -ne 7.165 -or $Evaluation.standard_comparison.variants.mixbit.cold_start_baseline_mib -ne 4730 -or $Evaluation.standard_comparison.variants.mixbit.overall_peak_mib_max -ne 8485 -or $Evaluation.standard_comparison.variants.mixbit.required_additional_vram_mib -ne 3755 -or $Evaluation.low_vram_reference.fresh_sessions -ne 3 -or $Evaluation.low_vram_reference.readme_selected.cold_start_baseline_mib -ne 1498 -or $Evaluation.low_vram_reference.readme_selected.overall_peak_mib_max -ne 1988 -or $Evaluation.low_vram_reference.readme_selected.required_additional_vram_mib_max -ne 490 -or [Math]::Abs($Evaluation.low_vram_reference.readme_selected.elapsed_seconds_median_all_15 - 13.187079399940558) -gt 0.000000001 -or $Evaluation.low_vram_reference.summary.required_additional_vram_mib_median -ne 463 -or $Evaluation.low_vram_reference.summary.required_additional_vram_mib_max -ne 490 -or $Evaluation.low_vram_reference.summary.fallback_detected -or $Evaluation.low_vram_reference.summary.successful_outputs -ne 21 -or $Evaluation.low_vram_reference.summary.expected_outputs -ne 21 -or $Evaluation.low_vram_reference.same_gpu_standard_reference.required_additional_vram_mib_median -ne 3794 -or [Math]::Abs($Evaluation.low_vram_reference.same_gpu_standard_reference.low_vram_reduction_percent_median - 87.7965208223511) -gt 0.000000001 -or $Evaluation.low_vram_reference.same_gpu_standard_reference.fallback_detected -or $Evaluation.low_vram_reference.rtx3090_supported) { throw "Evaluation manifest contract is invalid." } & $Python -B (Join-Path $Root "scripts\check_gpu_compatibility.py") --self-test if ($LASTEXITCODE -ne 0) { throw "GPU compatibility self-test failed." } $env:ANIMA_RELEASE_ROOT = $Root $ImportCode = @' import importlib.util import os from pathlib import Path root = Path(os.environ["ANIMA_RELEASE_ROOT"]) contracts = ( ("anima_mixbit_public", "comfyui/custom_nodes/AnimaMixBit/__init__.py", {"AnimaMixedLowBitLoader"}), ("anima_vram_public", "comfyui/custom_nodes/AnimaVRAMFusion/__init__.py", {"AnimaVRAMProportionalLoader"}), ) for name, relative, expected in contracts: path = root / relative spec = importlib.util.spec_from_file_location(name, path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) if set(module.NODE_CLASS_MAPPINGS) != expected: raise RuntimeError(f"Unexpected public node exports: {relative}") '@ $ImportCode | & $Python -B - if ($LASTEXITCODE -ne 0) { throw "Custom-node import verification failed." } Remove-Item Env:\ANIMA_RELEASE_ROOT -ErrorAction SilentlyContinue $ChecksumPath = Join-Path $Root "checksums\SHA256SUMS.txt" $Listed = [System.Collections.Generic.HashSet[string]]::new( [System.StringComparer]::Ordinal ) $Verified = 0 foreach ($Line in Get-Content -LiteralPath $ChecksumPath -Encoding ascii) { if ($Line -notmatch "^([0-9a-f]{64}) (.+)$") { throw "Bad checksum line: $Line" } $Expected = $Matches[1] $Relative = $Matches[2] if (-not $Listed.Add($Relative)) { throw "Duplicate checksum path: $Relative" } $Path = Join-Path $Root ($Relative -replace "/", "\") if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { throw "Checksummed file is missing: $Relative" } $Actual = if ($HashCache.ContainsKey($Path)) { $HashCache[$Path] } else { (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() } if ($Actual -ne $Expected) { throw "Checksum mismatch: $Relative" } $HashCache[$Path] = $Actual $Verified++ } $ActualFiles = @( Get-ChildItem -LiteralPath $Root -Recurse -File | ForEach-Object { $_.FullName.Substring($Root.Length + 1).Replace("\", "/") } | Where-Object { $_ -ne "checksums/SHA256SUMS.txt" -and $_ -notlike ".cache/*" } ) foreach ($Relative in $ActualFiles) { if (-not $Listed.Contains($Relative)) { throw "Missing checksum: $Relative" } } if ($Listed.Count -ne $ActualFiles.Count) { throw "Checksum coverage mismatch." } $AudienceLabel = "Not-For-" + "All-Audiences" $AudienceAcronym = "NF" + "AA" $RetiredBrand = "Break" + "through" $Slash = [char]92 $LocalUserRoot = "C:" + $Slash + "Users" + $Slash $PrivateShareRoot = $Slash + $Slash + "MSI" + $Slash + "MSI" + $Slash $PrivateDataShareRoot = $Slash + $Slash + "MSI" + $Slash + "User" + "Data" + $Slash $PrivateAlias = "ka" + "nat" $MeasurementUserAlias = "ai" + "wit" $PrivateGpuIdentifier = "GPU-e460d949-" + "f905-c029-21fa-f005e01260a7" $PublicMarkerPattern = "(?i)" + [Regex]::Escape($AudienceLabel) + "|" + "\b" + [Regex]::Escape($AudienceAcronym) + "\b|" + [Regex]::Escape($RetiredBrand) $PersonalPattern = "(?i)" + [Regex]::Escape($LocalUserRoot) + "|" + [Regex]::Escape($PrivateShareRoot) + "|" + [Regex]::Escape($PrivateDataShareRoot) + "|" + "\b" + [Regex]::Escape($PrivateAlias) + "\b|" + "\b" + [Regex]::Escape($MeasurementUserAlias) + "\b|" + [Regex]::Escape($PrivateGpuIdentifier) foreach ($Readme in Get-ChildItem -LiteralPath $Root -Recurse -File -Filter "README*.md") { $Text = Get-Content -LiteralPath $Readme.FullName -Raw -Encoding utf8 if ($Text -match "(?i)sha-?256|$ExpectedSha") { throw "README contains a model hash: $($Readme.FullName)" } if ($Text -match "(?i)\bv1\.2\b") { throw "README contains a retired repository version label: $($Readme.FullName)" } if ($Text -match $PublicMarkerPattern) { throw "README contains a forbidden public marker: $($Readme.FullName)" } } $RootReadme = Get-Content -LiteralPath (Join-Path $Root "README.md") -Raw -Encoding utf8 $TableIndex = $RootReadme.IndexOf("| 比較 | Default Anima BF16 | INT8 ConvRot | MixBit 6.44 | MixBit 省VRAM |") $ImageIndex = $RootReadme.IndexOf("## 比較画像") $InstallIndex = $RootReadme.IndexOf("## 導入方法") $LicenseIndex = $RootReadme.IndexOf("## ライセンス") $EnglishIndex = $RootReadme.IndexOf("## English") if ($TableIndex -lt 0 -or $ImageIndex -le $TableIndex -or $InstallIndex -le $ImageIndex -or $LicenseIndex -le $InstallIndex -or $EnglishIndex -le $LicenseIndex) { throw "Root README section order is invalid." } foreach ($Marker in @( "RTX 3090で実測・対応", "RTX 3090は非対応", "VRAM・モデルロード前 → 最大値", "必要追加VRAM", "1,498 → **1,988 MiB**", "**490 MiB(3回最大)**", "13.187秒", "### 1. 通常モード", "### 2. 省VRAMモード", "Windows portable版", "bf16_int8_mixbit_rtx3090.png", "## Comparison image", "## Installation", "## License" )) { if (-not $RootReadme.Contains($Marker)) { throw "Root README is missing required guidance: $Marker" } } if ($RootReadme -match "(?i)INT8 (?:省VRAM|low-VRAM)") { throw "Root README still lists the removed INT8 low-VRAM mode." } if ($RootReadme -match "(?i)\bgit\s+(?:lfs|clone)\b") { throw "Root README still requires Git." } foreach ($RejectedPhrase in @( ("直接" + "比較できません"), ("推奨" + "tag構成"), ("not directly " + "comparable"), ("recommended Anima Aesthetic " + "tag structure") )) { if ($RootReadme.Contains($RejectedPhrase)) { throw "Root README contains rejected explanatory prose." } } $TextExtensions = ".md", ".json", ".ps1", ".py", ".txt", ".yml", ".yaml" $TextFiles = Get-ChildItem -LiteralPath $Root -Recurse -File | Where-Object { $_.Extension -in $TextExtensions } foreach ($TextFile in $TextFiles) { $Text = Get-Content -LiteralPath $TextFile.FullName -Raw -Encoding utf8 if ($Text -match $PersonalPattern) { throw "Personal or local path marker found: $($TextFile.FullName.Substring($Root.Length + 1))" } if ($Text -match $PublicMarkerPattern) { throw "Forbidden public marker found: $($TextFile.FullName.Substring($Root.Length + 1))" } $Bytes = [System.IO.File]::ReadAllBytes($TextFile.FullName) if ($Bytes.Length -ge 3 -and $Bytes[0] -eq 0xEF -and $Bytes[1] -eq 0xBB -and $Bytes[2] -eq 0xBF) { throw "UTF-8 BOM found: $($TextFile.FullName.Substring($Root.Length + 1))" } } foreach ($MarkdownFile in Get-ChildItem -LiteralPath $Root -Recurse -File -Filter "*.md") { $Markdown = Get-Content -LiteralPath $MarkdownFile.FullName -Raw -Encoding utf8 foreach ($Link in [Regex]::Matches($Markdown, "!?(?:\[[^\]]*\])\((?[^)]+)\)")) { $Target = $Link.Groups["target"].Value.Trim().Trim("<", ">") if ($Target -match "^(?i:https?|mailto):" -or $Target.StartsWith("#")) { continue } $Target = ($Target -split "#", 2)[0] if (-not $Target) { continue } $Resolved = Join-Path $MarkdownFile.DirectoryName ( [Uri]::UnescapeDataString($Target) -replace "/", "\" ) if (-not (Test-Path -LiteralPath $Resolved)) { throw "Broken Markdown link in $($MarkdownFile.Name): $Target" } } } $Forbidden = Get-ChildItem -LiteralPath $Root -Recurse -Force | Where-Object { $_.Name -eq ".cache" -or $_.Name -eq "__pycache__" -or $_.Extension -eq ".pyc" } if ($Forbidden) { throw "Cache or bytecode is present in the release." } Write-Output "PASS: package verified; $Verified checksums matched." exit 0 } catch { Remove-Item Env:\ANIMA_RELEASE_ROOT -ErrorAction SilentlyContinue [Console]::Error.WriteLine("FAIL: $($_.Exception.Message)") exit 2 }