<# .SYNOPSIS Captures the native AVEVA client's DeleteTagExtendedProperties (DelTep) wire traffic (HCAL R1.11 delete half) using the CROSS-SESSION trick so the delete passes the client-side sync gate. .DESCRIPTION DeleteTagExtendedPropertiesByName does a CLIENT-SIDE sync check and returns err 229 ("Tag extended property not synchronized with server") for any property the local cache doesn't see as server-synchronized — so a just-added property can't be deleted in the same session and its DelTep inBuff never reaches the wire. This script captures it in two SEPARATE harness processes (= two sessions) against one instrumented aahClientManaged.dll: Run A: add-tep (create sandbox tag + AddTagExtendedProperties) -> property now server-synced Run B: add-tep --tep-skip-create --tep-skip-add --tep-delete -> fresh connection: fetch the property from the server (seeds the local cache as SYNCED), then DeleteTagExtendedPropertiesByName, which now reaches the wire as DelTep. The capture file is cleared BETWEEN the two runs so it contains only Run B (the GetTepByNm read-for-sync + the DelTep delete). Decode with scripts/decode-del-tep-capture.py. SAFETY: sandbox-guarded — the tag MUST start with 'RetestSdkWrite'. The run leaves the sandbox tag in place (property removed); delete the tag afterwards with the supported aaDeleteTag proc. .NOTES Artifacts are diagnostic and gitignored. Sanitize before copying into docs/. #> [CmdletBinding()] param( [string]$ServerName = "localhost", [int]$TcpPort = 32568, [string]$TepTag = "RetestSdkWriteDelTepSdk", [string]$PropName = "SdkDelProp", [string]$PropValue = "SdkDelValue", [string]$Configuration = "Debug" ) $ErrorActionPreference = "Stop" $repoRoot = Split-Path -Parent $PSScriptRoot Set-Location $repoRoot if (-not $TepTag.StartsWith("RetestSdkWrite")) { throw "-TepTag must start with 'RetestSdkWrite' (sandbox guard)." } $reProj = Join-Path $repoRoot "tools\AVEVA.Historian.ReverseEngineering\AVEVA.Historian.ReverseEngineering.csproj" $harnessProj = Join-Path $repoRoot "tools\AVEVA.Historian.NativeTraceHarness\AVEVA.Historian.NativeTraceHarness.csproj" $instrProj = Join-Path $repoRoot "tools\AVEVA.Historian.ReverseInstrumentation\AVEVA.Historian.ReverseInstrumentation.csproj" $captureDir = Join-Path $repoRoot "artifacts\reverse-engineering\instrumented-wcf-del-tep" $currentCopy = Join-Path $captureDir "current-copy" $instrDll = Join-Path $captureDir "aahClientManaged.dll" $capturePath = Join-Path $captureDir "del-tep-capture-latest.ndjson" Write-Host "== Building tooling ($Configuration) ==" -ForegroundColor Cyan dotnet build $reProj -c $Configuration --nologo -v q | Out-Null dotnet build $instrProj -c $Configuration --nologo -v q | Out-Null dotnet build $harnessProj -c $Configuration --nologo -v q | Out-Null $instrSourceDll = Get-ChildItem -Recurse (Join-Path $repoRoot "tools\AVEVA.Historian.ReverseInstrumentation\bin\$Configuration") ` -Filter "AVEVA.Historian.ReverseInstrumentation.dll" | Select-Object -First 1 -ExpandProperty FullName if (-not $instrSourceDll) { throw "ReverseInstrumentation.dll not found under bin\$Configuration." } Write-Host "== Instrumenting WriteMessage + ReadMessage ==" -ForegroundColor Cyan New-Item -ItemType Directory -Force -Path $captureDir | Out-Null $writeOnly = Join-Path $captureDir "aahClientManaged.write.dll" dotnet run --no-build -c $Configuration --project $reProj -- ` instrument-wcf-writemessage (Join-Path $repoRoot "current\aahClientManaged.dll") $writeOnly | Out-Null dotnet run --no-build -c $Configuration --project $reProj -- ` instrument-wcf-readmessage $writeOnly $instrDll | Out-Null Write-Host "== Staging current-copy ==" -ForegroundColor Cyan robocopy (Join-Path $repoRoot "current") $currentCopy /MIR /NJH /NJS /NDL /NP /NC /NS | Out-Null Copy-Item -Force $instrDll (Join-Path $currentCopy "aahClientManaged.dll") Copy-Item -Force $instrSourceDll (Join-Path $currentCopy "AVEVA.Historian.ReverseInstrumentation.dll") $harnessDll = Join-Path $currentCopy "aahClientManaged.dll" $env:AVEVA_HISTORIAN_RE_CAPTURE = $capturePath function Invoke-Harness([string[]]$extraArgs, [string]$label) { Write-Host "== $label ==" -ForegroundColor Green $harnessArgs = @( "--scenario", "add-tep", "--server-name", $ServerName, "--tcp-port", "$TcpPort", "--tep-tag", $TepTag, "--tep-name", $PropName, "--tep-value", $PropValue, "--current-dir", $currentCopy, "--managed-dll-path", $harnessDll ) + $extraArgs $json = $null try { $prevEap = $ErrorActionPreference $ErrorActionPreference = "Continue" $json = & dotnet run --no-build -c $Configuration --project $harnessProj -- @harnessArgs 2>&1 } finally { $ErrorActionPreference = $prevEap } $json | Select-Object -Last 20 } # Run A: create the sandbox tag + add the property (server-synced afterwards). Invoke-Harness @() "Run A: create + AddTagExtendedProperties ($TepTag : $PropName=$PropValue)" # Clear the capture so the file contains only Run B (read-for-sync + DelTep). if (Test-Path $capturePath) { Remove-Item -Force $capturePath } # Run B: FRESH session — fetch (sync the local cache) then DeleteTagExtendedPropertiesByName. Invoke-Harness @("--tep-skip-create", "--tep-skip-add", "--tep-delete") "Run B: fresh session -> read-for-sync -> DelTep" Remove-Item Env:\AVEVA_HISTORIAN_RE_CAPTURE -ErrorAction SilentlyContinue $recCount = if (Test-Path $capturePath) { (Get-Content $capturePath | Where-Object { $_.Trim() }).Count } else { 0 } Write-Host "`n== Capture summary (Run B only) ==" -ForegroundColor Cyan Write-Host " -> $recCount records -> $capturePath" Write-Host "`nDecode with: python scripts\decode-del-tep-capture.py" -ForegroundColor Cyan