Integrate release recovery, semantic review, coverage and Windows packaging

This commit is contained in:
Codex
2026-09-06 16:31:55 -07:00
parent c091f80e6e
commit 2b2d2bc18b
174 changed files with 27635 additions and 127 deletions
+32
View File
@@ -0,0 +1,32 @@
# Real server coverage parity probe
Run with PowerShell7 on Windows against a built/staged server. The script launches
its own hidden server on a free loopback port, creates synthetic data under a fresh
timestamped `.local/rest-coverage-*` directory, captures25 requests/responses and
asserts diagnostic parity, invalid-write rejection, source preservation and restart.
It stops only its own process, including on failure. It never attaches to an
existing server and does not use user credentials. The token it creates is fixed
synthetic probe data, not suitable for a deployed server.
From the repository root, replace the executable path with the artifact under test:
```powershell
$env:PATH = "$env:SystemRoot\System32;$env:SystemRoot;$env:SystemRoot\System32\Wbem"
& harness/fixtures/rest-coverage/run-coverage-probe.ps1 -ServerExe 'C:\path\to\staged\arcadia-server.exe'
```
For gnullvm builds, stage the required runtime DLL beside the executable. Clean
PATH is deliberate: success should not depend on a developer compiler directory.
The first launch and restart use the same isolated store; restart is a forced
process stop after an acknowledged saved revision. This tests local persistence,
not graceful-drain handling. Output directories and evidence are retained.
`coverage-probe.json` has incomplete, repaired and invalid source bundles with
explicit synthetic UUIDs, plus five exact expected warning tuples. The repair
deliberately leaves an independent `sequence_gap` warning. The final reintroduction
of the incomplete bundle is an explicit replacement, not service Undo. No new API
or production code is required by the probe.
Observed Windows execution and limitations are recorded in
`harness/release-rest-coverage-verification-20260906.md`. This launch wrapper is
Windows-specific; the fixture and HTTP oracles can be reused on other platforms.
@@ -0,0 +1,58 @@
{
"incomplete": {
"entry": "project.arcadia",
"files": {
"work.arcadia": "// Synthetic OA fixture: known responsibilities, explicit incomplete contexts.\noa_entity crew \"Crew\" id \"f0660906-0000-4000-8000-000000000002\" {}\noa_activity activity_group \"Manage service\" id \"f0660906-0000-4000-8000-000000000010\" {\n oa_activity a \"Prepare\" id \"f0660906-0000-4000-8000-000000000011\" {}\n oa_activity b \"Deliver\" id \"f0660906-0000-4000-8000-000000000012\" {}\n}\noa_activity c \"Verify\" id \"f0660906-0000-4000-8000-000000000013\" {}\noa_capability q \"Reliable delivery\" id \"f0660906-0000-4000-8000-000000000020\" {}\noa_mission m \"Deliver reliably\" id \"f0660906-0000-4000-8000-000000000021\" {}\nallocation allocate_a \"Prepare responsibility\" id \"f0660906-0000-4000-8000-000000000041\" { source @crew; target @a; }\nallocation allocate_b \"Deliver responsibility\" id \"f0660906-0000-4000-8000-000000000042\" { source @crew; target @b; }\nallocation allocate_c \"Verify responsibility\" id \"f0660906-0000-4000-8000-000000000043\" { source @crew; target @c; }\ninteraction eab \"Prepared service\" id \"f0660906-0000-4000-8000-000000000050\" { source @a; target @b; }\ninteraction ep \"Grouped service\" id \"f0660906-0000-4000-8000-000000000051\" { source @activity_group; target @c; }\ninteraction eca \"Verified service\" id \"f0660906-0000-4000-8000-000000000052\" { source @c; target @a; }\ncapability_involvement support \"Crew support\" id \"f0660906-0000-4000-8000-000000000060\" { source @crew; target @q; }",
"behavior.arcadia": "oa_process delivery \"Delivery path\" id \"f0660906-0000-4000-8000-000000000030\" { steps [@ab_use]; }\noa_occurrence ab_use \"Use prepared service\" id \"f0660906-0000-4000-8000-000000000031\" {\n parent @delivery; body { Exchange { exchange @eab; sender none; receiver none; message_kind Asynchronous; reply_to none; values []; }; };\n}",
"project.arcadia": "arcadia 5; project coverage \"REST coverage parity\" id \"f0660906-0000-4000-8000-000000000001\" { include \"work.arcadia\"; include \"behavior.arcadia\"; }"
}
},
"repaired": {
"entry": "project.arcadia",
"files": {
"work.arcadia": "// Synthetic OA fixture: known responsibilities, explicit incomplete contexts.\noa_entity crew \"Crew\" id \"f0660906-0000-4000-8000-000000000002\" {}\noa_activity activity_group \"Manage service\" id \"f0660906-0000-4000-8000-000000000010\" {\n oa_activity a \"Prepare\" id \"f0660906-0000-4000-8000-000000000011\" {}\n oa_activity b \"Deliver\" id \"f0660906-0000-4000-8000-000000000012\" {}\n}\noa_activity c \"Verify\" id \"f0660906-0000-4000-8000-000000000013\" {}\noa_capability q \"Reliable delivery\" id \"f0660906-0000-4000-8000-000000000020\" {}\noa_mission m \"Deliver reliably\" id \"f0660906-0000-4000-8000-000000000021\" {}\nallocation allocate_a \"Prepare responsibility\" id \"f0660906-0000-4000-8000-000000000041\" { source @crew; target @a; }\nallocation allocate_b \"Deliver responsibility\" id \"f0660906-0000-4000-8000-000000000042\" { source @crew; target @b; }\nallocation allocate_c \"Verify responsibility\" id \"f0660906-0000-4000-8000-000000000043\" { source @crew; target @c; }\ninteraction eab \"Prepared service\" id \"f0660906-0000-4000-8000-000000000050\" { source @a; target @b; }\ninteraction ep \"Grouped service\" id \"f0660906-0000-4000-8000-000000000051\" { source @a; target @c; }\ninteraction eca \"Verified service\" id \"f0660906-0000-4000-8000-000000000052\" { source @c; target @a; }\ncapability_involvement support \"Crew support\" id \"f0660906-0000-4000-8000-000000000060\" { source @crew; target @q; }",
"behavior.arcadia": "oa_process delivery \"Delivery path\" id \"f0660906-0000-4000-8000-000000000030\" { steps [@ca_use, @ab_use, @pc_use]; }\noa_occurrence ab_use \"Use prepared service\" id \"f0660906-0000-4000-8000-000000000031\" {\n parent @delivery; body { Exchange { exchange @eab; sender none; receiver none; message_kind Asynchronous; reply_to none; values []; }; };\n}\noa_occurrence ca_use \"Use verified service\" id \"f0660906-0000-4000-8000-000000000032\" {\n parent @delivery; body { Exchange { exchange @eca; sender none; receiver none; message_kind Asynchronous; reply_to none; values []; }; };\n}\noa_occurrence pc_use \"Use responsible leaf exchange\" id \"f0660906-0000-4000-8000-000000000033\" {\n parent @delivery; body { Exchange { exchange @ep; sender none; receiver none; message_kind Asynchronous; reply_to none; values []; }; };\n}\nmission_capability mission_delivery \"Mission delivery\" id \"f0660906-0000-4000-8000-000000000061\" { source @m; target @q; }\nchain_involvement context \"Explicit delivery context\" id \"f0660906-0000-4000-8000-000000000062\" { source @delivery; target @q; }",
"project.arcadia": "arcadia 5; project coverage \"REST coverage parity\" id \"f0660906-0000-4000-8000-000000000001\" { include \"work.arcadia\"; include \"behavior.arcadia\"; }"
}
},
"invalid": {
"entry": "project.arcadia",
"files": {
"work.arcadia": "// Synthetic OA fixture: known responsibilities, explicit incomplete contexts.\noa_entity crew \"Crew\" id \"f0660906-0000-4000-8000-000000000002\" {}\noa_activity activity_group \"Manage service\" id \"f0660906-0000-4000-8000-000000000010\" {\n oa_activity a \"Prepare\" id \"f0660906-0000-4000-8000-000000000011\" {}\n oa_activity b \"Deliver\" id \"f0660906-0000-4000-8000-000000000012\" {}\n}\noa_activity c \"Verify\" id \"f0660906-0000-4000-8000-000000000013\" {}\noa_capability q \"Reliable delivery\" id \"f0660906-0000-4000-8000-000000000020\" {}\noa_mission m \"Deliver reliably\" id \"f0660906-0000-4000-8000-000000000021\" {}\nallocation allocate_a \"Prepare responsibility\" id \"f0660906-0000-4000-8000-000000000041\" { source @crew; target @a; }\nallocation allocate_b \"Deliver responsibility\" id \"f0660906-0000-4000-8000-000000000042\" { source @crew; target @b; }\nallocation allocate_c \"Verify responsibility\" id \"f0660906-0000-4000-8000-000000000043\" { source @crew; target @c; }\ninteraction eab \"Prepared service\" id \"f0660906-0000-4000-8000-000000000050\" { source @a; target @b; }\ninteraction ep \"Grouped service\" id \"f0660906-0000-4000-8000-000000000051\" { source @crew; target @c; }\ninteraction eca \"Verified service\" id \"f0660906-0000-4000-8000-000000000052\" { source @c; target @a; }\ncapability_involvement support \"Crew support\" id \"f0660906-0000-4000-8000-000000000060\" { source @crew; target @q; }",
"behavior.arcadia": "oa_process delivery \"Delivery path\" id \"f0660906-0000-4000-8000-000000000030\" { steps [@ab_use]; }\noa_occurrence ab_use \"Use prepared service\" id \"f0660906-0000-4000-8000-000000000031\" {\n parent @delivery; body { Exchange { exchange @eab; sender none; receiver none; message_kind Asynchronous; reply_to none; values []; }; };\n}",
"project.arcadia": "arcadia 5; project coverage \"REST coverage parity\" id \"f0660906-0000-4000-8000-000000000001\" { include \"work.arcadia\"; include \"behavior.arcadia\"; }"
}
},
"expected": [
{
"object_id": "f0660906-0000-4000-8000-000000000051",
"path": "work.arcadia",
"code": "non_leaf_work_exchange",
"field": "source"
},
{
"object_id": "f0660906-0000-4000-8000-000000000013",
"path": "work.arcadia",
"code": "work_without_behavior_context",
"field": null
},
{
"object_id": "f0660906-0000-4000-8000-000000000052",
"path": "work.arcadia",
"code": "exchange_without_behavior_context",
"field": null
},
{
"object_id": "f0660906-0000-4000-8000-000000000021",
"path": "work.arcadia",
"code": "mission_without_capability",
"field": null
},
{
"object_id": "f0660906-0000-4000-8000-000000000020",
"path": "work.arcadia",
"code": "capability_without_behavior_context",
"field": null
}
]
}
@@ -0,0 +1,137 @@
param([Parameter(Mandatory=$true)][string]$ServerExe)
$ErrorActionPreference = 'Stop'
$taskRoot = (Resolve-Path (Join-Path $PSScriptRoot '../../..')).Path
$exe = (Resolve-Path -LiteralPath $ServerExe).Path
$runRoot = Join-Path $taskRoot ('.local/rest-coverage-' + (Get-Date -Format 'yyyyMMdd-HHmmss'))
$storePath = Join-Path $runRoot 'store'
New-Item -ItemType Directory -Path $runRoot,$storePath | Out-Null
$payload = Get-Content -LiteralPath (Join-Path $PSScriptRoot 'coverage-probe.json') -Raw | ConvertFrom-Json -AsHashtable
$testToken = 'release-coverage-probe-20260906-local-only'
$tokenPath = Join-Path $runRoot 'synthetic-token.txt'
[IO.File]::WriteAllText($tokenPath,$testToken)
$listener = [Net.Sockets.TcpListener]::new([Net.IPAddress]::Loopback,0)
$listener.Start()
$probePort = $listener.LocalEndpoint.Port
$listener.Stop()
$base = "http://127.0.0.1:$probePort"
$script:probeProcess = $null
$script:sequence = 0
$script:launch = 0
$codes = @($payload.expected | ForEach-Object { $_.code })
function Assert-Probe($condition,[string]$message) { if (-not $condition) { throw $message } }
function Start-ProbeServer {
$script:launch++
$script:probeProcess = Start-Process -FilePath $exe -ArgumentList @('--bind',"127.0.0.1:$probePort",'--data-dir',('"'+$storePath+'"'),'--token-file',('"'+$tokenPath+'"')) -WindowStyle Hidden -PassThru -RedirectStandardOutput (Join-Path $runRoot "server-$script:launch.stdout.log") -RedirectStandardError (Join-Path $runRoot "server-$script:launch.stderr.log")
for ($attempt = 0; $attempt -lt 40; $attempt++) {
if ($script:probeProcess.HasExited) { throw 'Probe server exited before readiness' }
try { $ready=Invoke-WebRequest "$base/health/ready" -TimeoutSec 1; if ($ready.StatusCode -eq 200) { return } } catch {}
Start-Sleep -Milliseconds 250
}
throw 'Probe server did not become ready'
}
function Stop-ProbeServer {
if ($null -ne $script:probeProcess -and -not $script:probeProcess.HasExited) {
Stop-Process -InputObject $script:probeProcess
$script:probeProcess.WaitForExit()
}
$script:probeProcess = $null
}
function Call-Probe([string]$name,[string]$method,[string]$path,$body=$null,[string]$etag='',[int]$expectedStatus=200) {
$script:sequence++
$stem = Join-Path $runRoot ('{0:D2}-{1}' -f $script:sequence,$name)
$headers = @{Authorization="Bearer $testToken"}
if ($etag) { $headers['If-Match']=$etag }
$request = @{Uri="$base$path";Method=$method;Headers=$headers;SkipHttpErrorCheck=$true;TimeoutSec=40}
if ($null -ne $body) {
$json=ConvertTo-Json -InputObject $body -Depth 100 -Compress
[IO.File]::WriteAllText("$stem.request.json",$json)
$request.ContentType='application/json'
$request.Body=[Text.Encoding]::UTF8.GetBytes($json)
}
$response=Invoke-WebRequest @request
$content=[string]$response.Content
[IO.File]::WriteAllText("$stem.response.txt",$content)
$tag=[string]($response.Headers.ETag | Select-Object -First 1)
@{method=$method;path=$path;status=[int]$response.StatusCode;etag=$tag} | ConvertTo-Json | Set-Content -LiteralPath "$stem.meta.json"
Assert-Probe ($response.StatusCode -eq $expectedStatus) "$name expected $expectedStatus; got $($response.StatusCode): $content"
$data=$null
try { $data=ConvertFrom-Json -InputObject $content -AsHashtable } catch {}
return @{content=$content;data=$data;etag=$tag;headers=$response.Headers}
}
function Tuples($issues) {
return (@($issues | Where-Object { $_.code -in $codes } | ForEach-Object { "$($_.code)|$($_.object_id)|$($_.field)" } | Sort-Object) -join "`n")
}
function Assert-Coverage($response,[bool]$located=$false) {
$found=@($response.data.issues | Where-Object { $_.code -in $codes })
Assert-Probe ((Tuples $found) -ceq (Tuples $payload.expected)) 'Five exact coverage tuples differ'
Assert-Probe (@($response.data.issues | Where-Object severity -eq 'error').Count -eq 0) 'Unexpected structural error'
foreach ($issue in $found) {
Assert-Probe ($issue.severity -eq 'warning') 'Coverage is not warning severity'
if ($located) {
Assert-Probe ($issue.path -eq 'work.arcadia' -and $issue.line -ge 1 -and $issue.column -ge 1 -and $null -ne $issue.span) 'Missing submitted-source location'
}
}
}
function Assert-Bundle($actual,$expected) {
Assert-Probe ($actual.entry -ceq $expected.entry -and $actual.files.Count -eq $expected.files.Count) 'Bundle entry/file count changed'
foreach ($key in $expected.files.Keys) { Assert-Probe ($actual.files[$key] -ceq $expected.files[$key]) "Source bytes changed: $key" }
}
try {
@{exe=$exe;sha256=(Get-FileHash -LiteralPath $exe -Algorithm SHA256).Hash;port=$probePort;started=(Get-Date -Format o)} | ConvertTo-Json | Set-Content (Join-Path $runRoot 'run.json')
Start-ProbeServer
$created=Call-Probe 'create' 'POST' '/api/v1/projects' @{name='Coverage probe host'} '' 201
$path=[string]($created.headers.Location | Select-Object -First 1)
Assert-Probe ($path -like '/api/v1/projects/*') 'Create omitted resource Location'
$before=Call-Probe 'before-model' 'GET' "$path/model"
$beforeBundle=Call-Probe 'before-bundle' 'GET' "$path/source-project"
$candidate=Call-Probe 'incomplete-candidate' 'POST' "$path/validation" @{format='source-project';source_project=$payload.incomplete}
Assert-Probe $candidate.data.valid 'Incomplete model should be valid'
Assert-Coverage $candidate $true
$after=Call-Probe 'candidate-no-commit-model' 'GET' "$path/model"
$afterBundle=Call-Probe 'candidate-no-commit-bundle' 'GET' "$path/source-project"
Assert-Probe ($after.content -ceq $before.content -and $after.etag -ceq $before.etag) 'Candidate changed accepted model/revision'
Assert-Bundle $afterBundle.data $beforeBundle.data
$committed=Call-Probe 'commit-incomplete' 'PUT' "$path/source-project" $payload.incomplete $before.etag
Assert-Coverage $committed $true
Assert-Probe ($committed.data.changed -and $committed.etag -cne $before.etag) 'Warning-only commit did not advance revision'
$model=Call-Probe 'incomplete-model' 'GET' "$path/model"
$bundle=Call-Probe 'incomplete-bundle' 'GET' "$path/source-project"
Assert-Bundle $bundle.data $payload.incomplete
$source=Call-Probe 'incomplete-canonical' 'GET' "$path/source"
$validation=Call-Probe 'incomplete-validation' 'GET' "$path/validation"
Assert-Coverage $validation
$jsonCheck=Call-Probe 'json-parity' 'POST' "$path/validation" @{format='json';model=$model.data}
$textCheck=Call-Probe 'text-parity' 'POST' "$path/validation" @{format='arcadia';source=$source.content}
Assert-Coverage $jsonCheck
Assert-Coverage $textCheck
Assert-Probe ($jsonCheck.data.valid -and $textCheck.data.valid) 'JSON/text parity candidate invalid'
$invalid=Call-Probe 'invalid-candidate' 'POST' "$path/validation" @{format='source-project';source_project=$payload.invalid}
Assert-Probe (-not $invalid.data.valid -and @($invalid.data.issues | Where-Object { $_.code -eq 'invalid_endpoints' -and $_.severity -eq 'error' }).Count -ge 1) 'Invalid endpoint not diagnosed'
Assert-Probe ((Tuples $invalid.data.issues) -eq '') 'Structural error did not gate coverage'
$null=Call-Probe 'invalid-write-rejected' 'PUT' "$path/source-project" $payload.invalid $model.etag 422
$unchanged=Call-Probe 'rejection-model' 'GET' "$path/model"
$unchangedBundle=Call-Probe 'rejection-bundle' 'GET' "$path/source-project"
Assert-Probe ($unchanged.content -ceq $model.content -and $unchanged.etag -ceq $model.etag) 'Rejected write changed model/revision'
Assert-Bundle $unchangedBundle.data $bundle.data
$fixed=Call-Probe 'repair-write' 'PUT' "$path/source-project" $payload.repaired $model.etag
Assert-Probe ((Tuples $fixed.data.issues) -eq '') 'Repair left coverage warnings'
$fixedModel=Call-Probe 'repaired-model' 'GET' "$path/model"
$fixedBundle=Call-Probe 'repaired-bundle' 'GET' "$path/source-project"
Assert-Bundle $fixedBundle.data $payload.repaired
$fixedValidation=Call-Probe 'repaired-validation' 'GET' "$path/validation"
Stop-ProbeServer
Start-ProbeServer
$reopened=Call-Probe 'restart-model' 'GET' "$path/model"
$reopenedBundle=Call-Probe 'restart-bundle' 'GET' "$path/source-project"
$reopenedValidation=Call-Probe 'restart-validation' 'GET' "$path/validation"
Assert-Probe ($reopened.content -ceq $fixedModel.content -and $reopened.etag -ceq $fixedModel.etag) 'Restart changed model/revision'
Assert-Bundle $reopenedBundle.data $fixedBundle.data
Assert-Probe ($reopenedValidation.content -ceq $fixedValidation.content) 'Restart changed validation'
$again=Call-Probe 'restore-incomplete-by-replacement' 'PUT' "$path/source-project" $payload.incomplete $reopened.etag
Assert-Coverage $again $true
@{result='passed';requests=$script:sequence;resource=$path;initial_revision=$committed.data.revision;repaired_revision=$fixed.data.revision;final_revision=$again.data.revision;repair_issues=$fixed.data.issues;evidence=$runRoot} | ConvertTo-Json -Depth 20 | Set-Content (Join-Path $runRoot 'result.json')
Get-Content (Join-Path $runRoot 'result.json')
} catch {
$_ | Out-String | Set-Content (Join-Path $runRoot 'failure.txt')
throw
} finally { Stop-ProbeServer }