test(upserver): 归档存档迁移与玩法闭环回归工具

This commit is contained in:
Liubing\LB
2026-09-28 18:16:14 +08:00
parent c4ae02def9
commit a6f5e107f8
232 changed files with 12903 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
$ErrorActionPreference='Stop'
$root='C:/projects/ft/CodexOutput/upserver'
function Read-Backup($stamp) { Get-Content -Raw -LiteralPath "$root/KVGameplayLoopTests/backups/$stamp/102.json" | ConvertFrom-Json }
function Changed-Keys($left,$right) {
@(@($left.PSObject.Properties.Name)+@($right.PSObject.Properties.Name) | Sort-Object -Unique | Where-Object { $left.$_ -cne $right.$_ })
}
function Hash-Value([string]$value) {
$sha=[Security.Cryptography.SHA256]::Create()
try { [BitConverter]::ToString($sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($value))).Replace('-','') } finally { $sha.Dispose() }
}
$before=Read-Backup '20260928T024346Z'
$reward=Read-Backup '20260928T024903Z'
$closed=Read-Backup '20260928T025001Z'
$final=Read-Backup '20260928T025514Z'
$events=@(Get-Content -LiteralPath "$root/KVGameplayLoopTests/runs/44848_639261601944579366/events.jsonl" | ForEach-Object { $_ | ConvertFrom-Json })
$recoveryEvents=@(Get-Content -LiteralPath "$root/KVGameplayLoopTests/runs/103828_639261606481142886/events.jsonl" | ForEach-Object { $_ | ConvertFrom-Json })
$recovered=(Get-Content -Raw -LiteralPath "$root/KVFishingRewardTests/fourth-recovered-values.json" | ConvertFrom-Json).Result | ConvertFrom-Json
$preMain=$before.data.NewPlayerDataDic | ConvertFrom-Json
$postMain=$final.data.NewPlayerDataDic | ConvertFrom-Json
$preMap=$before.data.Map_5_102 | ConvertFrom-Json
$postMap=$final.data.Map_5_102 | ConvertFrom-Json
$rewardConfirmation=@($events | Where-Object kind -EQ 'fishing-reward-confirmed')[0]
$presentation=@($events | Where-Object kind -EQ 'fishing-reward-presented')[0]
$ticketMatches=@($rewardConfirmation.detail.tickets | ForEach-Object { [pscustomobject]@{key=$_.key;sequence=$_.sequence;matchesFinalServer=((Hash-Value $final.data.($_.key)) -ceq $_.valueHash)} })
$cacheResults=@('44848_639261601944579366','103828_639261606481142886' | ForEach-Object {
$cacheFile=Get-ChildItem -LiteralPath "$root/KVGameplayLoopTests/runs/$_/cache" -Recurse -Filter state.json
$cache=Get-Content -Raw -LiteralPath $cacheFile.FullName | ConvertFrom-Json
[pscustomobject]@{run=$_;pending=@($cache.pending).Count;unknown=($null -ne $cache.unknownBatch);active=($null -ne $cache.activeBatch);baselineChangedKeys=@(Changed-Keys $cache.baseline $final.data)}
})
$report=[ordered]@{
phase='4C2-fourth-real-run-and-fresh-process-recovery-awaiting-independent-review'
api=$recovered.api
backups=@('20260928T024346Z','20260928T024903Z','20260928T025001Z','20260928T025514Z')
countBefore=@($before.data.PSObject.Properties).Count;countAfter=@($final.data.PSObject.Properties).Count
changedKeys=@(Changed-Keys $before.data $final.data)
changedFishIds=@(Changed-Keys $preMap $postMap)
fishBefore=$preMap.'10223';fishAfter=$postMap.'10223'
mainBefore=$preMain;mainAfter=$postMain
rewardToQuitChangedKeys=@(Changed-Keys $reward.data $closed.data)
quitToRecoveryFinalChangedKeys=@(Changed-Keys $closed.data $final.data)
consumeCount=@($events | Where-Object kind -EQ 'fishing-energy-applied').Count
rewardConfirmedCount=@($events | Where-Object kind -EQ 'fishing-reward-confirmed').Count
rewardPresentedCount=@($events | Where-Object kind -EQ 'fishing-reward-presented').Count
confirmedBeforePresented=([DateTime]$rewardConfirmation.at -lt [DateTime]$presentation.at)
rewardTickets=$ticketMatches
faults=@($events | Where-Object kind -EQ 'fault').Count
recoveryFishingEvents=@($recoveryEvents | Where-Object kind -Like 'fishing-*').Count
recoveryWrites=@($recoveryEvents | Where-Object kind -EQ 'accepted').Count
recovered=$recovered
recoveredCoreEqualsFinalServer=($recovered.core -ceq $postMain.newData)
recoveredFishRawEqualsFinalServer=($recovered.fishRaw -ceq $postMap.'10223')
cacheResults=$cacheResults
signupGold=16200;fishingGold=2516;totalGold=18716
independentFormulaRecomputed=$false
precastIndependentBackupCaptured=$false
boundary='用户在主会话尚未完成动作前快照时手动签到并抛竿;precast/live-gates实际采样晚于扣费,不能充当动作前基线。保存完整审计和服务器前后值,交独立复核裁决证据是否充分,不自动重跑。鱼TotalNum由新进程KV有效值读回验证;活对象直接验证重量/等级/NewFish,未通过私有反射读取TotalNum。'
}
$report | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath "$root/KVFishingRewardTests/fourth-reconciliation.json" -Encoding utf8
$checks=@(
$report.api -ceq 'http://s101.local:18080/'
$report.consumeCount -eq 1
$report.rewardConfirmedCount -eq 1
$report.rewardPresentedCount -eq 1
$report.confirmedBeforePresented
$report.faults -eq 0
$report.recoveryFishingEvents -eq 0
$report.rewardToQuitChangedKeys.Count -eq 0
$report.quitToRecoveryFinalChangedKeys.Count -eq 0
$report.recoveredCoreEqualsFinalServer
$report.recoveredFishRawEqualsFinalServer
@($ticketMatches | Where-Object { -not $_.matchesFinalServer }).Count -eq 0
@($cacheResults | Where-Object { $_.pending -ne 0 -or $_.unknown -or $_.active -or $_.baselineChangedKeys.Count -ne 0 }).Count -eq 0
)
if($checks -contains $false) { throw 'Reconciliation assertion failed; inspect fourth-reconciliation.json' }
[pscustomobject]@{checks=$checks.Count;passed=$true;changedKeys=$report.changedKeys;changedFishIds=$report.changedFishIds;recoveryUnchanged=$true} | ConvertTo-Json -Depth 4