返回 DeepSeek-Reasonix
windows-upgrade-ui-evidence.ps1
根目录 / scripts / windows-upgrade-ui-evidence.ps1
1 # The selector is deliberately scoped to the rendered transcript. Sidebar topic
2 # titles and offscreen accessibility nodes are not evidence of restored history.
3 function Get-UpgradeUIDescendants($element) {
4 return $element.FindAll([Windows.Automation.TreeScope]::Descendants, [Windows.Automation.Condition]::TrueCondition)
5 }
6
7 function Invoke-UpgradeUIButton($element) {
8 $pattern = $element.GetCurrentPattern([Windows.Automation.InvokePattern]::Pattern)
9 $pattern.Invoke()
10 }
11
12 function Invoke-PendingHistoricalSession($root) {
13 foreach ($element in (Get-UpgradeUIDescendants $root)) {
14 $current = $element.Current
15 if ($current.AutomationId -eq 'reasonix-prepare-restored-session' -and -not $current.IsOffscreen -and
16 $current.BoundingRectangle.Width -gt 0 -and $current.BoundingRectangle.Height -gt 0) {
17 Invoke-UpgradeUIButton $element
18 return $true
19 }
20 }
21 return $false
22 }
23
24 function Get-UpgradeUITimeMilliseconds {
25 return [long]([Diagnostics.Stopwatch]::GetTimestamp() * 1000.0 / [Diagnostics.Stopwatch]::Frequency)
26 }
27
28 function Wait-UpgradeUIPoll { Start-Sleep -Milliseconds 250 }
29
30 # This is functional recovery acceptance, not a cold-import latency SLO. A
31 # loaded Windows runner can spend the old entire 20-second budget importing,
32 # activating and exposing the first Markdown body through UI Automation. Keep
33 # a bounded completion wait and record its cost; startup readiness has its own
34 # separate deadline. Always sample before checking the deadline, including the
35 # final observation, instead of failing on a previously sampled empty surface.
36 function Wait-VisibleUpgradeHistory {
37 param(
38 [Parameter(Mandatory=$true)][scriptblock]$ReadRoot,
39 [Parameter(Mandatory=$true)][string]$Text,
40 [switch]$PrepareHistoricalSession,
41 [ValidateRange(1,300)][int]$TimeoutSeconds = 60
42 )
43 $started = Get-UpgradeUITimeMilliseconds
44 $prepared = -not $PrepareHistoricalSession
45 $found = $false
46 $root = $null
47 $polls = 0
48 while ($true) {
49 $root = & $ReadRoot
50 $polls++
51 if ($null -ne $root) {
52 if (-not $prepared) { $prepared = Invoke-PendingHistoricalSession $root }
53 # Lazy history is readable without activating a runtime. The import
54 # action blocks acceptance only when this wait was asked to prepare;
55 # otherwise it is the banner every unprepared legacy tab carries.
56 $found = Test-VisibleUpgradeHistory $root $Text -AllowPendingSource:(-not $PrepareHistoricalSession)
57 if ($found) { $prepared = $true }
58 }
59 $elapsed = (Get-UpgradeUITimeMilliseconds) - $started
60 if ($found -or $elapsed -ge ($TimeoutSeconds * 1000)) { break }
61 Wait-UpgradeUIPoll
62 }
63 return [pscustomobject]@{Root=$root; Found=$found; Prepared=$prepared; ElapsedMilliseconds=$elapsed; Polls=$polls; TimeoutSeconds=$TimeoutSeconds}
64 }
65
66 function Test-VisibleUpgradeHistory($root, [string]$text, [switch]$AllowPendingSource) {
67 if ([string]::IsNullOrWhiteSpace($text)) { return $false }
68 $descendants = @(Get-UpgradeUIDescendants $root)
69 foreach ($element in $descendants) {
70 $current = $element.Current
71 if ($current.IsOffscreen -or $current.BoundingRectangle.Width -le 0 -or $current.BoundingRectangle.Height -le 0) { continue }
72 # Old content alone cannot prove recovery: reject a still-loading/failed
73 # recovery surface and the obsolete chat notice that originally hid this bug.
74 if (([string]$current.AutomationId).StartsWith('reasonix-session-recovery-') -or
75 (-not $AllowPendingSource -and $current.AutomationId -eq 'reasonix-prepare-restored-session') -or
76 ([string]$current.Name).Contains('Failed to load conversation history.') -or
77 ([string]$current.Name).Contains('加载会话历史失败。') -or
78 ([string]$current.Name).Contains('載入會話歷史失敗。')) { return $false }
79 }
80 foreach ($transcript in $descendants) {
81 if (-not ([string]$transcript.Current.AutomationId).StartsWith('reasonix-chat-transcript-') -or $transcript.Current.IsOffscreen) { continue }
82 foreach ($element in (Get-UpgradeUIDescendants $transcript)) {
83 $current = $element.Current
84 if (-not $current.IsOffscreen -and $current.BoundingRectangle.Width -gt 0 -and $current.BoundingRectangle.Height -gt 0 -and
85 $current.Name.Contains($text)) { return $true }
86 }
87 }
88 return $false
89 }
90
90 lines Plain Text