CultLib/scripts/verify-reactive-document-scaling.ps1

105 lines
3.6 KiB
PowerShell
Raw Normal View History

param(
[string] $PythonPath = "",
[string] $NodePath = ""
)
$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot
$dotnet = Get-Command dotnet -ErrorAction Stop
$nodeExecutable = if ([string]::IsNullOrWhiteSpace($NodePath)) {
$node = Get-Command node -ErrorAction SilentlyContinue
if ($node) { $node.Source } else { Join-Path $env:ProgramFiles "nodejs\node.exe" }
}
else {
[IO.Path]::GetFullPath($NodePath)
}
if (-not (Test-Path -LiteralPath $nodeExecutable -PathType Leaf)) {
throw "Node.js executable not found: $nodeExecutable"
}
$pythonExecutable = if ([string]::IsNullOrWhiteSpace($PythonPath)) {
(Get-Command python -ErrorAction Stop).Source
}
else {
[IO.Path]::GetFullPath($PythonPath)
}
if (-not (Test-Path -LiteralPath $pythonExecutable)) {
throw "Python executable not found: $pythonExecutable"
}
$typescript = Join-Path $root "node_modules\typescript\bin\tsc"
if (-not (Test-Path -LiteralPath $typescript)) {
throw "TypeScript compiler not found: $typescript"
}
foreach ($dependency in @("cultcache-ts", "cultnet-ts")) {
$dependencyRoot = Join-Path $root "packages\$dependency"
Push-Location $dependencyRoot
try {
if ($dependency -eq "cultnet-ts") {
& $nodeExecutable (Join-Path $dependencyRoot "tools\generate-swarm-contracts.mjs")
if ($LASTEXITCODE -ne 0) {
throw "CultNet TypeScript contract generation failed."
}
}
& $nodeExecutable $typescript -p tsconfig.json --pretty false
if ($LASTEXITCODE -ne 0) {
throw "TypeScript dependency build failed: $dependency"
}
}
finally {
Pop-Location
}
}
& $dotnet.Source test (Join-Path $root "tests\GameCult.Mesh.Tests\GameCult.Mesh.Tests.csproj") `
--filter "FullyQualifiedName~ReactiveDocument_SchedulingScalesWithChangedDocumentsOnly" `
--nologo `
--verbosity minimal
if ($LASTEXITCODE -ne 0) {
throw "CultMesh C# reactive scaling verification failed."
}
Push-Location (Join-Path $root "packages\cultmesh-ts")
try {
& $nodeExecutable $typescript -p tsconfig.json --pretty false
if ($LASTEXITCODE -ne 0) {
throw "CultMesh TypeScript source build failed."
}
& $nodeExecutable $typescript -p tsconfig.test.json --pretty false
if ($LASTEXITCODE -ne 0) {
throw "CultMesh TypeScript test build failed."
}
$testFiles = Get-ChildItem -LiteralPath .\dist-test\test -Filter "*.test.js" |
Sort-Object Name |
ForEach-Object FullName
& $nodeExecutable --test @testFiles
if ($LASTEXITCODE -ne 0) {
throw "CultMesh TypeScript reactive scaling verification failed."
}
}
finally {
Pop-Location
}
Split the Python runtime into cultcache-py, cultnet-py, cultmesh-py One distribution named cultcache-py carried three libraries. Rust and TypeScript layer them as cultcache < cultnet < cultmesh; Python now does the same, one package per layer, module names unchanged so every `from cultmesh_py import ...` keeps working. Two imports ran against that layering and are resolved by moving code to where the dependency direction says it lives, not by adding a shim: - cultnet_py.interop_peer imported the Verse/peer catalog, authority lease, stream, and simulation-fact contracts from cultmesh_py. They are wire contracts a bare peer has to speak without owning a node, which is why cultnet-rs and cultnet-ts keep them in the net layer. They now live in cultnet_py.cultmesh_contracts; cultmesh_py re-exports them. - cultcache_py.benchmark imported cultnet_py. It measures framed CultNet parse beside cache paths, so it and compare_csharp move to cultnet_py. verify checks all three packages and moves to cultmesh_py. The single 6,693-line test module is split by what each test touches: a test using any cultmesh_py name lands in cultmesh-py, else cultnet_py in cultnet-py, else cultcache-py. Each suite runs with only its layer and the layers below on the path, so a test that reaches up fails to import rather than quietly binding the packages back together. 11 / 53 / 78 = the same 142. Workflows install all three; the publish job is one matrix over the three packages keyed by tag prefix. The TS test harnesses put all three src directories on PYTHONPATH. cultcache-py bumps to 0.2.0 because it no longer contains cultnet_py or cultmesh_py; the new packages start at 0.1.0. Nothing was ever published, so no PyPI consumer moves. cultcache-py 11 tests, path: cultcache-py/src cultnet-py 53 tests, path: + cultnet-py/src cultmesh-py 78 tests, path: + cultmesh-py/src python -m cultmesh_py.verify -> ok, all five checks cultnet_py.interop_peer imports with cultmesh_py absent Not run here: the cultnet-ts interop ring and cultcache-ts store matrix need dotnet/kotlin peers; their PYTHONPATH change is four lines. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 13:10:47 +02:00
$pythonPath = (@("cultcache-py", "cultnet-py", "cultmesh-py") | ForEach-Object { Join-Path $root "packages\$_\src" }) -join [IO.Path]::PathSeparator
$previousPythonPath = $env:PYTHONPATH
$env:PYTHONPATH = if ([string]::IsNullOrWhiteSpace($previousPythonPath)) {
$pythonPath
}
else {
$pythonPath + [IO.Path]::PathSeparator + $previousPythonPath
}
try {
& $pythonExecutable -m unittest discover `
Split the Python runtime into cultcache-py, cultnet-py, cultmesh-py One distribution named cultcache-py carried three libraries. Rust and TypeScript layer them as cultcache < cultnet < cultmesh; Python now does the same, one package per layer, module names unchanged so every `from cultmesh_py import ...` keeps working. Two imports ran against that layering and are resolved by moving code to where the dependency direction says it lives, not by adding a shim: - cultnet_py.interop_peer imported the Verse/peer catalog, authority lease, stream, and simulation-fact contracts from cultmesh_py. They are wire contracts a bare peer has to speak without owning a node, which is why cultnet-rs and cultnet-ts keep them in the net layer. They now live in cultnet_py.cultmesh_contracts; cultmesh_py re-exports them. - cultcache_py.benchmark imported cultnet_py. It measures framed CultNet parse beside cache paths, so it and compare_csharp move to cultnet_py. verify checks all three packages and moves to cultmesh_py. The single 6,693-line test module is split by what each test touches: a test using any cultmesh_py name lands in cultmesh-py, else cultnet_py in cultnet-py, else cultcache-py. Each suite runs with only its layer and the layers below on the path, so a test that reaches up fails to import rather than quietly binding the packages back together. 11 / 53 / 78 = the same 142. Workflows install all three; the publish job is one matrix over the three packages keyed by tag prefix. The TS test harnesses put all three src directories on PYTHONPATH. cultcache-py bumps to 0.2.0 because it no longer contains cultnet_py or cultmesh_py; the new packages start at 0.1.0. Nothing was ever published, so no PyPI consumer moves. cultcache-py 11 tests, path: cultcache-py/src cultnet-py 53 tests, path: + cultnet-py/src cultmesh-py 78 tests, path: + cultmesh-py/src python -m cultmesh_py.verify -> ok, all five checks cultnet_py.interop_peer imports with cultmesh_py absent Not run here: the cultnet-ts interop ring and cultcache-ts store matrix need dotnet/kotlin peers; their PYTHONPATH change is four lines. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 13:10:47 +02:00
-s (Join-Path $root "packages\cultmesh-py\tests") `
-p "test_cultmesh.py" `
-k "reactive_scheduling_scales_with_changed_documents_only"
if ($LASTEXITCODE -ne 0) {
throw "CultMesh Python reactive scaling verification failed."
}
}
finally {
$env:PYTHONPATH = $previousPythonPath
}
Write-Output '{"runtimes":["csharp","typescript","python"],"documentCounts":[1,100,1000],"changedFraction":0.01,"idleSchedules":0,"invariant":"scheduling is proportional to explicitly changed documents"}'