feat: consolidate legacy parity migration baseline

This commit is contained in:
2026-07-20 22:06:12 +09:00
parent 5eb4054120
commit 4a54977341
66 changed files with 5391 additions and 460 deletions

View File

@@ -1,5 +1,11 @@
[CmdletBinding()]
param(
[ValidateSet('ReadOnly', 'DryRunPlayout', 'FullUiDb')]
[string]$Profile = 'ReadOnly',
[ValidateSet('All', 'PList', 'GraphE', 'Catalog', 'Screens')]
[string]$FullUiDbScope = 'All',
[ValidateRange(1024, 65535)]
[int]$Port = 9339,
@@ -12,7 +18,7 @@ param(
[ValidateRange(10, 120)]
[int]$LaunchTimeoutSeconds = 30,
[ValidateRange(30, 300)]
[ValidateRange(30, 900)]
[int]$HarnessTimeoutSeconds = 180
)
@@ -1544,6 +1550,8 @@ function Invoke-NodeHarnessUnderTcpWatch(
[string]$ScreenshotPath,
[string]$WindowsInputRequestPath,
[string]$WindowsInputAcknowledgementPath,
[string]$HarnessProfile,
[string]$HarnessScope,
[int]$TimeoutSeconds,
[Diagnostics.Process]$Application,
[string]$ExpectedApplicationPath) {
@@ -1559,6 +1567,10 @@ function Invoke-NodeHarnessUnderTcpWatch(
$WindowsInputRequestPath,
'--windows-input-ack',
$WindowsInputAcknowledgementPath,
'--profile',
$HarnessProfile,
'--scope',
$HarnessScope,
'--timeout-ms',
[string]($TimeoutSeconds * 1000)
) | ForEach-Object { ConvertTo-QuotedProcessArgument ([string]$_) }
@@ -2210,6 +2222,8 @@ function Read-AndAssertHarnessEvidence(
[string]$ScreenshotPath,
[string]$WindowsInputRequestPath,
[string]$WindowsInputAcknowledgementPath,
[string]$HarnessProfile,
[string]$HarnessScope,
[int]$ExpectedPort,
[int]$ExpectedTimeoutSeconds) {
try {
@@ -2218,7 +2232,52 @@ function Read-AndAssertHarnessEvidence(
$result = [string]$evidence.result
$safeResult = $result -ceq 'PASS' -or $result -ceq 'PASS_WITH_WARNING'
$warnings = @($evidence.warnings)
$expectedProfile = switch -CaseSensitive ($HarnessProfile) {
'FullUiDb' { 'full-ui-db'; break }
'DryRunPlayout' { 'dry-run-playout'; break }
default { 'read-only' }
}
$expectedScope = if ($HarnessProfile -ceq 'FullUiDb') {
$HarnessScope.ToLowerInvariant()
}
else {
'all'
}
$databaseWriteContractOk = if ($HarnessProfile -ceq 'FullUiDb') {
$evidence.safety.databaseWriteIntentIssued -eq $true -and
@($evidence.safety.approvedDatabaseWriteMessages).Count -ge 3 -and
[string]$evidence.fullUiDb.result -ceq 'PASS' -and
$evidence.fullUiDb.cleanupVerified -eq $true
}
else {
$evidence.safety.databaseWriteIntentIssued -eq $false -and
@($evidence.safety.approvedDatabaseWriteMessages).Count -eq 0 -and
$null -eq $evidence.fullUiDb
}
$playoutIntentContractOk = if ($HarnessProfile -ceq 'DryRunPlayout') {
$evidence.safety.playoutIntentIssued -eq $true -and
[string]$evidence.dryRunPlayout.result -ceq 'PASS' -and
-not [string]::IsNullOrWhiteSpace(
[string]$evidence.dryRunPlayout.selectedEntryId) -and
-not [string]::IsNullOrWhiteSpace(
[string]$evidence.dryRunPlayout.nextEntryId) -and
-not [string]::IsNullOrWhiteSpace(
[string]$evidence.dryRunPlayout.stagedEntryId) -and
[string]$evidence.dryRunPlayout.selectedEntryId -cne
[string]$evidence.dryRunPlayout.nextEntryId -and
[string]$evidence.dryRunPlayout.stagedEntryId -cne
[string]$evidence.dryRunPlayout.selectedEntryId -and
[int]$evidence.dryRunPlayout.playlistCountBeforeSelection -eq
[int]$evidence.dryRunPlayout.playlistCountAfterDoubleClick -and
[int]$evidence.dryRunPlayout.programCutSelection -ge 0
}
else {
$evidence.safety.playoutIntentIssued -eq $false -and
$null -eq $evidence.dryRunPlayout
}
if ([int]$evidence.schemaVersion -ne 1 -or
[string]$evidence.profile -cne $expectedProfile -or
[string]$evidence.scope -cne $expectedScope -or
-not $safeResult -or
($result -ceq 'PASS_WITH_WARNING' -and $warnings.Count -eq 0) -or
$null -ne $evidence.error -or
@@ -2231,8 +2290,8 @@ function Read-AndAssertHarnessEvidence(
[string]$evidence.safety.requiredMode -cne 'dryRun' -or
[string]$evidence.safety.requiredPhase -cne 'idle' -or
$evidence.safety.appCloseRequested -ne $false -or
$evidence.safety.playoutIntentIssued -ne $false -or
$evidence.safety.databaseWriteIntentIssued -ne $false -or
-not $playoutIntentContractOk -or
-not $databaseWriteContractOk -or
$evidence.safety.externalCancellationRequested -ne $false -or
@($evidence.safety.blockedOutboundMessages).Count -ne 0 -or
@($evidence.safety.stateViolations).Count -ne 0 -or
@@ -2241,14 +2300,30 @@ function Read-AndAssertHarnessEvidence(
Throw-SafeFailure 'The real input evidence does not satisfy the DryRun safety contract.'
}
$allowedOutbound = @(
'ready', 'search-stocks', 'select-stock', 'cut-pointer-down',
'cut-key-down', 'drop-selected-cuts', 'activate-playlist-row',
'select-playlist-row', 'reorder-playlist-rows',
'select-playlist-boundary', 'refresh-named-playlists')
foreach ($messageType in @($evidence.safety.observedOutboundMessageTypes)) {
if ($allowedOutbound -cnotcontains [string]$messageType) {
Throw-SafeFailure 'The evidence contains an outbound message outside the read-only allowlist.'
if ($HarnessProfile -ceq 'ReadOnly' -or
$HarnessProfile -ceq 'DryRunPlayout') {
$allowedOutbound = @(
'ready', 'search-stocks', 'select-stock', 'cut-pointer-down',
'cut-key-down', 'drop-selected-cuts', 'activate-playlist-row',
'select-playlist-row', 'reorder-playlist-rows',
'select-playlist-boundary', 'refresh-named-playlists')
if ($HarnessProfile -ceq 'DryRunPlayout') {
$allowedOutbound += @('take-in', 'next-playout', 'take-out')
}
foreach ($messageType in @($evidence.safety.observedOutboundMessageTypes)) {
if ($allowedOutbound -cnotcontains [string]$messageType) {
Throw-SafeFailure 'The evidence contains an outbound message outside the selected non-write allowlist.'
}
}
}
else {
$playoutMessages = @(
'prepare-playout', 'take-in', 'next-playout', 'take-out',
'choose-background', 'toggle-background')
foreach ($messageType in @($evidence.safety.observedOutboundMessageTypes)) {
if ($playoutMessages -ccontains [string]$messageType) {
Throw-SafeFailure 'The full UI/DB evidence contains a playout message.'
}
}
}
@@ -2338,7 +2413,9 @@ function Read-AndAssertHarnessEvidence(
$dragVisualCount = @($domPlaylist | Where-Object {
$_.dragging -eq $true -or $_.dragBefore -eq $true -or $_.dragAfter -eq $true
}).Count
if (-not (Test-ExactStringSequence $statePlaylistIds $expectedAfterOrder) -or
if (($HarnessProfile -ceq 'ReadOnly' -or
$HarnessProfile -ceq 'DryRunPlayout') -and (
-not (Test-ExactStringSequence $statePlaylistIds $expectedAfterOrder) -or
-not (Test-ExactStringSequence $domPlaylistIds $expectedAfterOrder) -or
-not (Test-ExactStringSequence $selectedStateIds @([string]$request.sourceRowId)) -or
-not (Test-ExactStringSequence $selectedDomIds @([string]$request.sourceRowId)) -or
@@ -2349,9 +2426,18 @@ function Read-AndAssertHarnessEvidence(
$activeDomIds `
@([string]$request.expectedActiveRowIdAfterHome)) -or
$dragVisualCount -ne 0 -or
@($dom.playlistPointerCapture.rowIds).Count -ne 0) {
@($dom.playlistPointerCapture.rowIds).Count -ne 0)) {
Throw-SafeFailure 'The sealed final playlist state does not match the Windows input result.'
}
$expectedFullUiDbPlaylistCount = if ($HarnessScope -ceq 'GraphE' -or
$HarnessScope -ceq 'Screens' -or $HarnessScope -ceq 'All') { 0 } else { 3 }
if ($HarnessProfile -ceq 'FullUiDb' -and (
$statePlaylist.Count -ne $expectedFullUiDbPlaylistCount -or
$domPlaylist.Count -ne $expectedFullUiDbPlaylistCount -or
$dragVisualCount -ne 0 -or
@($dom.playlistPointerCapture.rowIds).Count -ne 0)) {
Throw-SafeFailure 'The sealed full UI/DB playlist readback is not exact.'
}
return $evidence
}
@@ -2426,6 +2512,16 @@ try {
$Screenshot `
$WindowsInputRequest `
$WindowsInputAcknowledgement `
$(if ($Profile -ceq 'FullUiDb') {
'full-ui-db'
}
elseif ($Profile -ceq 'DryRunPlayout') {
'dry-run-playout'
}
else {
'read-only'
}) `
$(if ($Profile -ceq 'FullUiDb') { $FullUiDbScope.ToLowerInvariant() } else { 'all' }) `
$HarnessTimeoutSeconds `
$script:ApplicationProcess `
$registration.Executable
@@ -2447,6 +2543,8 @@ try {
$Screenshot `
$WindowsInputRequest `
$WindowsInputAcknowledgement `
$Profile `
$FullUiDbScope `
$Port `
$HarnessTimeoutSeconds
if ($null -eq $harnessRun.WindowsInput -or
@@ -2460,10 +2558,24 @@ try {
Assert-ExactApplicationStillRunning $script:ApplicationProcess $registration.Executable
Assert-NoTornadoConnection $script:ApplicationProcess.Id
$script:Phase = 'single-instance activation'
$singleInstance = Assert-SingleInstanceActivation `
$script:ApplicationProcess `
$registration.Executable
if ($Profile -cne 'FullUiDb') {
$script:Phase = 'single-instance activation'
$singleInstance = Assert-SingleInstanceActivation `
$script:ApplicationProcess `
$registration.Executable
}
else {
# The read-only package smoke already owns the single-instance contract.
# Avoid launching an unrelated redirector after an authorized DB-write run.
$singleInstance = [pscustomobject]@{
ActivationCalls = 0
ProcessCount = 1
RedirectorProcessId = $null
RedirectorStartTimeUtc = $null
RedirectorExited = $null
StableOriginalMilliseconds = $null
}
}
$script:Phase = 'normal close'
Invoke-ExactNormalClose $script:ApplicationProcess $registration.Executable

File diff suppressed because it is too large Load Diff

View File

@@ -32,14 +32,23 @@ if (-not [IO.Path]::IsPathRooted($NodePath) -or
$repositoryRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
$appScript = Join-Path $repositoryRoot 'src\MBN_STOCK_WEBVIEW.LegacyParityApp\Web\app.js'
$testFile = Join-Path $repositoryRoot 'tests\LegacyParityWeb\thin-client.test.cjs'
$testRoot = Join-Path $repositoryRoot 'tests\LegacyParityWeb'
$testFiles = @(
Get-ChildItem -LiteralPath $testRoot -Filter '*.test.cjs' -File |
Sort-Object -Property FullName |
Select-Object -ExpandProperty FullName
)
if ($testFiles.Count -eq 0) {
throw 'No Legacy parity Web test files were found.'
}
& $NodePath --check $appScript
if ($LASTEXITCODE -ne 0) {
throw "Legacy parity JavaScript syntax validation failed with exit code $LASTEXITCODE."
}
& $NodePath --test $testFile
& $NodePath --test @testFiles
if ($LASTEXITCODE -ne 0) {
throw "Legacy parity Web tests failed with exit code $LASTEXITCODE."
}