param( [string]$OutputDir = "runs/login-reachability-probe-package" ) $ErrorActionPreference = "Stop" Set-StrictMode -Version Latest $repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path $packageScript = Join-Path $repo "scripts\package-login-reachability-probe.ps1" if (-not (Test-Path -LiteralPath $packageScript)) { throw "missing package script: $packageScript" } $packageRoot = Join-Path $repo $OutputDir $zipPath = "$packageRoot.zip" if (Test-Path -LiteralPath $packageRoot) { Remove-Item -LiteralPath $packageRoot -Recurse -Force } if (Test-Path -LiteralPath $zipPath) { Remove-Item -LiteralPath $zipPath -Force } & powershell -NoProfile -ExecutionPolicy Bypass -File $packageScript -OutputDir $OutputDir if ($LASTEXITCODE -ne 0) { throw "package-login-reachability-probe.ps1 failed with exit code $LASTEXITCODE" } $requiredFiles = @( "README.txt", "OPERATOR-STEPS.md", "TODO-COVERAGE.md", "EXPECTED-RETURN-FILES.txt", "LOGIN-REACHABILITY-INPUTS.template.json", "LOGIN-REACHABILITY-INPUTS.schema.json", "LOGIN-REACHABILITY-PACKAGE-MANIFEST.json", "RUN-LOGIN-REACHABILITY-SUITE.bat", "00-prepare-inputs.bat", "01-run-before-recorder.bat", "02-run-after-text-recorder.bat", "03-run-after-file-recorder.bat", "04-create-return-zip.bat", "CREATE-RETURN-ZIP.ps1", "compute-text-hash.ps1", "compute-file-hash.ps1", "optional-run-capability-smoke.bat", "docs\login-reachability-validation-items.md", "docs\send-upload-deep-dive.md", "tools\isphere-capability-smoke.exe", "recorder\ISphereLiveProbeRecorder.exe", "recorder\variants\ISphereLiveProbeRecorder-x86.exe" ) foreach ($relative in $requiredFiles) { $path = Join-Path $packageRoot $relative if (-not (Test-Path -LiteralPath $path)) { throw "missing package file: $relative" } } $instructionText = @( Get-Content -LiteralPath (Join-Path $packageRoot "README.txt") -Raw Get-Content -LiteralPath (Join-Path $packageRoot "OPERATOR-STEPS.md") -Raw Get-Content -LiteralPath (Join-Path $packageRoot "TODO-COVERAGE.md") -Raw Get-Content -LiteralPath (Join-Path $packageRoot "EXPECTED-RETURN-FILES.txt") -Raw Get-Content -LiteralPath (Join-Path $packageRoot "LOGIN-REACHABILITY-INPUTS.template.json") -Raw Get-Content -LiteralPath (Join-Path $packageRoot "LOGIN-REACHABILITY-PACKAGE-MANIFEST.json") -Raw ) -join "`n" foreach ($needle in @( "LOCAL_LOGIN_UNAVAILABLE", "ONLINE_LOGIN_REQUIRED", "NO_AUTOMATIC_SEND", "RUN-LOGIN-REACHABILITY-SUITE.bat", "LOGIN-REACHABILITY-OUTPUT.json", "run", "targets", "runtime", "reachability", "server_auth", "snapshots", "attempts", "failures", "correlation", "content_sha256", "file_sha256", "duplicate_second_send_attempted", "duplicate_second_file_send_attempted", "production_send_enabled", "production_file_send_enabled", "runtime_observations", "group_probe", "fallback_a_route", "TODO-COVERAGE", "backup_only" )) { if ($instructionText -notmatch [regex]::Escape($needle)) { throw "package instructions missing required phrase: $needle" } } if (-not (Test-Path -LiteralPath $zipPath)) { throw "missing package zip: $zipPath" } $inputsTemplate = Join-Path $packageRoot "LOGIN-REACHABILITY-INPUTS.template.json" $inputsPath = Join-Path $packageRoot "LOGIN-REACHABILITY-INPUTS.json" $inputs = Get-Content -LiteralPath $inputsTemplate -Raw | ConvertFrom-Json $inputs.run.operator_confirmed_logged_in = $true $inputs.run.operator_started_at_local = "2026-07-13T09:00:00+08:00" $inputs.run.operator_finished_at_local = "2026-07-13T09:05:00+08:00" $inputs.run.before_recorder_present = $true $inputs.run.one_shot_text_enabled = $true $inputs.run.one_shot_file_enabled = $true $inputs.run.one_text_send_only_confirmed = $true $inputs.run.one_file_send_only_confirmed = $true $inputs.targets.direct_jid = "test-direct@example.invalid" $inputs.targets.group_jid = "test-group@example.invalid" $inputs.targets.target_selection_source = "verify-script" $inputs.targets.self_send_or_sandbox_account_confirmed = $true $inputs.runtime_observations.app_context_manager_reachable = $true $inputs.runtime_observations.message_scheduling_reachable = $true $inputs.runtime_observations.chat_xmpp_authenticated = $true $inputs.runtime_observations.target_jid_mapping_observed = $true $inputs.runtime_observations.file_upload_para_observed = $true $inputs.runtime_observations.ifile_transfer_reachable = $true $inputs.runtime_observations.file_upload_result_file_id_observed = $true $inputs.runtime_observations.send_file_message_finalization_observed = $true $inputs.runtime_observations.notes = "synthetic runtime observations" $inputs.text_attempt.content_sha256 = ("a" * 64) $inputs.text_attempt.content_length = 16 $inputs.text_attempt.operator_clicked_send_at_local = "2026-07-13T09:01:00+08:00" $inputs.text_attempt.after_recorder_present = $true $inputs.text_attempt.success_ack_or_sent_record_present = $true $inputs.text_attempt.success_ack_or_sent_record = "synthetic sent-record ack for verify script" $inputs.text_attempt.duplicate_second_send_attempted = $false $inputs.file_attempt.allowed_dir = "C:\verify" $inputs.file_attempt.sandbox_file_path = "C:\verify\small.txt" $inputs.file_attempt.file_sha256 = ("b" * 64) $inputs.file_attempt.file_size_bytes = 12 $inputs.file_attempt.operator_clicked_send_file_at_local = "2026-07-13T09:03:00+08:00" $inputs.file_attempt.after_recorder_present = $true $inputs.file_attempt.file_upload_or_sent_record_present = $true $inputs.file_attempt.file_upload_or_sent_record = "synthetic file sent-record ack for verify script" $inputs.file_attempt.duplicate_second_file_send_attempted = $false $inputs.group_probe.enabled = $true $inputs.group_probe.group_jid = "test-group@example.invalid" $inputs.group_probe.chatroom_branch_observed = $true $inputs.group_probe.speech_permission_state = "allowed" $inputs.group_probe.upload_permission_state = "allowed" $inputs.fallback_a_route.enabled_if_b_route_fails = $true $inputs.fallback_a_route.hwnd = "0x1234" $inputs.fallback_a_route.rtbSendMessage_present = $true $inputs.fallback_a_route.btnSend_present = $true $inputs.fallback_a_route.btnSendFile_or_file_menu_present = $true $inputs.fallback_a_route.uia_or_screenshot_ref = "synthetic fallback evidence" $inputs.sent_record_source.source_type = "synthetic" $inputs.sent_record_source.source_path_or_ref = "verify-script" $inputs.sent_record_source.before_count = "1" $inputs.sent_record_source.after_count = "3" $inputs.sent_record_source.ack_or_ref_id = "verify-ack" $inputs.sent_record_source.correlation_notes = "synthetic verification only" $inputs | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $inputsPath -Encoding UTF8 $beforeProbeDir = Join-Path $packageRoot "return-evidence\before\isphere-live-probe-verify" $afterTextDir = Join-Path $packageRoot "return-evidence\after-text\isphere-live-probe-verify" $afterFileDir = Join-Path $packageRoot "return-evidence\after-file\isphere-live-probe-verify" New-Item -ItemType Directory -Force -Path $beforeProbeDir, $afterTextDir, $afterFileDir | Out-Null @' { "probe_mode": "verify", "target_count": 1, "host": { "is_64_bit_os": true, "is_64_bit_process": false, "machine_name": "VERIFY" }, "targets": [ { "pid": 1234, "process_name": "IMPlatformClient", "bitness": "x86", "assembly_presence": { "IMPlatformClient.exe": true, "smack.dll": true, "IMPP.Interface.dll": true, "IMPP.Service.dll": true, "IMPP.ServiceBase.dll": true } } ] } '@ | Set-Content -LiteralPath (Join-Path $beforeProbeDir "probe_client_runtime.json") -Encoding UTF8 @' { "entrypoints": [ { "id": "text_high_level_by_jid", "capability": "send_message", "assembly_found": true, "reflection_type_found": true, "reflection_method_found": true, "string_type_hint": true, "string_method_hint": true, "available": true, "reflection_error": "" }, { "id": "text_message_scheduler", "capability": "send_message", "assembly_found": true, "reflection_type_found": true, "reflection_method_found": true, "string_type_hint": true, "string_method_hint": true, "available": true, "reflection_error": "" }, { "id": "text_wire_chat_send", "capability": "send_message", "assembly_found": true, "reflection_type_found": true, "reflection_method_found": true, "string_type_hint": true, "string_method_hint": true, "available": true, "reflection_error": "" }, { "id": "file_service_upload", "capability": "send_file", "assembly_found": true, "reflection_type_found": true, "reflection_method_found": true, "string_type_hint": true, "string_method_hint": true, "available": true, "reflection_error": "" }, { "id": "file_wire_message", "capability": "send_file", "assembly_found": true, "reflection_type_found": true, "reflection_method_found": true, "string_type_hint": true, "string_method_hint": true, "available": true, "reflection_error": "" } ] } '@ | Set-Content -LiteralPath (Join-Path $beforeProbeDir "send_entrypoints_preflight.json") -Encoding UTF8 @' { "tcp": { "connection_count": 1, "connections": [ { "state": "ESTABLISHED", "remote_port": 5222 } ] } } '@ | Set-Content -LiteralPath (Join-Path $beforeProbeDir "network_inventory.json") -Encoding UTF8 @' { "target_process_seen": true, "initial_route_hint": "B_ROUTE_PROMISING" } '@ | Set-Content -LiteralPath (Join-Path $beforeProbeDir "feasibility_summary.json") -Encoding UTF8 "after text synthetic evidence" | Set-Content -LiteralPath (Join-Path $afterTextDir "dummy.txt") -Encoding UTF8 "after file synthetic evidence" | Set-Content -LiteralPath (Join-Path $afterFileDir "dummy.txt") -Encoding UTF8 Push-Location $packageRoot try { $returnOutput = & powershell -NoProfile -ExecutionPolicy Bypass -File ".\CREATE-RETURN-ZIP.ps1" 2>&1 $returnExit = $LASTEXITCODE } finally { Pop-Location } if ($returnExit -ne 0) { throw "CREATE-RETURN-ZIP.ps1 synthetic verification failed exit=$returnExit output=$($returnOutput -join "`n")" } $outputJson = Join-Path $packageRoot "LOGIN-REACHABILITY-OUTPUT.json" if (-not (Test-Path -LiteralPath $outputJson)) { throw "missing generated LOGIN-REACHABILITY-OUTPUT.json" } $output = Get-Content -LiteralPath $outputJson -Raw | ConvertFrom-Json foreach ($section in @("run", "targets", "runtime", "reachability", "server_auth", "snapshots", "attempts", "failures", "correlation")) { if ($null -eq $output.PSObject.Properties[$section]) { throw "LOGIN-REACHABILITY-OUTPUT.json missing section: $section" } } if ($output.run.validation_ok -ne $true) { throw "synthetic LOGIN-REACHABILITY-OUTPUT.json should have validation_ok=true" } [ordered]@{ ok = $true package_dir = (Resolve-Path -LiteralPath $packageRoot).Path zip = (Resolve-Path -LiteralPath $zipPath).Path required_file_count = $requiredFiles.Count synthetic_return_verified = $true online_login_required = $true no_automatic_send = $true production_send_enabled = $false production_file_send_enabled = $false } | ConvertTo-Json -Depth 6 -Compress