diff --git a/OpenJibo/docs/feature-backlog.md b/OpenJibo/docs/feature-backlog.md index f195be3..ce35603 100644 --- a/OpenJibo/docs/feature-backlog.md +++ b/OpenJibo/docs/feature-backlog.md @@ -977,6 +977,7 @@ For `1.0.19`: 11. STT upgrade and noise screening - progress update (`2026-05-21`): added a low-signal short-turn screen in websocket finalization so filler-only fragments and stray single-token leftovers like `so command` get rejected before they can become bad turns, while preserving the existing yes/no and word-of-the-day short-turn flows 12. Hosted capture/storage plan / indexing for group testing + - progress update (`2026-05-21`): added a bundle helper so group testers can package raw capture trees, `capture-index.ndjson`, and exported fixtures into one zip handoff artifact 13. Binary-safe media storage / sync to cloud drive: OneDrive, Google Drive, Box, etc. 14. Provider-backed news and weather parity polish 15. Grocery list capability discovery and MVP selection diff --git a/OpenJibo/docs/live-jibo-capture.md b/OpenJibo/docs/live-jibo-capture.md index 8e0758a..544b8df 100644 --- a/OpenJibo/docs/live-jibo-capture.md +++ b/OpenJibo/docs/live-jibo-capture.md @@ -77,3 +77,18 @@ Useful helper scripts: - [scripts/cloud/get-websocket-capture-summary.sh](/OpenJibo/scripts/cloud/get-websocket-capture-summary.sh) - [scripts/cloud/import-websocket-capture-fixture.py](/OpenJibo/scripts/cloud/import-websocket-capture-fixture.py) - [live-jibo-test-runbook.md](/OpenJibo/docs/live-jibo-test-runbook.md) + +## Group Testing Handoff + +When you have a useful capture set and want to share it with another tester, bundle the capture root into a single zip so the raw events, capture index, and exported fixtures stay together. + +Recommended helper: + +- [scripts/cloud/New-CaptureBundle.ps1](/OpenJibo/scripts/cloud/New-CaptureBundle.ps1) + +The bundle includes: + +- `capture-index.ndjson` +- websocket and HTTP `*.events.ndjson` files +- exported `*.flow.json` fixtures +- a small `bundle-manifest.json` with file counts and source metadata diff --git a/OpenJibo/docs/release-1.0.19-plan.md b/OpenJibo/docs/release-1.0.19-plan.md index 32e4178..0e44685 100644 --- a/OpenJibo/docs/release-1.0.19-plan.md +++ b/OpenJibo/docs/release-1.0.19-plan.md @@ -85,6 +85,7 @@ The goal is to port these in small batches, capture the source-backed phrasing w - continue alarm/gallery/yes-no cleanup from `1.0.18` evidence where regressions are still open - improve short-turn STT reliability and low-signal screening - the latest STT pass adds a websocket-side low-signal screen for filler-only and stray single-token leftovers while keeping yes/no and word-of-the-day turns intact +- capture indexing and group-test handoff now have a bundle helper that packages raw event captures, the index manifest, and exported fixtures together for easier review/share flows ### 3. Pegasus-To-Cloud Platform Porting diff --git a/OpenJibo/scripts/cloud/New-CaptureBundle.ps1 b/OpenJibo/scripts/cloud/New-CaptureBundle.ps1 new file mode 100644 index 0000000..f66c6a3 --- /dev/null +++ b/OpenJibo/scripts/cloud/New-CaptureBundle.ps1 @@ -0,0 +1,101 @@ +param( + [string]$CaptureRoot = "..\..\captures", + [string]$BundleDirectory = "..\..\captures\bundles", + [string]$BundleName +) + +function Get-RelativePath { + param( + [Parameter(Mandatory = $true)] + [string]$BasePath, + [Parameter(Mandatory = $true)] + [string]$FullPath + ) + + $normalizedBase = [System.IO.Path]::GetFullPath($BasePath) + if (-not $normalizedBase.EndsWith([System.IO.Path]::DirectorySeparatorChar)) { + $normalizedBase = $normalizedBase + [System.IO.Path]::DirectorySeparatorChar + } + + $normalizedFull = [System.IO.Path]::GetFullPath($FullPath) + if (-not $normalizedFull.StartsWith($normalizedBase, [StringComparison]::OrdinalIgnoreCase)) { + throw "Path '$FullPath' is not under '$BasePath'." + } + + return $normalizedFull.Substring($normalizedBase.Length) +} + +$resolvedCaptureRoot = Resolve-Path -LiteralPath $CaptureRoot -ErrorAction Stop +$resolvedBundleDirectory = Resolve-Path -LiteralPath $BundleDirectory -ErrorAction SilentlyContinue +if (-not $resolvedBundleDirectory) { + $resolvedBundleDirectory = New-Item -ItemType Directory -Force -Path $BundleDirectory | Select-Object -ExpandProperty FullName +} +else { + $resolvedBundleDirectory = $resolvedBundleDirectory.Path +} + +if ([string]::IsNullOrWhiteSpace($BundleName)) { + $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" + $BundleName = "capture-bundle-$timestamp" +} + +$stagingDirectory = Join-Path $resolvedBundleDirectory "$BundleName.staging" +$archivePath = Join-Path $resolvedBundleDirectory "$BundleName.zip" + +if (Test-Path -LiteralPath $stagingDirectory) { + Remove-Item -LiteralPath $stagingDirectory -Recurse -Force +} + +New-Item -ItemType Directory -Force -Path $stagingDirectory | Out-Null + +try { + $sourceFiles = Get-ChildItem -LiteralPath $resolvedCaptureRoot -Recurse -File | Where-Object { + $_.Name -eq "capture-index.ndjson" -or + $_.Name -like "*.events.ndjson" -or + $_.Name -like "*.flow.json" + } + + if (-not $sourceFiles) { + Write-Host "No capture files were found under $resolvedCaptureRoot" + exit 0 + } + + foreach ($file in $sourceFiles) { + $relativePath = Get-RelativePath -BasePath $resolvedCaptureRoot -FullPath $file.FullName + $destinationPath = Join-Path $stagingDirectory $relativePath + $destinationDirectory = Split-Path -Parent $destinationPath + + if (-not (Test-Path -LiteralPath $destinationDirectory)) { + New-Item -ItemType Directory -Force -Path $destinationDirectory | Out-Null + } + + Copy-Item -LiteralPath $file.FullName -Destination $destinationPath -Force + } + + $captureIndexFiles = @($sourceFiles | Where-Object { $_.Name -eq "capture-index.ndjson" }) + $eventFiles = @($sourceFiles | Where-Object { $_.Name -like "*.events.ndjson" }) + $fixtureFiles = @($sourceFiles | Where-Object { $_.Name -like "*.flow.json" }) + + $manifest = [ordered]@{ + createdUtc = (Get-Date).ToUniversalTime().ToString("O") + sourceRoot = $resolvedCaptureRoot + fileCount = $sourceFiles.Count + captureIndexCount = $captureIndexFiles.Count + eventFileCount = $eventFiles.Count + fixtureCount = $fixtureFiles.Count + } + + $manifest | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $stagingDirectory "bundle-manifest.json") -Encoding utf8 + + if (Test-Path -LiteralPath $archivePath) { + Remove-Item -LiteralPath $archivePath -Force + } + + Compress-Archive -Path (Join-Path $stagingDirectory '*') -DestinationPath $archivePath -Force + Write-Host "Created capture bundle at $archivePath" +} +finally { + if (Test-Path -LiteralPath $stagingDirectory) { + Remove-Item -LiteralPath $stagingDirectory -Recurse -Force + } +} diff --git a/OpenJibo/scripts/cloud/README.md b/OpenJibo/scripts/cloud/README.md index f8b82b4..909128b 100644 --- a/OpenJibo/scripts/cloud/README.md +++ b/OpenJibo/scripts/cloud/README.md @@ -16,6 +16,8 @@ These scripts help exercise the new .NET hosted cloud locally. Runs a small readiness checklist before the first physical Jibo test against the .NET cloud. - `Import-WebSocketCaptureFixture.ps1` Sanitizes an exported websocket capture fixture and copies it into the checked-in websocket fixture set. +- `New-CaptureBundle.ps1` + Packages the capture root, capture index, and exported fixtures into a single zip bundle for group testing handoff. - `start-dotnet-with-node-cert.sh` Starts the .NET API on Linux using the same PEM certificate material already used by the Node server. - `invoke-live-jibo-prep.sh`