diff --git a/.github/workflows/cookiecutter-bootstrap.yml b/.github/workflows/cookiecutter-bootstrap.yml
index 9b76b493e..d52f92175 100644
--- a/.github/workflows/cookiecutter-bootstrap.yml
+++ b/.github/workflows/cookiecutter-bootstrap.yml
@@ -232,13 +232,13 @@ jobs:
run: npm ci
- name: Download Linux bootstrap artifact
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v8
with:
name: cookiecutter-bootstrap-linux
path: tests/results/_agent
- name: Download Windows bootstrap artifact
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v8
with:
name: cookiecutter-bootstrap-windows
path: tests/results/_agent
@@ -282,7 +282,7 @@ jobs:
- name: Upload template verification report
if: ${{ always() }}
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: template-agent-verification-${{ github.run_id }}
path: tests/results/_agent/promotion/template-agent-verification-report.json
diff --git a/.github/workflows/downstream-promotion.yml b/.github/workflows/downstream-promotion.yml
index 314bd08d4..0c0a3520b 100644
--- a/.github/workflows/downstream-promotion.yml
+++ b/.github/workflows/downstream-promotion.yml
@@ -324,7 +324,7 @@ jobs:
- name: Upload downstream promotion artifacts
if: ${{ always() && hashFiles('tests/results/_agent/onboarding/*.json', 'tests/results/_agent/promotion/*.json') != '' }}
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: downstream-promotion-${{ github.run_id }}
path: |
diff --git a/.github/workflows/publish-tools-image.yml b/.github/workflows/publish-tools-image.yml
index 96442227a..5ff116854 100644
--- a/.github/workflows/publish-tools-image.yml
+++ b/.github/workflows/publish-tools-image.yml
@@ -69,7 +69,7 @@ jobs:
--labels-file "$RUNNER_TEMP/tools-image-labels.txt"
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
+ uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
diff --git a/.github/workflows/release-conductor.yml b/.github/workflows/release-conductor.yml
index 7da0e9088..b8587422e 100644
--- a/.github/workflows/release-conductor.yml
+++ b/.github/workflows/release-conductor.yml
@@ -8,6 +8,11 @@ on:
required: false
default: false
type: boolean
+ repair_existing_tag:
+ description: 'Repair an existing authoritative tag as a signed annotated tag'
+ required: false
+ default: false
+ type: boolean
channel:
description: 'Release channel'
required: false
@@ -66,12 +71,82 @@ jobs:
run: |
pwsh -NoLogo -NoProfile -File tools/priority/Resolve-PolicyToken.ps1 -TokenFileName release-conductor-gh-token.txt
+ - name: Configure release tag signing material
+ shell: bash
+ env:
+ RELEASE_TAG_SIGNING_PRIVATE_KEY: ${{ secrets.RELEASE_TAG_SIGNING_PRIVATE_KEY }}
+ RELEASE_TAG_SIGNING_PUBLIC_KEY: ${{ secrets.RELEASE_TAG_SIGNING_PUBLIC_KEY }}
+ RELEASE_TAG_SIGNING_IDENTITY_NAME: ${{ vars.RELEASE_TAG_SIGNING_IDENTITY_NAME || '' }}
+ RELEASE_TAG_SIGNING_IDENTITY_EMAIL: ${{ vars.RELEASE_TAG_SIGNING_IDENTITY_EMAIL || '' }}
+ run: |
+ set -euo pipefail
+ if [[ -z "${RELEASE_TAG_SIGNING_PRIVATE_KEY:-}" ]]; then
+ echo "No release tag signing key configured; skipping workflow-owned signing setup."
+ exit 0
+ fi
+ if [[ -z "${GH_TOKEN:-}" ]]; then
+ echo "::error::GH_TOKEN is unavailable after Resolve-PolicyToken; cannot derive workflow signing identity."
+ exit 1
+ fi
+ signing_dir="$RUNNER_TEMP/release-tag-signing"
+ mkdir -p "$signing_dir"
+ private_key_path="$signing_dir/id_release_tag_signing"
+ public_key_path="${private_key_path}.pub"
+ signing_login="$(gh api user --jq '.login')"
+ signing_id="$(gh api user --jq '.id')"
+ signing_name="${RELEASE_TAG_SIGNING_IDENTITY_NAME:-}"
+ signing_email="${RELEASE_TAG_SIGNING_IDENTITY_EMAIL:-}"
+
+ if [[ -z "$signing_name" ]]; then
+ signing_name="$(gh api user --jq '.name // .login')"
+ fi
+ if [[ -z "$signing_email" ]]; then
+ signing_email="$(gh api user --jq '.email // ""')"
+ fi
+ if [[ -z "$signing_email" ]]; then
+ signing_email="${signing_id}+${signing_login}@users.noreply.github.com"
+ fi
+
+ identity_source="policy-token-user"
+ if [[ -n "${RELEASE_TAG_SIGNING_IDENTITY_NAME:-}" || -n "${RELEASE_TAG_SIGNING_IDENTITY_EMAIL:-}" ]]; then
+ identity_source="repo-variable-override"
+ fi
+
+ printf '%s\n' "$RELEASE_TAG_SIGNING_PRIVATE_KEY" > "$private_key_path"
+ chmod 600 "$private_key_path"
+
+ if [[ -n "${RELEASE_TAG_SIGNING_PUBLIC_KEY:-}" ]]; then
+ printf '%s\n' "$RELEASE_TAG_SIGNING_PUBLIC_KEY" > "$public_key_path"
+ else
+ ssh-keygen -y -f "$private_key_path" > "$public_key_path"
+ fi
+ chmod 644 "$public_key_path"
+
+ git config gpg.format ssh
+ git config user.signingkey "$public_key_path"
+ git config user.name "$signing_name"
+ git config user.email "$signing_email"
+ git config tag.gpgSign true
+
+ {
+ echo "RELEASE_TAG_SIGNING_BACKEND=ssh"
+ echo "RELEASE_TAG_SIGNING_SOURCE=workflow-secret"
+ echo "RELEASE_TAG_SIGNING_IDENTITY_NAME=$signing_name"
+ echo "RELEASE_TAG_SIGNING_IDENTITY_EMAIL=$signing_email"
+ echo "RELEASE_TAG_SIGNING_IDENTITY_LOGIN=$signing_login"
+ echo "RELEASE_TAG_SIGNING_IDENTITY_ID=$signing_id"
+ echo "RELEASE_TAG_SIGNING_IDENTITY_SOURCE=$identity_source"
+ } >> "$GITHUB_ENV"
+
- name: Run release conductor
shell: pwsh
env:
RELEASE_CONDUCTOR_ENABLED: ${{ vars.RELEASE_CONDUCTOR_ENABLED || '0' }}
+ RELEASE_TAG_SIGNING_BACKEND: ${{ env.RELEASE_TAG_SIGNING_BACKEND || '' }}
+ RELEASE_TAG_SIGNING_SOURCE: ${{ env.RELEASE_TAG_SIGNING_SOURCE || '' }}
run: |
npm ci --ignore-scripts
+ node tools/npm/run-script.mjs priority:queue:supervisor -- --dry-run --report tests/results/_agent/queue/queue-supervisor-report.json
node tools/npm/run-script.mjs priority:policy:snapshot -- --output tests/results/_agent/policy/policy-state-snapshot.json
$reportPath = 'tests/results/_agent/release/release-conductor-report.json'
@@ -105,6 +180,10 @@ jobs:
$args += '--dry-run'
}
+ if ('${{ inputs.repair_existing_tag }}' -eq 'true') {
+ $args += '--repair-existing-tag'
+ }
+
$channelInput = '${{ inputs.channel }}'
if (-not [string]::IsNullOrWhiteSpace($channelInput)) {
$args += @('--channel', $channelInput.Trim().ToLowerInvariant())
@@ -134,5 +213,6 @@ jobs:
name: release-conductor-${{ github.run_id }}
path: |
tests/results/_agent/release/release-conductor-report.json
+ tests/results/_agent/queue/queue-supervisor-report.json
tests/results/_agent/policy/policy-state-snapshot.json
if-no-files-found: error
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index df311d6a0..cfd5a95bf 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -4,6 +4,12 @@ on:
push:
tags:
- 'v*'
+ workflow_dispatch:
+ inputs:
+ release_tag:
+ description: 'Authoritative release tag to publish or replay.'
+ required: true
+ type: string
jobs:
certification-matrix:
@@ -13,17 +19,40 @@ jobs:
actions: read
contents: read
outputs:
+ target_tag: ${{ steps.release_target.outputs.tag }}
channel: ${{ steps.channel.outputs.channel }}
steps:
+ - name: Resolve release target tag
+ id: release_target
+ shell: bash
+ run: |
+ set -euo pipefail
+ tag="${GITHUB_REF_NAME}"
+ if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
+ tag='${{ inputs.release_tag }}'
+ fi
+ if [[ -z "$tag" ]]; then
+ echo "Release target tag could not be resolved." >&2
+ exit 1
+ fi
+ if [[ "$tag" != v* ]]; then
+ echo "Release target tag must start with v: $tag" >&2
+ exit 1
+ fi
+ echo "tag=$tag" >> "$GITHUB_OUTPUT"
+
- uses: actions/checkout@v5
+ with:
+ ref: ${{ steps.release_target.outputs.tag }}
- name: Resolve release channel
id: channel
shell: bash
run: |
set -euo pipefail
+ resolved_tag='${{ steps.release_target.outputs.tag }}'
channel="stable"
- if [[ "${GITHUB_REF_NAME}" == *"-rc."* ]]; then
+ if [[ "$resolved_tag" == *-rc.* ]]; then
channel="rc"
fi
echo "channel=${channel}" >> "$GITHUB_OUTPUT"
@@ -68,8 +97,31 @@ jobs:
id-token: write
outputs:
cli_version: ${{ steps.meta.outputs.cli_version }}
+ target_tag: ${{ needs.certification-matrix.outputs.target_tag }}
+ env:
+ RELEASE_TAG: ${{ needs.certification-matrix.outputs.target_tag }}
steps:
- uses: actions/checkout@v5
+ with:
+ ref: ${{ env.RELEASE_TAG }}
+
+ - name: Checkout replay automation surfaces
+ if: ${{ github.event_name == 'workflow_dispatch' }}
+ uses: actions/checkout@v5
+ with:
+ ref: develop
+ path: .release-automation
+
+ - name: Resolve release automation root
+ id: automation_root
+ shell: bash
+ run: |
+ set -euo pipefail
+ automation_root='.'
+ if [[ -f '.release-automation/tools/priority/release-trust-remediation.mjs' ]]; then
+ automation_root='.release-automation'
+ fi
+ echo "path=${automation_root}" >> "$GITHUB_OUTPUT"
- name: Setup Node 20
uses: actions/setup-node@v6
@@ -85,7 +137,7 @@ jobs:
shell: bash
run: |
set -euo pipefail
- TAG="${GITHUB_REF_NAME}"
+ TAG="${RELEASE_TAG}"
awk -v tag="$TAG" '
$0 ~ "^##[[:space:]]*\\[?" tag "\\]?$" {print; in=1; next}
in && $0 ~ "^##[[:space:]]*\\[" {exit}
@@ -212,7 +264,7 @@ jobs:
if-no-files-found: error
- name: Attest release assets provenance
- uses: actions/attest-build-provenance@v2
+ uses: actions/attest-build-provenance@v4
with:
subject-path: |
artifacts/cli/*.zip
@@ -233,7 +285,7 @@ jobs:
--checksums artifacts/cli/SHA256SUMS.txt \
--sbom artifacts/cli/sbom.spdx.json \
--provenance artifacts/cli/provenance.json \
- --tag-ref "${{ github.ref_name }}" \
+ --tag-ref "${RELEASE_TAG}" \
--signer-workflow "${{ github.repository }}/.github/workflows/release.yml" \
--report tests/results/_agent/supply-chain/release-trust-gate.json
@@ -245,12 +297,25 @@ jobs:
-JsonPath tests/results/_agent/supply-chain/release-trust-gate.json `
-SchemaPath docs/schemas/supply-chain-trust-gate-v1.schema.json
+ - name: Append release trust remediation guidance
+ if: always()
+ shell: bash
+ run: |
+ set -euo pipefail
+ node "${{ steps.automation_root.outputs.path }}/tools/priority/release-trust-remediation.mjs" \
+ --trust-report tests/results/_agent/supply-chain/release-trust-gate.json \
+ --tag-ref "${RELEASE_TAG}" \
+ --output tests/results/_agent/release/release-trust-remediation.md \
+ --summary "$GITHUB_STEP_SUMMARY"
+
- name: Upload supply-chain trust artifact
if: always()
uses: actions/upload-artifact@v7
with:
name: release-supply-chain-trust-${{ github.run_id }}
- path: tests/results/_agent/supply-chain/release-trust-gate.json
+ path: |
+ tests/results/_agent/supply-chain/release-trust-gate.json
+ tests/results/_agent/release/release-trust-remediation.md
if-no-files-found: error
- name: Enforce rollback drill health gate
@@ -259,9 +324,9 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
- node tools/priority/rollback-drill-health.mjs \
+ node "${{ steps.automation_root.outputs.path }}/tools/priority/rollback-drill-health.mjs" \
--repo "${{ github.repository }}" \
- --policy tools/policy/release-rollback-policy.json \
+ --policy "${{ steps.automation_root.outputs.path }}/tools/policy/release-rollback-policy.json" \
--report tests/results/_agent/release/rollback-drill-health.json
- name: Validate rollback drill health schema
@@ -270,7 +335,7 @@ jobs:
run: |
pwsh -NoLogo -NoProfile -File tools/Invoke-JsonSchemaLite.ps1 `
-JsonPath tests/results/_agent/release/rollback-drill-health.json `
- -SchemaPath docs/schemas/release-rollback-drill-health-v1.schema.json
+ -SchemaPath '${{ steps.automation_root.outputs.path }}/docs/schemas/release-rollback-drill-health-v1.schema.json'
- name: Upload rollback drill health artifact
if: always()
@@ -283,7 +348,6 @@ jobs:
- name: Append release surface map
shell: pwsh
env:
- RELEASE_TAG: ${{ github.ref_name }}
CLI_VERSION: ${{ steps.meta.outputs.cli_version }}
MODULE_VERSION: ${{ steps.comparevi_tools.outputs.comparevi_tools_release_version }}
MODULE_METADATA: tests/results/_agent/release/comparevi-tools-artifact.json
@@ -304,6 +368,7 @@ jobs:
if: steps.notes.outputs.fallback == 'false'
uses: softprops/action-gh-release@v2
with:
+ tag_name: ${{ env.RELEASE_TAG }}
body_path: RELEASE_NOTES.md
files: |
artifacts/cli/*.zip
@@ -316,6 +381,7 @@ jobs:
if: steps.notes.outputs.fallback == 'true'
uses: softprops/action-gh-release@v2
with:
+ tag_name: ${{ env.RELEASE_TAG }}
generate_release_notes: true
files: |
artifacts/cli/*.zip
@@ -334,7 +400,7 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'publish-tools-image.yml',
- ref: '${{ github.ref_name }}',
+ ref: 'develop',
inputs: {
version: releaseVersion,
channel: releaseChannel
@@ -345,6 +411,8 @@ jobs:
validate-cli-artifacts:
runs-on: ${{ matrix.os }}
needs: release
+ env:
+ RELEASE_TAG: ${{ needs.release.outputs.target_tag }}
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
@@ -518,7 +586,7 @@ jobs:
}
pwsh -NoLogo -NoProfile -File tools/release-review/Write-ReleaseReviewScenarioSummary.ps1 `
-Os '${{ matrix.os }}' `
- -Tag '${{ github.ref_name }}' `
+ -Tag '${{ env.RELEASE_TAG }}' `
-ChecksumOutcome $checksumOutcome `
-SmokeOutcome $smokeOutcome `
-OutputPath 'tests/results/release-review/scenario-summary-${{ matrix.os }}.json'
@@ -616,6 +684,8 @@ jobs:
actions: read
contents: read
issues: write
+ env:
+ RELEASE_TAG: ${{ needs.release.outputs.target_tag }}
steps:
- uses: actions/checkout@v5
@@ -655,7 +725,8 @@ jobs:
shell: bash
run: |
set -euo pipefail
- source_sha="$(git rev-parse "${{ github.ref_name }}^{commit}")"
+ git fetch --force --tags origin "refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}"
+ source_sha="$(git rev-parse "${RELEASE_TAG}^{commit}")"
echo "source_sha=$source_sha" >> "$GITHUB_OUTPUT"
- name: Resolve downstream proving artifact selection
@@ -743,7 +814,7 @@ jobs:
-ScenarioRoot tests/results/release-contract/scenarios `
-ProfilePath tools/release-review/scenario-profiles.json `
-PolicyPath tools/policy/release-review-gates.json `
- -Tag '${{ github.ref_name }}' `
+ -Tag '${{ env.RELEASE_TAG }}' `
-OutputIndexPath tests/results/release-contract/review-index.json `
-OutputCommentPath tests/results/release-contract/review-comment.md
if (Test-Path -LiteralPath 'tests/results/release-contract/review-comment.md' -PathType Leaf) {
@@ -800,7 +871,7 @@ jobs:
'cancelled' { 'blocked' }
default { 'fail' }
}
- $channel = if ('${{ github.ref_name }}' -match '-rc\.') { 'rc' } else { 'stable' }
+ $channel = if ('${{ env.RELEASE_TAG }}' -match '-rc\.') { 'rc' } else { 'stable' }
pwsh -NoLogo -NoProfile -File tools/Write-PromotionEvidenceLedger.ps1 -OutputPath tests/results/promotion-contract/release-ledger.json -WorkflowName '${{ github.workflow }}' -Stream 'comparevi-cli' -Channel $channel -Version '${{ needs.release.outputs.cli_version }}' -GateStatus $gateStatus -GateReason 'release-contract job result' -SummaryPath 'tests/results/release-contract/review-index.json' -StepSummaryPath $env:GITHUB_STEP_SUMMARY
- name: Emit SLO metrics
@@ -822,11 +893,11 @@ jobs:
run: |
set -euo pipefail
channel="stable"
- if printf '%s' "${{ github.ref_name }}" | grep -q -- '-rc\.'; then
+ if printf '%s' "${RELEASE_TAG}" | grep -q -- '-rc\.'; then
channel="rc"
fi
signed_tag_args=()
- if ! printf '%s' "${{ github.ref_name }}" | grep -Eq -- '-tools\.[0-9]+$'; then
+ if ! printf '%s' "${RELEASE_TAG}" | grep -Eq -- '-tools\.[0-9]+$'; then
signed_tag_args+=(--require-signed-tag)
fi
node tools/priority/release-scorecard.mjs \
@@ -834,7 +905,7 @@ jobs:
--stream comparevi-cli \
--channel "${channel}" \
--version "${{ needs.release.outputs.cli_version }}" \
- --tag-ref "${{ github.ref_name }}" \
+ --tag-ref "${RELEASE_TAG}" \
--ledger tests/results/promotion-contract/release-ledger.json \
--slo tests/results/_agent/slo/release-slo-metrics.json \
--rollback tests/results/_agent/release/rollback-drill-health.json \
diff --git a/AGENTS.md b/AGENTS.md
index dcc6e110d..9558d03df 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -105,6 +105,8 @@ Keep it short, stable, and helper-oriented. Deep runbooks belong in checked-in d
`tests/results/_agent/handoff/autonomous-governor-summary.json`.
- `node tools/npm/run-script.mjs priority:governor:portfolio` refreshes the cross-repo operating receipt at
`tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json`.
+- `node tools/npm/run-script.mjs priority:context:concentrate` refreshes the compact durable memory receipt at
+ `tests/results/_agent/handoff/sagan-context-concentrator.json`.
- `node tools/npm/run-script.mjs priority:continuity` refreshes the continuity receipts at
`tests/results/_agent/runtime/continuity-telemetry.json` and
`tests/results/_agent/handoff/continuity-summary.json`.
@@ -116,6 +118,7 @@ Keep it short, stable, and helper-oriented. Deep runbooks belong in checked-in d
- `tests/results/_agent/issue/no-standing-priority.json`
- `tests/results/_agent/handoff/autonomous-governor-summary.json`
- `tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json`
+ - `tests/results/_agent/handoff/sagan-context-concentrator.json`
- `tests/results/_agent/handoff/continuity-summary.json`
- `tests/results/_agent/handoff/entrypoint-status.json`
- `tests/results/_agent/runtime/`
diff --git a/AGENT_HANDOFF.txt b/AGENT_HANDOFF.txt
index 39cf21ec9..eca6def34 100644
--- a/AGENT_HANDOFF.txt
+++ b/AGENT_HANDOFF.txt
@@ -9,8 +9,7 @@ Live repository state belongs in the machine-generated artifacts under
## First Actions
1. Run `pwsh -NoLogo -NoProfile -File tools/priority/bootstrap.ps1`.
-2. Check `.agent_priority_cache.json` and
- `tests/results/_agent/issue/router.json`.
+2. Check `.agent_priority_cache.json` and `tests/results/_agent/issue/router.json`.
3. Run `pwsh -NoLogo -NoProfile -File tools/Print-AgentHandoff.ps1
-ApplyToggles -AutoTrim` when you need the current watcher/handoff snapshot.
4. When human disposition surfaces are in play, run
@@ -25,7 +24,9 @@ Live repository state belongs in the machine-generated artifacts under
`tests/results/_agent/handoff/autonomous-governor-summary.json` for the
current repo owner decision and
`tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json`
- for the cross-repo owner decision.
+ for the cross-repo owner decision, and
+ `tests/results/_agent/handoff/sagan-context-concentrator.json` for the compact
+ hot/warm durable memory view of subagent work and blockers.
## Live State Surfaces
@@ -43,6 +44,8 @@ Live repository state belongs in the machine-generated artifacts under
`node tools/npm/run-script.mjs priority:governor:summary`
- Governor portfolio:
`node tools/npm/run-script.mjs priority:governor:portfolio`
+- Context concentrator:
+ `node tools/npm/run-script.mjs priority:context:concentrate`
## Current-State Artifacts
@@ -54,6 +57,7 @@ Live repository state belongs in the machine-generated artifacts under
- `tests/results/_agent/handoff/entrypoint-status.json`
- `tests/results/_agent/handoff/monitoring-mode.json`
- `tests/results/_agent/handoff/autonomous-governor-summary.json`
+- `tests/results/_agent/handoff/sagan-context-concentrator.json`
- `tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json`
- `tests/results/_agent/handoff/human-go-no-go-latest.json`
- `tests/results/_agent/handoff/*.json`
@@ -65,8 +69,7 @@ Live repository state belongs in the machine-generated artifacts under
- The project board is visibility only.
- Treat `queue-empty` as a valid idle state; do not invent a null issue context.
- Treat `queue-empty + safe-idle + pivot-ready` as an explicit monitoring state.
-- Prefer sanitized repo helpers (`node tools/npm/run-script.mjs ...`) over raw
- `npm`.
+- Prefer sanitized repo helpers (`node tools/npm/run-script.mjs ...`) over raw `npm`.
## When Handoff Looks Wrong
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ab972772..e89b8cf97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,6 +38,24 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
expectations between backend releases in this repo and facade releases in
`comparevi-history`.
+## [v0.6.4-rc.2] - 2026-03-24
+
+### Changed
+
+- The published `CompareVI.Tools` bundle contract now targets the next RC
+ identity so release publication can carry the merged producer-owned Docker
+ contract instead of replaying the earlier `v0.6.4-rc.1` bundle metadata.
+- Release branch materials now treat `v0.6.4-rc.2` as the active RC cut for the
+ template Docker-profile rail, keeping the changelog, PR notes, checklist, and
+ archived release notes aligned to the same release identity.
+
+### Added
+
+- The `CompareVI.Tools` release manifest now includes the producer-owned
+ `consumerContract.capabilities.dockerProfile` capability and
+ `consumerContract.dockerImageContract` source needed by
+ `LabviewGitHubCiTemplate#20` once the next authoritative bundle is published.
+
## [v0.6.4-rc.1] - 2026-03-22
### Changed
diff --git a/Directory.Build.props b/Directory.Build.props
index 3876e87cc..c32b8466b 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -7,7 +7,7 @@
false
true
true
- 0.6.4-rc.1
+ 0.6.4-rc.2
0.6.4.0
0.6.4.0
$(Version)+local
diff --git a/dist/tools/schemas/definitions.js b/dist/tools/schemas/definitions.js
index 2e93876b1..0edf0b512 100644
--- a/dist/tools/schemas/definitions.js
+++ b/dist/tools/schemas/definitions.js
@@ -279,35 +279,136 @@ const warmupModeSchema = z.enum(['detect', 'spawn', 'skip']);
const warmupEventsSchema = z.union([z.string().min(1), z.null()]);
const compareCliSchema = cliInfoSchema;
const comparePolicySchema = z.enum(['lv-first', 'cli-first', 'cli-only', 'lv-only']);
+const testStandCompareOutcomeSchema = z
+ .object({
+ exitCode: z.number(),
+ seconds: z.number().optional(),
+ command: z.string().optional(),
+ diff: z.boolean().optional(),
+})
+ .nullable();
+const testStandCompareNodeSchema = z.object({
+ events: z.string().min(1),
+ capture: z.union([z.string().min(1), z.null()]),
+ report: z.boolean(),
+ command: z.string().min(1).optional(),
+ cliPath: z.string().min(1).optional(),
+ cli: compareCliSchema.optional(),
+ staging: z
+ .object({
+ enabled: z.boolean(),
+ root: z.union([z.string().min(1), z.null()]),
+ })
+ .optional(),
+ allowSameLeaf: z.boolean().optional(),
+ policy: comparePolicySchema.optional(),
+ mode: z.string().min(1).optional(),
+ autoCli: z.boolean().optional(),
+ sameName: z.boolean().optional(),
+ timeoutSeconds: z.number().min(0).optional(),
+});
+const testStandExecutionCellSchema = z.object({
+ cellId: z.string().min(1).nullable().optional(),
+ leaseId: z.string().min(1).nullable().optional(),
+ leasePath: z.string().min(1).nullable().optional(),
+ agentId: z.string().min(1).nullable().optional(),
+ agentClass: z.enum(['sagan', 'subagent', 'other']).nullable().optional(),
+ cellClass: z.enum(['worker', 'coordinator', 'kernel-coordinator']).nullable().optional(),
+ suiteClass: z.enum(['single-compare', 'dual-plane-parity']).nullable().optional(),
+ planeBinding: z.string().min(1).nullable().optional(),
+ runtimeSurface: z.literal('windows-native-teststand').nullable().optional(),
+ premiumSaganMode: z.boolean().optional(),
+ operatorAuthorizationRef: z.string().min(1).nullable().optional(),
+ workingRoot: z.string().min(1).nullable().optional(),
+ artifactRoot: z.string().min(1).nullable().optional(),
+ isolatedLaneGroupId: z.string().min(1).nullable().optional(),
+ hostOsFingerprintSha256: hexSha256.nullable().optional(),
+});
+const testStandProcessModelSchema = z.object({
+ runtimeSurface: z.literal('windows-native-teststand'),
+ processModelClass: z.enum(['sequential-process-model', 'parallel-process-model']),
+ windowsOnly: z.literal(true),
+ rootHarnessInstanceId: z.string().min(1),
+ planeCount: z.number().int().min(1),
+});
+const testStandHarnessInstanceSchema = z.object({
+ harnessKind: z.string().min(1),
+ instanceId: z.string().min(1),
+ role: z.enum(['single-plane', 'coordinator', 'plane-child']),
+ processModelClass: z.enum(['sequential-process-model', 'parallel-process-model']),
+ planeBinding: z.string().min(1).nullable().optional(),
+ parentInstanceId: z.string().min(1).nullable().optional(),
+});
+const testStandPlaneSessionSchema = z.object({
+ plane: z.string().min(1),
+ architecture: z.enum(['32-bit', '64-bit']),
+ labviewExePath: z.union([z.string().min(1), z.null()]).optional(),
+ outputRoot: z.string().min(1),
+ warmup: z.object({
+ mode: warmupModeSchema,
+ events: warmupEventsSchema,
+ }),
+ compare: testStandCompareNodeSchema,
+ outcome: testStandCompareOutcomeSchema,
+ error: z.union([z.string().min(1), z.null()]).optional(),
+ exitCode: z.number(),
+ executionCell: testStandExecutionCellSchema.nullable().optional(),
+ harnessInstance: testStandHarnessInstanceSchema.nullable().optional(),
+ processModel: testStandProcessModelSchema.optional(),
+});
+const testStandParitySummarySchema = z.object({
+ status: z.enum(['match', 'mismatch', 'incomplete']),
+ comparedFields: z.array(z.string().min(1)),
+ exitCodeParity: z.boolean().nullable().optional(),
+ diffParity: z.boolean().nullable().optional(),
+ mismatchCount: z.number().int().min(0),
+ mismatches: z.array(z.object({
+ field: z.string().min(1),
+ x64: z.union([z.string().min(1), z.number(), z.boolean(), z.null()]).optional(),
+ x32: z.union([z.string().min(1), z.number(), z.boolean(), z.null()]).optional(),
+ })),
+});
const testStandCompareSessionSchema = z.object({
- schema: z.literal('teststand-compare-session/v1'),
+ schema: z.enum(['teststand-compare-session/v1', 'teststand-compare-session/v2']),
at: isoString,
warmup: z.object({
mode: warmupModeSchema,
events: warmupEventsSchema,
}),
- compare: z.object({
- events: z.string().min(1),
- capture: z.union([z.string().min(1), z.null()]),
- report: z.boolean(),
- command: z.string().min(1).optional(),
- cliPath: z.string().min(1).optional(),
- cli: compareCliSchema.optional(),
- policy: comparePolicySchema.optional(),
- mode: z.string().min(1).optional(),
- autoCli: z.boolean().optional(),
- sameName: z.boolean().optional(),
- timeoutSeconds: z.number().min(0).optional(),
- }),
- outcome: z
+ compare: testStandCompareNodeSchema,
+ outcome: testStandCompareOutcomeSchema,
+ error: z.union([z.string().min(1), z.null()]).optional(),
+ executionCell: testStandExecutionCellSchema.nullable().optional(),
+ harnessInstance: testStandHarnessInstanceSchema.nullable().optional(),
+ processModel: testStandProcessModelSchema.optional(),
+ suiteClass: z.enum(['single-compare', 'dual-plane-parity']).optional(),
+ primaryPlane: z.string().min(1).optional(),
+ requestedSimultaneous: z.boolean().optional(),
+ planes: z
.object({
- exitCode: z.number(),
- seconds: z.number().optional(),
- command: z.string().optional(),
- diff: z.boolean().optional(),
+ x64: testStandPlaneSessionSchema,
+ x32: testStandPlaneSessionSchema,
})
- .nullable(),
- error: z.union([z.string().min(1), z.null()]).optional(),
+ .optional(),
+ parity: testStandParitySummarySchema.optional(),
+}).superRefine((value, ctx) => {
+ if (value.schema === 'teststand-compare-session/v2') {
+ if (!value.suiteClass) {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'suiteClass is required for v2 sessions', path: ['suiteClass'] });
+ }
+ if (!value.primaryPlane) {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'primaryPlane is required for v2 sessions', path: ['primaryPlane'] });
+ }
+ if (typeof value.requestedSimultaneous !== 'boolean') {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'requestedSimultaneous is required for v2 sessions', path: ['requestedSimultaneous'] });
+ }
+ if (!value.planes) {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'planes is required for v2 sessions', path: ['planes'] });
+ }
+ if (!value.parity) {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'parity is required for v2 sessions', path: ['parity'] });
+ }
+ }
});
const invokerEventSchema = z.object({
timestamp: isoString,
diff --git a/docs/DELIVERY_CONTROL_PLANE_PR_LANES.md b/docs/DELIVERY_CONTROL_PLANE_PR_LANES.md
index 81f67596a..3299f3e71 100644
--- a/docs/DELIVERY_CONTROL_PLANE_PR_LANES.md
+++ b/docs/DELIVERY_CONTROL_PLANE_PR_LANES.md
@@ -17,7 +17,7 @@ This scaffold tracks the six planned mergeable slices so agents can resume deter
- Keep each lane mergeable and production-safe in isolation.
- Rebase each next lane on merged upstream `develop` before opening its PR.
-- Preserve signed-tag policy; release conductor must remain proposal-only when signing material is unavailable.
+- Preserve signed-tag policy; release conductor must fail closed before tag creation when signing material is unavailable.
## Resume commands
diff --git a/docs/DEVELOPER_GUIDE.md b/docs/DEVELOPER_GUIDE.md
index 3f08c9325..534892d47 100644
--- a/docs/DEVELOPER_GUIDE.md
+++ b/docs/DEVELOPER_GUIDE.md
@@ -177,10 +177,14 @@ Quick reference for building, testing, and releasing the LVCompare composite act
`gh issue create/edit`. Omit `--output` to print to STDOUT.
- `pwsh -NoLogo -NoProfile -File tools/Post-IssueComment.ps1 -Issue -BodyFile issue-comment.md`
Posts GitHub issue comments through `--body-file` by default so multiline Markdown survives PowerShell and mixed
- Windows/WSL shells without backtick-escape drift.
+ Windows/WSL shells without backtick-escape drift. The wrapper also appends the
+ checked-in durable budget hook by default; pass `-SkipBudgetHook` only when a
+ test or break-glass path must suppress the attestation.
- `pwsh -NoLogo -NoProfile -File tools/Post-PullRequestComment.ps1 -PullRequest -Repo -BodyFile pr-comment.md`
Posts GitHub pull-request comments through `--body-file` by default so multiline Markdown survives PowerShell and
- mixed Windows/WSL shells without backtick-escape drift.
+ mixed Windows/WSL shells without backtick-escape drift. The wrapper also
+ appends the checked-in durable budget hook by default; pass `-SkipBudgetHook`
+ only when a test or break-glass path must suppress the attestation.
- `node tools/priority/github-helper.mjs snippet --issue 531 --prefix Fixes`
Emits an auto-link snippet (defaults to `Fixes #531`) you can drop into PR descriptions so GitHub auto-closes the issue.
- `node tools/npm/run-script.mjs priority:project:portfolio:apply -- --url --use-config`
@@ -476,8 +480,8 @@ For Docker/Desktop VI history validation, run fast-loop lanes explicitly:
Auto mode activates on release windows, open `release/*` PRs, or `release-burst` labels, and backs off for
30 minutes whenever the throughput controller enters `stabilize`.
For queue-aware release proposals, run `node tools/npm/run-script.mjs priority:release:conductor -- --dry-run`.
- Apply mode requires `RELEASE_CONDUCTOR_ENABLED=1`; if signing material is unavailable, the conductor remains
- proposal-only and emits evidence without mutating tags.
+ Apply mode requires `RELEASE_CONDUCTOR_ENABLED=1`; if signing material is unavailable, the conductor now fails closed
+ before tag creation and emits readiness evidence without mutating tags.
Hosted `schedule` and `workflow_run` conductor lanes stay proposal-only when apply mode is disabled, and dry-runs
record advisory-only queue-evidence / no-recent-success diagnostics instead of failing for missing queue artifacts or
idle dwell windows.
@@ -657,6 +661,9 @@ pwsh -File tools/Print-AgentHandoff.ps1 -ApplyToggles -AutoTrim
`node tools/npm/run-script.mjs priority:handoff`, which now prints the
entrypoint index alongside the standing-priority snapshot and other handoff
summaries.
+- Refresh the compact hot/warm durable memory view directly with
+ `node tools/npm/run-script.mjs priority:context:concentrate`, which writes
+ `tests/results/_agent/handoff/sagan-context-concentrator.json`.
- The overall future-agent handoff contract is summarized in
[`docs/knowledgebase/Agent-Handoff-Surfaces.md`](./knowledgebase/Agent-Handoff-Surfaces.md).
- See [`WATCHER_TELEMETRY_DX.md`](./WATCHER_TELEMETRY_DX.md) for automation response expectations.
diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md
index 2485919db..d51c27a59 100644
--- a/docs/ENVIRONMENT.md
+++ b/docs/ENVIRONMENT.md
@@ -12,6 +12,56 @@ All values are strings; use `1` / `0` for boolean-style flags.
| `LVCOMPARE_PATH` | Optional override for LVCompare.exe (must resolve to canonical path) |
| `WORKING_DIRECTORY` | Process CWD when invoking LVCompare |
+## Canonical host OS fingerprint
+
+The authoritative OS/build receipt for the canonical Windows host lane group is
+written by:
+
+```powershell
+node tools/npm/run-script.mjs env:labview:2026:host-planes
+```
+
+Primary artifact:
+
+- `tests/results/_agent/host-planes/labview-2026-host-plane-report.json`
+
+Key fields:
+
+- `host.osFingerprint.fingerprintSha256`
+- `host.osFingerprint.isolatedLaneGroupId`
+- `host.osFingerprint.canonical.version`
+- `host.osFingerprint.canonical.buildNumber`
+- `host.osFingerprint.canonical.ubr`
+- `host.osFingerprint.canonical.displayVersion`
+- `host.osFingerprint.canonical.editionId`
+
+Treat those fields as the upgrade-attribution baseline for isolated lane
+groups. If the fingerprint changes after a host upgrade, classify that as host
+OS drift first and only then assess Docker, LabVIEW, or workflow regressions.
+`computerName`, branding labels, and boot/install timestamps remain advisory.
+
+## Docker lane handshake
+
+Use the lease helper when a background agent needs an isolated Docker lane:
+
+```powershell
+node tools/npm/run-script.mjs priority:lane:docker:handshake -- --action request --lane-id docker-agent-epicurus-linux-01 --agent-id epicurus --agent-class subagent --capability docker-lane
+```
+
+Primary artifact:
+
+- `tests/results/_agent/runtime/docker-lane-handshake.json`
+
+Notes:
+
+- The helper depends on the canonical host-plane report and the operator cost profile.
+- Ordinary subagent Docker leases use the configured operator labor rate as-is.
+- Premium simultaneous `docker-lane` plus `native-labview-2026-32` is Sagan-only, requires `operatorAuthorizationRef`,
+ and bills at `1.5x` the configured operator labor rate.
+- The handshake projects `host.osFingerprint.isolatedLaneGroupId` and
+ `host.osFingerprint.fingerprintSha256` into the lease so Docker-lane usage stays attributable to the canonical host OS
+ baseline.
+
## Dispatcher guards (leak detection / cleanup)
| Variable | Notes |
@@ -64,6 +114,9 @@ Notes:
the wrapper and the TestStand harness invoke the LabVIEW CLI directly to generate an HTML report
and enrich `lvcompare-capture.json` with an `environment.cli` metadata block (path, version,
reportType, reportPath, status, message).
+- `tools/TestStand-CompareHarness.ps1` remains a native-plane consumer surface. It is useful when you need deterministic
+ warmup plus compare session receipts, but it should still be attributed to the selected native plane rather than to a
+ separate execution plane.
- When a CLI report is produced, embedded artefacts (for example, diff images) are decoded into
`tests/results//compare/cli-images/`, and `environment.cli.artifacts` records the report
size, image count, and exported file paths so downstream tooling can rehydrate attachments.
diff --git a/docs/RELEASE_OPERATIONS_RUNBOOK.md b/docs/RELEASE_OPERATIONS_RUNBOOK.md
index 965bbbbf0..7a3fca1d1 100644
--- a/docs/RELEASE_OPERATIONS_RUNBOOK.md
+++ b/docs/RELEASE_OPERATIONS_RUNBOOK.md
@@ -53,11 +53,20 @@ Configuration path: `Settings -> Environments -> -> Required revie
backend stable release as fully complete
5. Finalize release (draft tag + metadata):
- `node tools/npm/run-script.mjs release:finalize -- `
-6. Verify rollback drill health:
+6. Verify workflow signing readiness before authoritative tag publication:
+ - `node tools/npm/run-script.mjs priority:release:signing:readiness`
+ - confirm `tests/results/_agent/release/release-signing-readiness.json` reports:
+ - `codePathState = ready`
+ - `signingCapabilityState = configured`
+ - `signingAuthorityState = ready`
+ - `releaseConductorApplyState = enabled`
+ - if `externalBlocker` reports any signing secret, signing authority, or apply-gating blocker,
+ treat that as an explicit external blocker and stop before rerunning release publication flows
+7. Verify rollback drill health:
- `node tools/npm/run-script.mjs priority:rollback:drill:health -- --repo `
- confirm `tests/results/_agent/release/rollback-drill-health.json` reports `status=pass`
-7. Obtain environment approvals for protected deployments from GitHub UI/mobile.
-8. Record evidence links in the governing issue/PR before closure.
+8. Obtain environment approvals for protected deployments from GitHub UI/mobile.
+9. Record evidence links in the governing issue/PR before closure.
## One-command rollback
@@ -138,6 +147,35 @@ For unattended cadence, use `.github/workflows/downstream-onboarding-feedback.ym
## Supply-chain trust remediation classes
+Before relying on a local workstation tag, prefer the release conductor
+automation path:
+
+- run `.github/workflows/release-conductor.yml` in apply mode
+- if the authoritative release tag already exists but the trust gate reports
+ `tag-not-annotated` or `tag-signature-unverified`, rerun
+ `.github/workflows/release-conductor.yml` with:
+ - the target `version`
+ - `apply = true`
+ - `repair_existing_tag = true`
+- provision `RELEASE_TAG_SIGNING_PRIVATE_KEY` and optional
+ `RELEASE_TAG_SIGNING_PUBLIC_KEY` for workflow-owned signing
+- optionally set `RELEASE_TAG_SIGNING_IDENTITY_NAME` and
+ `RELEASE_TAG_SIGNING_IDENTITY_EMAIL` when the signing authority should use an
+ explicit Git identity override; otherwise the workflow derives the signer
+ identity from the resolved policy token account
+- inspect `tests/results/_agent/release/release-conductor-report.json`
+ first
+- require both:
+ - `release.tagCreated = true`
+ - `release.tagPushed = true`
+ - when repair mode is used:
+ - `release.repair.status = repaired`
+ - `release.repair.remoteTargetCommitOid` matches the authoritative commit
+ - `release.publicationReplay.status = dispatched`
+ - `release.publicationReplay.ref = develop`
+ - `release.publicationReplay.tagInputValue` matches the authoritative tag
+ - the replayed `Release on tag` run succeeds for the repaired tag
+
When the release trust gate fails, inspect `tests/results/_agent/supply-chain/release-trust-gate.json` and follow the
matching remediation path:
@@ -148,7 +186,23 @@ matching remediation path:
- `tag-signature-cli-unavailable`
- Restore GitHub CLI availability on runner and retry release.
- `tag-not-annotated`, `tag-signature-unverified`
- - Recreate release tag as a signed annotated tag and rerun release.
+ - Use `node tools/npm/run-script.mjs priority:release:signing:readiness`
+ first.
+ - If signing readiness is `ready`, run the release conductor in repair mode
+ for the target version so the authoritative tag is recreated as a signed
+ annotated tag without changing the intended release commit.
+ - Rerun release only after the repair report shows
+ `release.repair.status = repaired` and
+ `release.publicationReplay.status = dispatched`.
+ - Repaired-tag replay now dispatches `release.yml` from `develop` with
+ `workflow_dispatch.inputs.release_tag=`; do not rely on the
+ repaired tag itself carrying the newer workflow definition.
+- `workflow-signing-secret-missing`, `workflow-signing-secret-unverifiable`
+- `workflow-signing-admin-scope-missing`, `workflow-signing-key-missing`, `workflow-signing-authority-unverifiable`
+- `release-conductor-apply-disabled`, `release-conductor-apply-unverifiable`
+ - Use `node tools/npm/run-script.mjs priority:release:signing:readiness` to confirm the blocker, provision or repair
+ the workflow signing secrets, signing authority, or release-conductor enablement, and only then rerun authoritative
+ release publication.
- `checksum-invalid-line`, `checksum-empty`, `checksum-entry-missing-file`, `checksum-missing-artifact`, `checksum-mismatch`
- Regenerate `SHA256SUMS.txt` from fresh artifacts and ensure no post-pack mutation occurred.
- `sbom-parse-failed`, `sbom-invalid`
@@ -178,6 +232,7 @@ matching remediation path:
- `tests/results/_agent/release/release--branch.json`
- `tests/results/_agent/release/release--finalize.json`
+- `tests/results/_agent/release/release-signing-readiness.json`
- `tests/results/_agent/policy/policy-drift-report.json`
- `tests/results/_agent/health-snapshot/health-snapshot.json`
- `tests/results/_agent/supply-chain/release-trust-gate.json`
diff --git a/docs/RELEASE_PROMOTION_CONTRACT.md b/docs/RELEASE_PROMOTION_CONTRACT.md
index c585dbbb0..a41dcb69a 100644
--- a/docs/RELEASE_PROMOTION_CONTRACT.md
+++ b/docs/RELEASE_PROMOTION_CONTRACT.md
@@ -16,6 +16,9 @@ alignment, and evidence ledger expectations.
- Certification runbook: `docs/CERTIFICATION_MATRIX.md`
- Supply-chain trust gate script: `tools/priority/supply-chain-trust-gate.mjs`
- Supply-chain trust gate schema: `docs/schemas/supply-chain-trust-gate-v1.schema.json`
+- Release signing readiness script: `tools/priority/release-signing-readiness.mjs`
+- Release signing readiness schema:
+ `docs/schemas/release-signing-readiness-report-v1.schema.json`
- Rollback policy: `tools/policy/release-rollback-policy.json`
- Rollback command: `tools/priority/rollback-release.mjs`
- Rollback drill health gate: `tools/priority/rollback-drill-health.mjs`
@@ -137,6 +140,107 @@ Release tags must pass the supply-chain trust gate before GitHub Release publica
If the trust gate fails, release publication is blocked (fail-closed) and the report artifact must be used for remediation.
+Release publication also emits trust remediation guidance when the trust gate
+finds repair-eligible tag failures:
+
+- Markdown artifact:
+ `tests/results/_agent/release/release-trust-remediation.md`
+- Required behavior:
+ - preserve the existing release tag identity
+ - route `tag-not-annotated` and `tag-signature-unverified` to release
+ conductor repair mode
+ - instruct repair using:
+ - `version = `
+ - `apply = true`
+ - `repair_existing_tag = true`
+
+Authoritative signed tag publication now belongs to the release conductor control
+plane:
+
+- `.github/workflows/release-conductor.yml` may load
+ `RELEASE_TAG_SIGNING_PRIVATE_KEY` and optional
+ `RELEASE_TAG_SIGNING_PUBLIC_KEY`
+- the workflow may also honor optional repo variables:
+ - `RELEASE_TAG_SIGNING_IDENTITY_NAME`
+ - `RELEASE_TAG_SIGNING_IDENTITY_EMAIL`
+ - when unset, the workflow derives signer identity from the resolved policy
+ token account before recreating or publishing the signed tag
+- when signing material is present, release conductor must:
+ - configure workflow-owned tag signing
+ - configure workflow-owned signer identity
+ - create the signed annotated tag
+ - push the tag to the authoritative remote for the target repository
+ - when repairing an existing tag, dispatch `.github/workflows/release.yml`
+ from `develop` with `workflow_dispatch.inputs.release_tag=` so
+ publication replays deterministically against the repaired authoritative tag
+- `tests/results/_agent/release/release-conductor-report.json` must record:
+ - signing backend/source
+ - signer identity used for tag creation/repair
+ - whether the tag was created
+ - whether the tag was pushed authoritatively
+ - whether repair mode was requested/performed for an existing tag
+ - the authoritative remote tag object/commit used for repair
+ - which workflow ref carried the replay dispatch
+ - which explicit tag input was used for repaired-tag publication replay
+ - whether repaired-tag publication replay was dispatched
+ - any push failure blocker
+
+## Workflow signing readiness
+
+Authoritative release-tag publication must also expose workflow signing readiness
+before the release lane is rerun:
+
+- Report script: `node tools/npm/run-script.mjs priority:release:signing:readiness`
+- Report artifact:
+ `tests/results/_agent/release/release-signing-readiness.json`
+
+That report distinguishes:
+
+- `codePathState`
+ - whether the checked-in release conductor exposes the workflow-owned signing
+ contract
+- `signingCapabilityState`
+ - whether repository Actions secrets actually provide the signing material
+- `publicationState`
+ - whether authoritative signed tag publication has already succeeded
+
+If the report emits an external blocker such as:
+
+- `workflow-signing-secret-missing`
+- `workflow-signing-secret-unverifiable`
+- `workflow-signing-admin-scope-missing`
+- `workflow-signing-key-missing`
+- `workflow-signing-authority-unverifiable`
+- `release-conductor-apply-disabled`
+- `release-conductor-apply-unverifiable`
+
+promotion remains blocked by external signing readiness. Repair the specific
+secret, authority, or apply-gating surface first, then refresh readiness
+instead of rerunning release publication just to rediscover the same blocker.
+
+## Published CompareVI.Tools bundle observer
+
+Once a release exists, compare can also observe the actually published
+`CompareVI.Tools` asset and check whether it is already producer-native for the
+template's `vi-history` distribution contract:
+
+- Observer script:
+ `node tools/npm/run-script.mjs priority:release:published:bundle`
+- Report artifact:
+ `tests/results/_agent/release/release-published-bundle-observer.json`
+
+This observer downloads the published `CompareVI.Tools-v*.zip` asset, extracts
+`comparevi-tools-release.json`, and proves whether the published bundle already
+exposes:
+
+- `consumerContract.capabilities.viHistory`
+- `upstream-producer` / `release-bundle`
+- `versionContract.authoritativeConsumerPin`
+- the declared bundle import path and referenced consumer contract paths
+
+That surface is the compare-side bridge between signed release publication and
+template issue `LabviewGitHubCiTemplate#18`.
+
## Rollback drill health gate
Release tags must pass rollback drill health before GitHub Release publication:
diff --git a/docs/SELFHOSTED_CI_SETUP.md b/docs/SELFHOSTED_CI_SETUP.md
index 795a8b0f7..e70a0e352 100644
--- a/docs/SELFHOSTED_CI_SETUP.md
+++ b/docs/SELFHOSTED_CI_SETUP.md
@@ -13,6 +13,9 @@ Minimal steps to provision a Windows runner suitable for LVCompare workflows.
## Runner configuration
- Labels: `self-hosted`, `Windows`, `X64`.
+- Prefer a small number of coarse GitHub runner labels over one runner registration per background agent.
+- Isolated Docker lanes should be leased locally through the Docker-lane handshake helper instead of by creating a
+ permanent GitHub Actions runner service for each agent.
- Service account requires access to VI fixtures and temporary directories.
- Environment variables (system scope recommended):
- `LV_BASE_VI`, `LV_HEAD_VI` (sample VIs).
@@ -27,15 +30,46 @@ Minimal steps to provision a Windows runner suitable for LVCompare workflows.
Test-Path 'C:\Program Files\National Instruments\Shared\LabVIEW Compare\LVCompare.exe'
[Environment]::GetEnvironmentVariable('LV_BASE_VI', 'Machine')
[Environment]::GetEnvironmentVariable('LV_HEAD_VI', 'Machine')
+node tools/npm/run-script.mjs env:labview:2026:host-planes
+node tools/npm/run-script.mjs priority:lane:docker:handshake -- --action request --lane-id docker-agent-check-01 --agent-id operator --agent-class other --capability docker-lane
```
Dispatch `Pester (self-hosted, real CLI)` manually to confirm environment validation and tests pass.
+When the host is part of the canonical isolated lane group, treat the generated
+host-plane report as the OS/build source of truth:
+
+- `tests/results/_agent/host-planes/labview-2026-host-plane-report.json`
+- `host.osFingerprint.fingerprintSha256`
+- `host.osFingerprint.isolatedLaneGroupId`
+- `host.osFingerprint.canonical.version`
+- `host.osFingerprint.canonical.buildNumber`
+- `host.osFingerprint.canonical.ubr`
+
+Future host refreshes and isolated lane groups should compare against that
+fingerprint before blaming LabVIEW, Docker, or runner drift on the workload
+itself.
+
+When the host also carries deterministic compare tooling, the TestStand harness
+is a supported native-plane consumer:
+
+- `pwsh -NoLogo -NoProfile -File tools/TestStand-CompareHarness.ps1`
+ `-BaseVi -HeadVi -OutputRoot`
+ `tests/results/teststand-session -Warmup detect -RenderReport`
+
+That harness does not define a separate runner class. It consumes one of the
+native LabVIEW planes and should be attributed to the same host OS fingerprint
+and isolated lane group.
+
## Maintenance
- Keep LabVIEW and Windows patched.
- Monitor runner health (Actions → Runners).
- Rotate PATs and verify secrets annually.
- Periodically refresh fixture VIs and environment variables.
+- After a Windows upgrade, rerun
+ `node tools/npm/run-script.mjs env:labview:2026:host-planes` and compare the
+ previous versus current `host.osFingerprint` values before reclassifying lane
+ regressions. A changed fingerprint means the canonical host OS baseline moved.
Further reading: [`docs/E2E_TESTING_GUIDE.md`](./E2E_TESTING_GUIDE.md), [`docs/ENVIRONMENT.md`](./ENVIRONMENT.md).
diff --git a/docs/SINGLE_HOST_LABVIEW_2026_PLANES.md b/docs/SINGLE_HOST_LABVIEW_2026_PLANES.md
index 1e7821dda..12a699ccf 100644
--- a/docs/SINGLE_HOST_LABVIEW_2026_PLANES.md
+++ b/docs/SINGLE_HOST_LABVIEW_2026_PLANES.md
@@ -16,6 +16,12 @@ Treat these four planes as distinct:
Do not collapse them into a generic “LabVIEW 2026 host” concept. The repo contracts and artifacts are written so future
agents can tell which plane actually produced the evidence.
+Treat the TestStand harness as a host-plane consumer, not a fifth plane. It is a deterministic wrapper around
+Windows-native LabVIEW warmup and LVCompare session capture, so its receipts still belong to one of the native planes
+rather than to a separate execution category.
+
+TestStand is a Windows-only runtime surface. It should not be modeled as a Linux or Docker execution runtime.
+
## Shadow policy
`native-labview-2026-32` is a shadow acceleration surface, not an authoritative
@@ -50,6 +56,109 @@ The native planes are also distinct:
They may share supporting tooling paths, but they remain different host planes and must not be reported as one surface.
+## Lease-backed lane protocol
+
+Shared host surfaces must use a software four-phase handshake before an agent treats a Docker or premium native lane as
+owned:
+
+1. `request`
+2. `grant`
+3. `commit` plus `heartbeat`
+4. `release`
+
+Use the checked-in helper when you need a replayable lease receipt:
+
+- `node tools/npm/run-script.mjs priority:lane:docker:handshake -- --action request`
+ `--lane-id docker-agent-epicurus-linux-01 --agent-id epicurus`
+ `--agent-class subagent --capability docker-lane`
+
+Use the execution-cell helper when an agent needs an isolated TestStand-owned native session cell:
+
+- `node tools/npm/run-script.mjs priority:lane:execution-cell -- --action request`
+ `--cell-id exec-cell-hooke-01 --agent-id hooke --agent-class subagent`
+ `--suite-class dual-plane-parity --plane-binding native-labview-2026-64`
+ `--capability teststand-harness`
+
+Use the bundle helper when one agent needs a Windows-native execution cell plus an isolated Docker lane under one
+durable receipt:
+
+- `node tools/npm/run-script.mjs priority:lane:execution-cell:bundle -- --action request`
+ `--cell-id exec-cell-sagan-kernel-01 --lane-id docker-agent-sagan-kernel-01`
+ `--agent-id sagan --agent-class sagan --cell-class kernel-coordinator`
+ `--suite-class dual-plane-parity --plane-binding dual-plane-parity`
+ `--capability teststand-harness --capability docker-lane`
+ `--operator-authorization-ref budget-auth://operator/session-2026-03-24`
+
+At `commit`, the execution-cell lease and Docker-lane handshake should bind to each other reciprocally through their
+child receipts. The execution-cell commit now records `dockerLaneId` plus `dockerLaneLeaseId`, and the Docker-lane
+commit records `executionCellId` plus `executionCellLeaseId`. Premium activation is not complete until both receipts
+carry those reciprocal ids for the same agent-owned host fingerprint.
+
+The resulting report is written to:
+
+- `tests/results/_agent/runtime/docker-lane-handshake.json`
+
+- `tests/results/_agent/runtime/execution-cell-lease.json`
+
+- `tests/results/_agent/runtime/execution-cell-bundle.json`
+
+The durable handshake state lives under the Git common-dir so clean worktrees share one lease view.
+
+### Premium Sagan dual-lane rule
+
+Only `sagan` may lease `docker-lane` and `native-labview-2026-32` simultaneously.
+
+- required capabilities:
+ - `docker-lane`
+ - `native-labview-2026-32`
+- required authorization:
+ - `operatorAuthorizationRef`
+- billable multiplier:
+ - `1.5x` the configured operator labor rate
+
+Subagents may lease isolated Docker lanes, but they must not activate the premium dual-lane combination.
+
+### Execution cells and harness instances
+
+Each agent should lease an execution cell before it launches a native TestStand compare session.
+
+- one agent -> one execution cell lease
+- one execution cell -> one owning TestStand harness instance
+- dual-plane parity -> one coordinator harness instance plus one child harness instance per native plane
+
+Project the execution-cell lease into the harness with:
+
+- `-ExecutionCellLeasePath`
+- `-ExecutionCellId`
+- `-ExecutionCellLeaseId`
+- `-HarnessInstanceId`
+
+That keeps session receipts attributable to:
+
+- the agent
+- the execution cell
+- the owning harness instance
+- the canonical host OS fingerprint
+
+Execution cells that use `teststand-compare-harness` must bind only to Windows-native planes:
+
+- `native-labview-2026-64`
+- `native-labview-2026-32`
+- `dual-plane-parity`
+
+Bindings like `docker-desktop/linux-container-2026` or other container/Linux plane identifiers are invalid for
+TestStand-owned cells and should fail closed at lease grant time.
+
+When a single agent needs both a Windows-native execution cell and a Docker lane, prefer the bundle helper over
+manual choreography. It keeps:
+
+- the execution cell receipt
+- the Docker lane handshake
+- premium Sagan rate enforcement
+- rollback of partial grants
+
+under one machine-readable bundle report instead of leaving the allocation split across two separate ad hoc calls.
+
## Authoritative entry points
Use these commands as the checked-in operator surfaces:
@@ -75,10 +184,20 @@ Use these commands as the checked-in operator surfaces:
the recommendation that led to the applied bundle without leaving the
checked-in report chain.
5. Fast Docker Desktop lane loops:
+ - `node tools/npm/run-script.mjs priority:lane:docker:handshake -- --action inspect --lane-id `
- `pwsh -NoLogo -NoProfile -File tools/Test-DockerDesktopFastLoop.ps1 -LaneScope linux -StepTimeoutSeconds 600`
- `pwsh -NoLogo -NoProfile -File tools/Test-DockerDesktopFastLoop.ps1 -LaneScope windows -StepTimeoutSeconds 600`
- `pwsh -NoLogo -NoProfile -File tools/Test-DockerDesktopFastLoop.ps1 -LaneScope both -StepTimeoutSeconds 600`
-6. Differentiated diagnostics replay:
+6. TestStand harness session wrapper:
+ - `pwsh -NoLogo -NoProfile -File tools/TestStand-CompareHarness.ps1 -BaseVi -HeadVi -OutputRoot tests/results/teststand-session -Warmup detect -RenderReport`
+ - Use this when the host plane needs a deterministic native compare session with a replayable `session-index.json`.
+ - To bind the session to an execution cell, add:
+ - `-ExecutionCellLeasePath -ExecutionCellId -ExecutionCellLeaseId -HarnessInstanceId `
+ - For native LabVIEW 2026 x64/x32 parity on the same host, add:
+ - `-SuiteClass dual-plane-parity -LabVIEW64ExePath -LabVIEW32ExePath `
+ - Dual-plane parity still treats the harness as a host-plane consumer. It does not create a new authority plane;
+ it produces a parity receipt across the two existing native planes.
+7. Differentiated diagnostics replay:
- `node tools/npm/run-script.mjs history:diagnostics:show -- --ResultsRoot tests/results/local-parity/windows`
The replay helper is the fastest operator readback. It prints the host-plane report first and then the differentiated
@@ -104,25 +223,29 @@ Use these artifacts as the machine-readable source of truth:
- `tests/results/_agent/runtime/concurrent-lane-apply-receipt.json`
4. Concurrent lane status receipt:
- `tests/results/_agent/runtime/concurrent-lane-status-receipt.json`
-5. Fast-loop readiness envelope:
+5. Docker lane handshake receipt:
+ - `tests/results/_agent/runtime/docker-lane-handshake.json`
+6. Execution cell lease receipt:
+ - `tests/results/_agent/runtime/execution-cell-lease.json`
+7. Execution cell bundle receipt:
+ - `tests/results/_agent/runtime/execution-cell-bundle.json`
+8. Fast-loop readiness envelope:
- `docker-runtime-fastloop-readiness.json`
- `docker-runtime-fastloop-readiness.md`
-6. Fast-loop proof bundle when produced:
+9. Fast-loop proof bundle when produced:
- `docker-fast-loop-proof-*.json`
-7. Top-level fast-loop GitHub outputs when `tools/Test-DockerDesktopFastLoop.ps1` runs inside GitHub Actions:
- - `docker-fast-loop-summary-path`
- - `docker-fast-loop-status-path`
- - `docker-fast-loop-host-plane-summary-path`
- - `docker-fast-loop-host-plane-summary-status`
- - `docker-fast-loop-host-plane-summary-sha256`
- - `docker-fast-loop-host-plane-summary-reason`
-8. Top-level fast-loop Step Summary when `tools/Test-DockerDesktopFastLoop.ps1` receives `-StepSummaryPath`:
- - `Summary Path`
- - `Status Path`
- - `Host Plane Summary Path`
- - `Host Plane Summary Status`
- - `Host Plane Summary SHA-256`
- - `Host Plane Summary Reason`
+10. Top-level fast-loop GitHub outputs when
+ `tools/Test-DockerDesktopFastLoop.ps1` runs inside GitHub Actions:
+ `docker-fast-loop-summary-path`, `docker-fast-loop-status-path`,
+ `docker-fast-loop-host-plane-summary-path`,
+ `docker-fast-loop-host-plane-summary-status`,
+ `docker-fast-loop-host-plane-summary-sha256`, and
+ `docker-fast-loop-host-plane-summary-reason`
+11. Top-level fast-loop Step Summary when
+ `tools/Test-DockerDesktopFastLoop.ps1` receives `-StepSummaryPath`:
+ `Summary Path`, `Status Path`, `Host Plane Summary Path`,
+ `Host Plane Summary Status`, `Host Plane Summary SHA-256`, and
+ `Host Plane Summary Reason`
When the local fast loop runs, prefer the readiness envelope for lane verdicts and the host-plane report for the native
64-bit versus native 32-bit split. For Docker lane replay, use the readiness envelope together with
@@ -135,6 +258,8 @@ Use the artifacts in this order:
1. `labview-2026-host-plane-report.json`
- confirms the native `x64` and `x32` plane readiness
- shows the host/runner identity
+ - records `host.osFingerprint` as the canonical Windows upgrade baseline for
+ the isolated lane group
- records the mutually exclusive Docker pair and the candidate parallel pairs
2. `labview-2026-host-plane-summary.md`
- records the operator-facing summary paired with the report
@@ -154,33 +279,45 @@ Use the artifacts in this order:
- records merge-queue-backed PR state when a PR can be resolved from the applied branch or explicit selector
- keeps deferred manual Docker and host-native shadow lanes explicit for the orchestrator
- records an orchestrator disposition so worker-slot release decisions do not depend on ad hoc GitHub polling
-6. `docker-runtime-fastloop-readiness.json`
+6. `docker-lane-handshake.json`
+ - records request, grant, commit/heartbeat, and release state for one isolated Docker lane
+ - projects `host.osFingerprint.isolatedLaneGroupId` into the lease
+ - records whether premium Sagan dual-lane mode was requested or granted
+ - records the billable operator-equivalent rate derived from the operator cost profile
+7. `execution-cell-bundle.json`
+ - records one agent-owned allocation across a Windows-native execution cell and an optional isolated Docker lane
+ - records the effective billable rate once, even when both child resources are active
+ - rolls back partial grants so failed bundle admission does not strand half-allocated state
+ - keeps premium Sagan dual-lane authorization and Windows-native TestStand requirements in one receipt
+8. `docker-runtime-fastloop-readiness.json`
- records the fast-loop verdict and lane outcomes
- carries the differentiated Docker Desktop plane projection
- records `hostPlaneSummary.path`, `hostPlaneSummary.status`, and `hostPlaneSummary.sha256`
- records whether Docker exclusivity was required and whether it was satisfied
-7. `docker-fast-loop-proof-*.json`
+9. `docker-fast-loop-proof-*.json`
- records `hostPlaneSummaryPath`
- records `hostPlaneSummaryProvenance`
- records `hashes.hostPlaneSummarySha256`
- projects GitHub outputs:
- `docker-fast-loop-proof-host-plane-summary-path`
- `docker-fast-loop-proof-host-plane-summary-sha256`
-8. Top-level `tools/Test-DockerDesktopFastLoop.ps1` GitHub outputs
- - project `docker-fast-loop-summary-path` and `docker-fast-loop-status-path`
- - project `docker-fast-loop-host-plane-summary-path`
- - project `docker-fast-loop-host-plane-summary-status`
- - project `docker-fast-loop-host-plane-summary-sha256`
- - project `docker-fast-loop-host-plane-summary-reason`
- - keep success and fail-closed summary provenance available to downstream workflow consumers without reopening JSON
-9. Top-level `tools/Test-DockerDesktopFastLoop.ps1` Step Summary
- - appends `### Docker Fast Loop Summary`
- - prints the same summary path and status path surfaced through GitHub outputs
- - prints host-plane summary path, status, SHA-256, and fail-closed reason
- - preserves the missing-summary reason before the script throws
-10. `history:diagnostics:show`
- - replays the same distinction in console form for the operator
- - prints `[host-plane-split][summary] status= sha256=` when summary provenance exists
+10. Top-level `tools/Test-DockerDesktopFastLoop.ps1` GitHub outputs:
+ project `docker-fast-loop-summary-path`,
+ `docker-fast-loop-status-path`, `docker-fast-loop-host-plane-summary-path`,
+ `docker-fast-loop-host-plane-summary-status`,
+ `docker-fast-loop-host-plane-summary-sha256`, and
+ `docker-fast-loop-host-plane-summary-reason`. Keep success and fail-closed
+ summary provenance available to downstream workflow consumers without
+ reopening JSON.
+11. Top-level `tools/Test-DockerDesktopFastLoop.ps1` Step Summary:
+ append `### Docker Fast Loop Summary`, print the same summary path and
+ status path surfaced through GitHub outputs, print host-plane summary path,
+ status, SHA-256, and fail-closed reason, and preserve the missing-summary
+ reason before the script throws.
+12. `history:diagnostics:show`:
+ replay the same distinction in console form for the operator and print
+ `[host-plane-split][summary] status= sha256=` when
+ summary provenance exists.
If any of those surfaces disagree on the selected plane or exclusivity state, stop and treat the run as not yet
trustworthy.
@@ -203,6 +340,26 @@ trustworthy.
merge-queued, or fully settled without raw GitHub polling.
8. When summarizing a run, name the exact plane identifier instead of saying “host” or “Docker” without qualification.
9. Do not treat `native-labview-2026-32` as a release or CI authority surface; it is a shadow accelerator only.
+10. Treat `tools/TestStand-CompareHarness.ps1` as a deterministic consumer of a native plane. Its `session-index.json`
+ is useful evidence, but it does not create a new authority plane.
+11. Use the Docker-lane handshake before assigning an isolated Docker lane to a background agent so exclusivity,
+ billable rate, and host fingerprint stay replayable.
+12. When a parity run needs both native LabVIEW 2026 planes at once, use `-SuiteClass dual-plane-parity` and keep the
+ output tied to the same `host.osFingerprint.isolatedLaneGroupId` as the surrounding host-plane receipts.
+13. Only Sagan may request simultaneous `docker-lane` plus
+ `native-labview-2026-32`, and that request must carry an explicit
+ `operatorAuthorizationRef`.
+14. Use `priority:lane:execution-cell:bundle` when one agent needs both a
+ Windows-native TestStand cell and an isolated Docker lane. It is the
+ preferred control surface for Sagan kernel cells and for future per-agent
+ execution cells that need container-local tooling alongside native Windows
+ LabVIEW work.
+15. Compare `host.osFingerprint.fingerprintSha256` before and after host
+ upgrades. If it changes, treat the new value as a moved canonical host OS
+ baseline rather than attributing the drift to the workload first.
+16. Use `host.osFingerprint.isolatedLaneGroupId` as the replayable identifier
+ for this canonical Windows baseline when documenting or comparing isolated
+ local lane groups.
## Related contracts
@@ -210,10 +367,16 @@ trustworthy.
- [concurrent-lane-apply-receipt-v1.schema.json](schemas/concurrent-lane-apply-receipt-v1.schema.json)
- [concurrent-lane-status-receipt-v1.schema.json](schemas/concurrent-lane-status-receipt-v1.schema.json)
- [concurrent-lane-plan-v1.schema.json](schemas/concurrent-lane-plan-v1.schema.json)
+- [docker-lane-handshake-v1.schema.json](schemas/docker-lane-handshake-v1.schema.json)
+- [docker-lane-handshake-report-v1.schema.json](schemas/docker-lane-handshake-report-v1.schema.json)
+- [execution-cell-bundle-report-v1.schema.json](schemas/execution-cell-bundle-report-v1.schema.json)
- [labview-2026-host-plane-report-v1.schema.json](schemas/labview-2026-host-plane-report-v1.schema.json)
- [Write-LabVIEW2026HostPlaneDiagnostics.ps1](../tools/Write-LabVIEW2026HostPlaneDiagnostics.ps1)
- [concurrent-lane-apply.mjs](../tools/priority/concurrent-lane-apply.mjs)
- [concurrent-lane-status.mjs](../tools/priority/concurrent-lane-status.mjs)
+- [execution-cell-bundle.mjs](../tools/priority/execution-cell-bundle.mjs)
- [concurrent-lane-plan.mjs](../tools/priority/concurrent-lane-plan.mjs)
+- [docker-lane-handshake.mjs](../tools/priority/docker-lane-handshake.mjs)
- [Test-DockerDesktopFastLoop.ps1](../tools/Test-DockerDesktopFastLoop.ps1)
+- [TestStand-CompareHarness.ps1](../tools/TestStand-CompareHarness.ps1)
- [Show-DockerFastLoopDiagnostics.ps1](../tools/Show-DockerFastLoopDiagnostics.ps1)
diff --git a/docs/TESTSTAND_INTEGRATION_PLAN.md b/docs/TESTSTAND_INTEGRATION_PLAN.md
index 27347b9c4..3f9a4896e 100644
--- a/docs/TESTSTAND_INTEGRATION_PLAN.md
+++ b/docs/TESTSTAND_INTEGRATION_PLAN.md
@@ -41,9 +41,83 @@ stays available even when fresh harness artefacts are not present.
`tests/results/teststand-session/session-index.json` produced locally, allowing agents to verify shape changes without
rerunning LabVIEW.
+TestStand itself is Windows-only. Treat it as a Windows-native execution-cell runtime, not as a Linux or Docker
+runtime. Linux/container planes may still participate elsewhere in the host fabric, but not as TestStand-owned harness
+cells.
+
Validate the session index with `node tools/npm/run-script.mjs session:teststand:validate` so schema regressions surface
immediately when the harness outputs change.
+### 1.2.1 Dual-plane parity command
+
+The harness now also supports an opt-in LabVIEW 2026 native parity suite that launches both native planes
+simultaneously and writes a parity-aware `session-index.json`.
+
+```powershell
+pwsh -NoLogo -NoProfile -File tools/TestStand-CompareHarness.ps1 `
+ -BaseVi (Resolve-Path .\VI1.vi) `
+ -HeadVi (Resolve-Path .\VI2.vi) `
+ -OutputRoot tests/results/teststand-session `
+ -SuiteClass dual-plane-parity `
+ -LabVIEW64ExePath 'C:\Program Files\National Instruments\LabVIEW 2026\LabVIEW.exe' `
+ -LabVIEW32ExePath 'C:\Program Files (x86)\National Instruments\LabVIEW 2026\LabVIEW.exe' `
+ -Warmup detect `
+ -RenderReport
+```
+
+Parity sessions use `schema = teststand-compare-session/v2` and include:
+
+- `suiteClass = dual-plane-parity`
+- `primaryPlane = native-labview-2026-64`
+- `requestedSimultaneous = true`
+- `processModel.runtimeSurface = windows-native-teststand`
+- `processModel.processModelClass = parallel-process-model`
+- `planes.x64` / `planes.x32` single-plane session records
+- `parity.status`, `mismatchCount`, and field-level mismatch details
+
+`Run-DX.ps1` forwards the same contract through:
+
+- `-TestStandSuiteClass dual-plane-parity`
+- `-LabVIEW64ExePath`
+- `-LabVIEW32ExePath`
+
+This keeps dual-plane parity runs visible in `tests/results/_agent/dx-status.json` without changing the default
+single-plane TestStand path.
+
+### 1.2.2 Execution-cell-owned harness instances
+
+Treat the harness as an execution-cell consumer, not as ambient host state.
+
+- each agent leases one execution cell
+- that execution cell owns its harness instance
+- dual-plane parity keeps one coordinator harness instance plus one child harness instance per plane
+
+The harness now accepts:
+
+- `-ExecutionCellLeasePath`
+- `-ExecutionCellId`
+- `-ExecutionCellLeaseId`
+- `-HarnessInstanceId`
+
+Session receipts project both:
+
+- `executionCell`
+- `harnessInstance`
+- `processModel`
+
+That keeps TestStand evidence attributable to one agent-owned memory/process boundary instead of an unscoped host run.
+
+The explicit process-model contract now makes 3 things machine-readable:
+
+- `executionCell.runtimeSurface = windows-native-teststand`
+- `harnessInstance.processModelClass = sequential-process-model|parallel-process-model`
+- `processModel.rootHarnessInstanceId` / `planeCount` so coordinator-owned parity runs stay attributable even when child
+ plane receipts are inspected independently
+
+When the owning agent also needs an isolated Docker lane for repeatable adjunct tooling, prefer
+`priority:lane:execution-cell:bundle` over separate lease calls. That bundle projects one effective billable rate,
+rolls back partial allocations, and keeps the Windows-only TestStand contract attached to the same cell-owned receipt.
+
> **Note**: `-CloseLabVIEW` / `-CloseLVCompare` now queue post-run cleanup requests. The helpers do not invoke the close
> scripts inline; instead `tools/Post-Run-Cleanup.ps1` consumes the requests after `Invoke-PesterTests.ps1` completes,
> guaranteeing a single LabVIEWCLI invocation per job.
@@ -109,8 +183,9 @@ deterministic:
### 2.2 Telemetry
-- Update `tools/Ensure-SessionIndex.ps1` to recognise the `teststand-compare-session/v1` schema and emit summary lines
- (`exit`, `diff`, elapsed seconds).
+- Update `tools/Ensure-SessionIndex.ps1` to recognise both `teststand-compare-session/v1` and
+ `teststand-compare-session/v2`, emitting summary lines (`exit`, `diff`, elapsed seconds) and parity status when the
+ dual-plane suite is used.
- Amend the Summary appender to group TestStand runs under a dedicated heading (`### TestStand Compare Session`).
- Capture the warmup/compare NDJSON files via the artifact manifest so they are available for debugging.
diff --git a/docs/archive/releases/RELEASE_NOTES_v0.6.4-rc.2.md b/docs/archive/releases/RELEASE_NOTES_v0.6.4-rc.2.md
new file mode 100644
index 000000000..8509383e5
--- /dev/null
+++ b/docs/archive/releases/RELEASE_NOTES_v0.6.4-rc.2.md
@@ -0,0 +1,42 @@
+
+# Release v0.6.4-rc.2
+
+Highlights
+
+- The next RC publishes the producer-owned Docker contract in
+ `CompareVI.Tools`.
+ - `comparevi-tools-release.json` now carries
+ `consumerContract.capabilities.dockerProfile`.
+ - The same payload now exposes the producer-owned
+ `consumerContract.dockerImageContract` source needed by downstream Docker
+ distributors.
+- `v0.6.4-rc.2` is the honest follow-up to the published `v0.6.4-rc.1` bundle.
+ - `v0.6.4-rc.1` is now authoritative for the producer-native `vi-history`
+ contract.
+ - It still predates commit `5969b9114cafdab989dadb70c5bec188b07a3996`, so its
+ published bundle does not include the new docker-profile capability.
+- The template Docker-profile rail stays dependency-driven.
+ - `LabviewGitHubCiTemplate#20` remains blocked until this RC is published and
+ the producer bundle proves the Docker contract authoritatively.
+ - The template should consume the published producer contract, not invent a
+ template-local Docker image convention.
+
+Upgrade Notes
+
+- This is a release candidate. The final `v0.6.4` release still depends on RC
+ validation, authoritative bundle publication, and the template follow-up
+ consuming the published contract cleanly.
+- The replay-routing repair from `#1942` stays part of the release story, but it
+ is no longer the active publication blocker. The remaining release objective
+ is publishing the newer producer contract on the next RC identity.
+
+Validation Checklist
+
+- [x] `node tools/npm/run-script.mjs release:branch -- 0.6.4-rc.2`
+- [ ] Live hosted RC validation on `release/v0.6.4-rc.2`
+- [ ] `node tools/npm/run-script.mjs release:finalize -- 0.6.4-rc.2`
+- [ ] `node tools/npm/run-script.mjs priority:release:conductor -- --apply --channel rc --version 0.6.4-rc.2`
+- [ ] `node tools/npm/run-script.mjs priority:release:published:bundle`
+- [ ] Published `CompareVI.Tools-v0.6.4-rc.2.zip` proves both:
+ - producer-native `vi-history`
+ - producer-owned `dockerProfile`
diff --git a/docs/documentation-manifest.json b/docs/documentation-manifest.json
index c12af1157..2b3862a5f 100644
--- a/docs/documentation-manifest.json
+++ b/docs/documentation-manifest.json
@@ -2,7 +2,7 @@
"$schema": "./schemas/documentation-manifest-v1.schema.json",
"schema": "documentation-manifest-v1",
"version": "1.0.0",
- "updated": "2026-03-22T23:35:00Z",
+ "updated": "2026-03-24T02:15:00Z",
"entries": [
{
"name": "Root Entry Points",
@@ -31,6 +31,33 @@
"docs/release/TAG_PREP_CHECKLIST.md"
]
},
+ {
+ "name": "Release Signing Readiness Contracts",
+ "category": "supporting",
+ "status": "reference",
+ "description": "Workflow-owned tag-signing readiness report contract, focused tests, and runbook references used to surface signing capability as an explicit external blocker before release attempts.",
+ "files": [
+ "docs/RELEASE_OPERATIONS_RUNBOOK.md",
+ "docs/RELEASE_PROMOTION_CONTRACT.md",
+ "docs/schemas/release-signing-readiness-report-v1.schema.json",
+ "tools/priority/release-signing-readiness.mjs",
+ "tools/priority/__tests__/release-signing-readiness.test.mjs",
+ "tools/priority/__tests__/release-signing-readiness-schema.test.mjs"
+ ]
+ },
+ {
+ "name": "Published CompareVI.Tools Bundle Observer",
+ "category": "supporting",
+ "status": "reference",
+ "description": "Published-release observer that downloads the latest CompareVI.Tools asset and checks whether the producer-native vi-history contract is live for downstream template distribution.",
+ "files": [
+ "docs/RELEASE_PROMOTION_CONTRACT.md",
+ "docs/schemas/release-published-bundle-observer-report-v1.schema.json",
+ "tools/priority/release-published-bundle-observer.mjs",
+ "tools/priority/__tests__/release-published-bundle-observer.test.mjs",
+ "tools/priority/__tests__/release-published-bundle-observer-schema.test.mjs"
+ ]
+ },
{
"name": "Docs Tree",
"category": "docs",
@@ -134,6 +161,8 @@
"docs/schemas/agent-cost-turn-v1.schema.json",
"docs/schemas/agent-cost-rollup-v1.schema.json",
"docs/schemas/average-issue-cost-scorecard-v1.schema.json",
+ "docs/schemas/github-comment-budget-hook-policy-v1.schema.json",
+ "docs/schemas/github-comment-budget-hook-report-v1.schema.json",
"docs/schemas/operator-cost-profile-v1.schema.json",
"docs/schemas/pr-spend-projection-v1.schema.json",
"tools/priority/__fixtures__/agent-cost-rollup/live-turn-estimated.json",
@@ -142,13 +171,17 @@
"tools/priority/__fixtures__/agent-cost-rollup/invoice-turn-next-baseline.json",
"tools/priority/__fixtures__/agent-cost-rollup/invoice-turn-baseline-reconciled.json",
"tools/priority/__fixtures__/agent-cost-rollup/private-invoice-metadata-sample.json",
+ "tools/policy/github-comment-budget-hook.json",
"tools/policy/operator-cost-profile.json",
"tools/priority/agent-cost-invoice-normalize.mjs",
"tools/priority/agent-cost-invoice-turn.mjs",
"tools/priority/agent-cost-turn.mjs",
"tools/priority/agent-cost-rollup.mjs",
"tools/priority/average-issue-cost-scorecard.mjs",
+ "tools/priority/github-comment-budget-hook.mjs",
"tools/priority/pr-spend-projection.mjs",
+ "tools/priority/__tests__/github-comment-budget-hook.test.mjs",
+ "tools/priority/__tests__/github-comment-budget-hook-schema.test.mjs",
"tools/priority/__tests__/average-issue-cost-scorecard.test.mjs",
"tools/priority/__tests__/average-issue-cost-scorecard-schema.test.mjs",
"tools/priority/__tests__/agent-cost-invoice-normalize.test.mjs",
@@ -435,7 +468,7 @@
"name": "Host Plane Diagnostics Contracts",
"category": "supporting",
"status": "reference",
- "description": "Machine-readable report and summary contracts, VI-history local runtime-plane receipts, helper entrypoints, fast-loop provenance surfaces, and the single-host runbook for the LabVIEW 2026 host-plane split.",
+ "description": "Machine-readable report and summary contracts, VI-history local runtime-plane receipts, lease-backed Docker-lane handshake contracts, TestStand harness host-plane attribution, helper entrypoints, fast-loop provenance surfaces, and the single-host runbook for the LabVIEW 2026 host-plane split.",
"files": [
"docs/DEVELOPER_GUIDE.md",
"docs/SINGLE_HOST_LABVIEW_2026_PLANES.md",
@@ -447,18 +480,34 @@
"docs/schemas/comparevi-local-runtime-health-v1.schema.json",
"docs/schemas/comparevi-local-runtime-lease-v1.schema.json",
"docs/schemas/comparevi-local-runtime-state-v1.schema.json",
+ "docs/schemas/docker-lane-handshake-v1.schema.json",
+ "docs/schemas/docker-lane-handshake-report-v1.schema.json",
+ "docs/schemas/execution-cell-bundle-report-v1.schema.json",
+ "docs/schemas/execution-cell-lease-v1.schema.json",
+ "docs/schemas/execution-cell-lease-report-v1.schema.json",
"docs/schemas/labview-2026-host-plane-report-v1.schema.json",
"tests/VIHistoryLocalAcceleration.Tests.ps1",
+ "tests/TestStand-CompareHarness.Tests.ps1",
"tools/Build-VIHistoryDevImage.ps1",
"tools/Invoke-VIHistoryLocalOperatorSession.ps1",
"tools/Invoke-VIHistoryLocalRefinement.ps1",
+ "tools/TestStand-CompareHarness.ps1",
"tools/Manage-VIHistoryRuntimeInDocker.ps1",
"tools/LabVIEW2026HostPlaneDiagnostics.psm1",
"tools/Show-DockerFastLoopDiagnostics.ps1",
"tools/Test-DockerDesktopFastLoop.ps1",
"tools/Write-DockerFastLoopProof.ps1",
"tools/Write-DockerFastLoopReadiness.ps1",
- "tools/Write-LabVIEW2026HostPlaneDiagnostics.ps1"
+ "tools/Write-LabVIEW2026HostPlaneDiagnostics.ps1",
+ "tools/priority/docker-lane-handshake.mjs",
+ "tools/priority/execution-cell-bundle.mjs",
+ "tools/priority/execution-cell-lease.mjs",
+ "tools/priority/__tests__/docker-lane-handshake.test.mjs",
+ "tools/priority/__tests__/docker-lane-handshake-schema.test.mjs",
+ "tools/priority/__tests__/execution-cell-bundle.test.mjs",
+ "tools/priority/__tests__/execution-cell-bundle-schema.test.mjs",
+ "tools/priority/__tests__/execution-cell-lease.test.mjs",
+ "tools/priority/__tests__/execution-cell-lease-schema.test.mjs"
]
},
{
diff --git a/docs/knowledgebase/Agent-Cost-Telemetry-Surfaces.md b/docs/knowledgebase/Agent-Cost-Telemetry-Surfaces.md
index c88387ccd..f7957de58 100644
--- a/docs/knowledgebase/Agent-Cost-Telemetry-Surfaces.md
+++ b/docs/knowledgebase/Agent-Cost-Telemetry-Surfaces.md
@@ -258,6 +258,47 @@ There is now a local-only normalization helper for private invoice metadata:
- helper: `tools/priority/agent-cost-invoice-normalize.mjs`
This helper intentionally does not scrape PDFs directly in the stable slice.
+
+## Durable GitHub Comment Budget Hook
+
+Automation-authored GitHub comments now have a checked-in budget attestation
+surface so cost state survives session compaction and comment history remains a
+durable breadcrumb for later agents.
+
+- schema: `docs/schemas/github-comment-budget-hook-policy-v1.schema.json`
+- schema: `docs/schemas/github-comment-budget-hook-report-v1.schema.json`
+- policy: `tools/policy/github-comment-budget-hook.json`
+- helper: `tools/priority/github-comment-budget-hook.mjs`
+- npm surface: `priority:cost:comment-hook`
+- wrappers:
+ - `tools/Post-IssueComment.ps1`
+ - `tools/Post-PullRequestComment.ps1`
+
+The hook appends a machine-readable and human-readable budget block to GitHub
+comments with these markers:
+
+- ``
+- ``
+
+The hook projects:
+
+- token spend
+- observed operator-equivalent labor
+- observed blended lower-bound spend
+- operator budget cap / remaining lower bound
+- operational invoice-turn remainder
+- reserved calibration funding window state
+- live/background/total turn counts
+
+The checked-in policy keeps the calibration window reserved instead of silently
+consuming it. The current intent is:
+
+- operational invoice turn may spend
+- calibration invoice turn remains on hold
+
+Use the wrappers by default so GitHub issue and PR comments pick up the durable
+budget hook automatically. Pass `-SkipBudgetHook` only for narrow test or
+break-glass cases where the attestation must be suppressed deliberately.
Instead, it normalizes a local private metadata JSON payload into a checked-in
invoice-turn contract. That keeps raw invoice documents out of the repository
while still reducing manual transcription drift.
diff --git a/docs/knowledgebase/Agent-Handoff-Surfaces.md b/docs/knowledgebase/Agent-Handoff-Surfaces.md
index aef0e817a..b7078a2b8 100644
--- a/docs/knowledgebase/Agent-Handoff-Surfaces.md
+++ b/docs/knowledgebase/Agent-Handoff-Surfaces.md
@@ -23,7 +23,12 @@ entrypoint and machine-generated live state.
template pivot readiness.
- It refreshes `tests/results/_agent/handoff/autonomous-governor-summary.json`,
which is the top-level machine-readable rollup for the autonomous governor's
- current mode, wake disposition, funding-quality posture, and next owner.
+ current mode, wake disposition, funding-quality posture, release-signing
+ readiness, and next owner.
+- It refreshes `tests/results/_agent/handoff/sagan-context-concentrator.json`,
+ which is the machine-readable hot/warm memory concentrator for the current
+ standing issue, current owner decision, recent subagent episodes, and durable
+ blocker context.
- It refreshes
`tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json`,
which is the cross-repo machine-readable rollup for compare, canonical
@@ -43,6 +48,9 @@ entrypoint and machine-generated live state.
- `node tools/npm/run-script.mjs priority:handoff`
imports the handoff bundle and prints the entrypoint index, standing-priority
snapshot, and other current summaries.
+- `node tools/npm/run-script.mjs priority:context:concentrate`
+ rebuilds the compact context concentrator directly when you need the
+ synthesized hot/warm memory view without the full handoff bundle.
- `node tools/npm/run-script.mjs priority:handoff-tests`
exercises the contract lane used to keep these handoff surfaces from drifting.
@@ -58,8 +66,10 @@ entrypoint and machine-generated live state.
- `tests/results/_agent/handoff/entrypoint-status.json`
- `tests/results/_agent/handoff/monitoring-mode.json`
- `tests/results/_agent/handoff/autonomous-governor-summary.json`
+- `tests/results/_agent/handoff/sagan-context-concentrator.json`
- `tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json`
- `tests/results/_agent/handoff/downstream-repo-graph-truth.json`
+- `tests/results/_agent/release/release-signing-readiness.json`
- `tests/results/_agent/handoff/docker-review-loop-summary.json`
- `tests/results/_agent/handoff/*.json`
- `tests/results/_agent/sessions/*.json`
@@ -81,6 +91,9 @@ entrypoint and machine-generated live state.
event-driven monitoring mode.
- `tests/results/_agent/handoff/autonomous-governor-summary.json` is the
top-level operating summary for the autonomous governor.
+- `tests/results/_agent/handoff/sagan-context-concentrator.json` is the compact
+ durable memory view that keeps subagent findings, hot blockers, and current
+ owner decisions close to the active handoff surface.
- `tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json` is
the cross-repo operating summary for compare, canonical template, and proving
forks together.
@@ -92,8 +105,14 @@ entrypoint and machine-generated live state.
- merge-queue-owned PR waits, including the next wake condition and PR URL
- template pivot readiness
- current governor mode and next owner
+ - `vi-history` distributor dependency status between compare and the
+ canonical template
- latest wake lifecycle terminal state
- funding-quality posture for the latest wake
+ - release-signing readiness, including explicit external blockers when workflow
+ signing material is absent
+ - concentrated subagent episode memory, including hot working set,
+ warm recent memory, archive count, and lower-bound blended spend
- cross-repo owner and next-owner decisions
- repo graph truth for producer lineage, canonical development, and consumer proving
- wake conditions that should reopen compare or template work
diff --git a/docs/knowledgebase/CrossRepo-VIHistory.md b/docs/knowledgebase/CrossRepo-VIHistory.md
index 9a88f7bd6..f78df3315 100644
--- a/docs/knowledgebase/CrossRepo-VIHistory.md
+++ b/docs/knowledgebase/CrossRepo-VIHistory.md
@@ -114,6 +114,11 @@ The capability contract tells downstream distributors:
- `consumerContract.localOperatorSession`
- `consumerContract.diagnosticsCommentRenderer`
- `consumerContract.hostedNiLinuxRunner`
+- the template Docker profile should resolve the Producer-published Docker
+ image contract from
+ `consumerContract.capabilities.dockerProfile.authoritativeImageContractSource`,
+ which currently points at `consumerContract.dockerImageContract` inside the
+ same immutable `comparevi-tools-release.json` payload
That keeps the producer/distributor boundary clean:
@@ -122,6 +127,11 @@ That keeps the producer/distributor boundary clean:
- generated repositories consume the pinned release surface instead of
vendoring compare internals
+The autonomous governor portfolio also treats that producer/distributor link as
+an explicit dependency. Compare remains the current owner until the signed
+producer-native `CompareVI.Tools` release is ready, and only then does the
+portfolio hand off the next-owner route to `LabviewGitHubCiTemplate`.
+
For hosted GitHub runner diagnostics, use the same extracted bundle root as
`COMPAREVI_SCRIPTS_ROOT` and resolve the NI Linux runner from
`tools/Run-NILinuxContainerCompare.ps1`. Keep its adjacent support scripts
diff --git a/docs/knowledgebase/GitHub-Intake-Layer.md b/docs/knowledgebase/GitHub-Intake-Layer.md
index d89e60c6c..32ad4ba4c 100644
--- a/docs/knowledgebase/GitHub-Intake-Layer.md
+++ b/docs/knowledgebase/GitHub-Intake-Layer.md
@@ -137,6 +137,11 @@ instead of inferring the correct path from prose alone.
gh issue comment 875 --body-file issue-comment.md
```
+ `Post-IssueComment.ps1` now appends the durable budget hook by default so
+ automation-authored comments retain spend state even after session compaction.
+ Use `-SkipBudgetHook` only when a test or narrow break-glass path needs the
+ raw body unchanged.
+
- Pull-request comments:
```powershell
@@ -144,6 +149,9 @@ instead of inferring the correct path from prose alone.
gh pr comment 875 --repo owner/repo --body-file pr-comment.md
```
+ `Post-PullRequestComment.ps1` follows the same default and appends the durable
+ budget hook unless `-SkipBudgetHook` is explicit.
+
- PR bodies:
```powershell
@@ -234,4 +242,5 @@ Human-authored PRs should use the `human-change` template so they do not acciden
For issue creation, issue comments, PR comments, and PR creation in mixed WSL/Windows shells, prefer `--body-file`
over inline multiline `--body` strings. For comments, prefer `tools/Post-IssueComment.ps1` and
`tools/Post-PullRequestComment.ps1` so PowerShell lanes always route through a temporary or explicit body file. That
-keeps quoting deterministic and aligns with the guidance in `AGENTS.md`.
+keeps quoting deterministic, appends the durable budget hook by default, and
+aligns with the guidance in `AGENTS.md`.
diff --git a/docs/release/PR_NOTES.md b/docs/release/PR_NOTES.md
index 7a7330646..9933943e8 100644
--- a/docs/release/PR_NOTES.md
+++ b/docs/release/PR_NOTES.md
@@ -1,39 +1,38 @@
-# Release v0.6.4-rc.1 - PR Notes Helper
+# Release v0.6.4-rc.2 - PR Notes Helper
-Reference sheet for refining the `v0.6.4-rc.1` release PR and draft release.
-This RC is about hardening the hosted-first release conductor, keeping the
-template conveyor pinned and green, and proving the repo can reach a truthful
-queue-empty state before the template pivot.
+Reference sheet for refining the `v0.6.4-rc.2` release PR and draft release.
+This RC is about publishing the merged producer-owned Docker contract, keeping
+the template conveyor pinned and green, and finishing the compare-side release
+identity shift needed to unblock the template Docker-profile consumer rail.
## 1. Summary
-Release `v0.6.4-rc.1` focuses on four themes:
+Release `v0.6.4-rc.2` focuses on four themes:
-- **Hosted-first release gating**: the release conductor now aligns `release/*`
- policy, live GitHub rulesets, and the actual RC PR gate so finalize depends
- on the checks that really matter.
+- **Producer-owned Docker contract publication**: the next RC publishes
+ `consumerContract.capabilities.dockerProfile` and
+ `consumerContract.dockerImageContract` in the authoritative
+ `CompareVI.Tools` release bundle.
+- **Honest RC identity shift**: `v0.6.4-rc.1` is now authoritative for
+ producer-native `vi-history`, but a fresh RC is needed because that published
+ bundle predates the merged Docker-profile contract.
- **Template conveyor as a pinned dependency**:
`LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate@v0.1.1` is treated as an
immutable dependency and is revalidated through the cookiecutter conveyor.
-- **Continuity/control-plane hardening**: standing rotation, detached
- bootstrap, linked worktree release helpers, and queue-empty proof surfaces
- now support an unattended RC cut.
-- **Capital deployment telemetry**: PR/issue spend, invoice-turn attribution,
- and template verification cost provenance stay visible while the RC moves.
+- **Continuity/control-plane hardening**: replay automation routing, standing
+ release continuity, and published-bundle observation stay aligned while the
+ RC moves toward authoritative Docker-contract publication.
## 2. RC Highlights
-- Release and feature dry-run helpers are worktree-safe, so `release:branch`,
- `release:finalize`, `feature:branch:dry`, and `feature:finalize:dry` behave
- correctly when `develop` is attached elsewhere.
-- `priority:pivot:template` now treats `queue-empty` as authoritative and only
- blocks on real remaining gates.
-- The downstream proving rail fails closed when template verification is
- missing, stale, or drifted from the pinned template dependency.
-- Hosted release readiness now evaluates the live `validate.yml` and
- `fixture-drift.yml` evidence lanes rather than retired self-hosted compare
- workflows.
+- The published bundle observer now proves `v0.6.4-rc.1` is authoritative for
+ producer-native `vi-history`, which narrows the remaining release gap to the
+ newer Docker-profile contract.
+- The next RC carries the merged producer Docker contract from `#1940` / `#1941`
+ onto the release surface instead of relying on template-local conventions.
+- The downstream template rail remains pinned and blocked cleanly until the new
+ producer contract is published.
## 3. Validation Snapshot
@@ -43,33 +42,36 @@ Release `v0.6.4-rc.1` focuses on four themes:
- `smoke-gate`
- `Policy Guard (Upstream) / policy-guard`
- `commit-integrity`
-- [ ] Latest `fixture-drift.yml` run for `release/v0.6.4-rc.1` is green and
+- [ ] Latest `fixture-drift.yml` run for `release/v0.6.4-rc.2` is green and
uploads the NI Linux review-suite evidence bundle.
- [ ] Latest template verification report stays `pass` for
`LabviewGitHubCiTemplate@v0.1.1`.
-- [ ] `node tools/npm/run-script.mjs release:finalize -- 0.6.4-rc.1` completes
+- [ ] `node tools/npm/run-script.mjs release:finalize -- 0.6.4-rc.2` completes
from a clean helper lane and writes fresh finalize metadata under
`tests/results/_agent/release/`.
+- [ ] `node tools/npm/run-script.mjs priority:release:published:bundle` flips
+ to the new RC and proves the producer-owned Docker contract is present.
## 4. Reviewer Focus
- Confirm `CHANGELOG.md`, this helper, `TAG_PREP_CHECKLIST.md`, and
- `../archive/releases/RELEASE_NOTES_v0.6.4-rc.1.md` all reference
- `v0.6.4-rc.1` consistently.
-- Review the hosted-first release gate adjustments:
- - `tools/policy/branch-required-checks.json`
- - `tools/priority/lib/release-pr-checks.mjs`
- - `tools/priority/lib/release-compare-evidence.mjs`
+ `../archive/releases/RELEASE_NOTES_v0.6.4-rc.2.md` all reference
+ `v0.6.4-rc.2` consistently.
+- Review the producer Docker-contract publication surfaces:
+ - `tools/Publish-CompareVIToolsArtifact.ps1`
+ - `docs/schemas/comparevi-tools-release-manifest-v1.schema.json`
+ - `docs/schemas/comparevi-tools-docker-profile-capability-v1.schema.json`
+ - `docs/schemas/comparevi-tools-docker-image-contract-v1.schema.json`
- Check that the release branch verification helper is validating real RC
- assets instead of stale historical release docs.
-- Check that the fixture-drift hosted Linux lane remains deterministic on
- `release/*` branches while keeping the VI history safeguard honest.
+ materials instead of stale historical release docs.
## 5. Follow-Up After RC
-1. Cut the final `v0.6.4` release once RC evidence is stable.
-2. Re-run the template pivot gate after the RC version is published.
-3. Keep the downstream proving rail pinned to the released template tag until a
- deliberate dependency bump is queued.
+1. Re-run the published-bundle observer after publication and confirm the
+ producer-owned Docker contract is authoritative.
+2. Start `LabviewGitHubCiTemplate#20` only after that published contract is
+ real.
+3. Cut the final `v0.6.4` release once the RC evidence and template follow-up
+ both settle.
---- Updated: 2026-03-22 (aligned with the `v0.6.4-rc.1` release candidate).
+--- Updated: 2026-03-24 (aligned with the `v0.6.4-rc.2` release candidate).
diff --git a/docs/release/TAG_PREP_CHECKLIST.md b/docs/release/TAG_PREP_CHECKLIST.md
index a8ab2289f..6b5b95fde 100644
--- a/docs/release/TAG_PREP_CHECKLIST.md
+++ b/docs/release/TAG_PREP_CHECKLIST.md
@@ -1,14 +1,15 @@
-# v0.6.4-rc.1 Tag Preparation Checklist
+# v0.6.4-rc.2 Tag Preparation Checklist
-Helper reference for cutting the `v0.6.4-rc.1` release candidate. Aligns with
+Helper reference for cutting the `v0.6.4-rc.2` release candidate. Aligns with
the archived release notes
-(`../archive/releases/RELEASE_NOTES_v0.6.4-rc.1.md`) and the RC cut issue
-(`#1797`). Update or archive once the release candidate is live.
+(`../archive/releases/RELEASE_NOTES_v0.6.4-rc.2.md`) and the standing compare
+publication rail (`#1877`). Update or archive once the release candidate is
+live.
## 1. Pre-flight Verification
-- [ ] Work from `release/v0.6.4-rc.1` (or the latest RC helper lane) and ensure
+- [ ] Work from `release/v0.6.4-rc.2` (or the latest RC helper lane) and ensure
it contains all RC-targeted changes.
- [ ] CI is green on the RC branch (Validate, Fixture Drift Validation,
Cookiecutter Bootstrap, and any active proving workflows).
@@ -24,10 +25,14 @@ the archived release notes
## 2. Version & Metadata Consistency
- [ ] `CHANGELOG.md` contains a finalized
- `## [v0.6.4-rc.1] - 2026-03-22` section.
-- [ ] Release docs reference `v0.6.4-rc.1` consistently where the RC is
+ `## [v0.6.4-rc.2] - 2026-03-24` section.
+- [ ] Release docs reference `v0.6.4-rc.2` consistently where the RC is
intentionally named.
-- [ ] `package.json` version is `0.6.4-rc.1` and matches the release notes.
+- [ ] `package.json` version is `0.6.4-rc.2` and matches the release notes.
+- [ ] The release materials explain why this RC exists:
+ - `v0.6.4-rc.1` is authoritative for producer-native `vi-history`
+ - `v0.6.4-rc.2` is the first RC meant to publish the producer-owned
+ docker-profile contract
- [ ] Regenerate `docs/action-outputs.md` if outputs changed
(`node tools/npm/run-script.mjs generate:outputs`) and confirm `action.yml`
matches the documented inputs/outputs.
@@ -52,7 +57,7 @@ the archived release notes
## 5. Release Materials Review
- [ ] `PR_NOTES.md`, this checklist, and
- `../archive/releases/RELEASE_NOTES_v0.6.4-rc.1.md` are consistent.
+ `../archive/releases/RELEASE_NOTES_v0.6.4-rc.2.md` are consistent.
- [ ] Helper docs reflect the hosted-first RC flow:
- `docs/knowledgebase/FEATURE_BRANCH_POLICY.md`
- `docs/knowledgebase/VICompare-Refs-Workflow.md`
@@ -62,34 +67,49 @@ the archived release notes
## 6. Tag Creation
+- [ ] Verify signed-tag readiness before push:
+
+```pwsh
+node tools/npm/run-script.mjs priority:release:signing:readiness
+node tools/npm/run-script.mjs priority:release:conductor -- --apply --channel rc --version 0.6.4-rc.2
+```
+
+- [ ] Confirm `tests/results/_agent/release/release-signing-readiness.json`
+ does not report `externalBlocker` before retrying authoritative release
+ publication.
+- [ ] Confirm `tests/results/_agent/release/release-conductor-report.json` reports
+ `status: pass` before pushing the RC tag.
- [ ] Create an annotated RC tag:
```pwsh
-git tag -a v0.6.4-rc.1 -m "v0.6.4-rc.1: hosted-first release conductor hardening"
+git tag -a v0.6.4-rc.2 -m "v0.6.4-rc.2: publish producer docker-profile contract"
```
- [ ] Push the tag:
```pwsh
-git push origin v0.6.4-rc.1
+git push origin v0.6.4-rc.2
```
## 7. GitHub Release Draft
Suggested draft-release outline:
-1. Summary: hosted-first release conductor hardening, template conveyor
- dependency, continuity/control-plane fixes.
-2. Upgrade notes: release helper safety, RC gate alignment, queue-empty pivot
- proof.
+1. Summary: producer-owned Docker contract publication, template conveyor
+ dependency, and release-surface continuity.
+2. Upgrade notes: `v0.6.4-rc.1` already published the producer-native
+ `vi-history` contract; `v0.6.4-rc.2` carries the producer-owned Docker
+ contract on the next authoritative RC.
3. Validation snapshot: required checks, Fixture Drift Validation,
- Cookiecutter Bootstrap, and template verification.
-4. Known issues / follow-ups: final `v0.6.4` cut, remaining non-RC backlog.
+ Cookiecutter Bootstrap, template verification, and published-bundle
+ observation.
+4. Known issues / follow-ups: final `v0.6.4` cut and template `#20` promotion
+ after authoritative publication proof.
5. Rollback: link to `ROLLBACK_PLAN.md`.
## 8. Post-Tag Actions
-- [ ] Run `node tools/npm/run-script.mjs release:finalize -- 0.6.4-rc.1` from a
+- [ ] Run `node tools/npm/run-script.mjs release:finalize -- 0.6.4-rc.2` from a
clean helper lane to fast-forward `main` and `develop`, then record the
finalize metadata.
- [ ] Refresh `priority:pivot:template` after the RC version lands so the pivot
@@ -99,18 +119,21 @@ Suggested draft-release outline:
## 9. Validation After Publish
-- [ ] Install the action via `@v0.6.4-rc.1` in a sample workflow and confirm a
+- [ ] Install the action via `@v0.6.4-rc.2` in a sample workflow and confirm a
compare using the canonical fixtures succeeds.
- [ ] Exercise the pinned template conveyor and downstream proving rail against
the RC release summary.
+- [ ] Re-run `node tools/npm/run-script.mjs priority:release:published:bundle`
+ and confirm the published `CompareVI.Tools` bundle carries
+ `consumerContract.capabilities.dockerProfile`.
- [ ] Re-run the LabVIEW CLI wrapper path to ensure rogue detection and cleanup
guard stay green.
## 10. Communication
-- [ ] Announce the RC cut, calling out the hosted-first release conductor,
- template dependency, and continuity hardening.
-- [ ] Remind consumers that the final pivot to `LabviewGitHubCiTemplate`
- remains gated on an RC release summary and a future agent handoff.
+- [ ] Announce the RC cut, calling out the published producer-owned Docker
+ contract and the template dependency it unlocks.
+- [ ] Remind consumers that `LabviewGitHubCiTemplate#20` only starts after the
+ published bundle proves the producer contract authoritatively.
---- Updated: 2026-03-22 (revamped for the `v0.6.4-rc.1` release cycle).
+--- Updated: 2026-03-24 (revamped for the `v0.6.4-rc.2` release cycle).
diff --git a/docs/schema/generated/teststand-compare-session.schema.json b/docs/schema/generated/teststand-compare-session.schema.json
index 82d5ae3ba..c1521ace5 100644
--- a/docs/schema/generated/teststand-compare-session.schema.json
+++ b/docs/schema/generated/teststand-compare-session.schema.json
@@ -6,7 +6,10 @@
"properties": {
"schema": {
"type": "string",
- "const": "teststand-compare-session/v1"
+ "enum": [
+ "teststand-compare-session/v1",
+ "teststand-compare-session/v2"
+ ]
},
"at": {
"type": "string",
@@ -151,6 +154,33 @@
},
"additionalProperties": false
},
+ "staging": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "root": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "required": [
+ "enabled",
+ "root"
+ ],
+ "additionalProperties": false
+ },
+ "allowSameLeaf": {
+ "type": "boolean"
+ },
"policy": {
"type": "string",
"enum": [
@@ -220,6 +250,507 @@
"type": "null"
}
]
+ },
+ "executionCell": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "cellId": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "leaseId": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "leasePath": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "agentId": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "agentClass": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": [
+ "sagan",
+ "subagent",
+ "other"
+ ]
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "cellClass": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": [
+ "worker",
+ "coordinator",
+ "kernel-coordinator"
+ ]
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "suiteClass": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": [
+ "single-compare",
+ "dual-plane-parity"
+ ]
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "planeBinding": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "runtimeSurface": {
+ "anyOf": [
+ {
+ "type": "string",
+ "const": "windows-native-teststand"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "premiumSaganMode": {
+ "type": "boolean"
+ },
+ "operatorAuthorizationRef": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "workingRoot": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "artifactRoot": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "isolatedLaneGroupId": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "hostOsFingerprintSha256": {
+ "anyOf": [
+ {
+ "type": "string",
+ "pattern": "^[A-Fa-f0-9]{64}$"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "harnessInstance": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "harnessKind": {
+ "type": "string",
+ "minLength": 1
+ },
+ "instanceId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "role": {
+ "type": "string",
+ "enum": [
+ "single-plane",
+ "coordinator",
+ "plane-child"
+ ]
+ },
+ "processModelClass": {
+ "type": "string",
+ "enum": [
+ "sequential-process-model",
+ "parallel-process-model"
+ ]
+ },
+ "planeBinding": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "parentInstanceId": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "required": [
+ "harnessKind",
+ "instanceId",
+ "role",
+ "processModelClass"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "processModel": {
+ "type": "object",
+ "properties": {
+ "runtimeSurface": {
+ "type": "string",
+ "const": "windows-native-teststand"
+ },
+ "processModelClass": {
+ "type": "string",
+ "enum": [
+ "sequential-process-model",
+ "parallel-process-model"
+ ]
+ },
+ "windowsOnly": {
+ "type": "boolean",
+ "const": true
+ },
+ "rootHarnessInstanceId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "planeCount": {
+ "type": "integer",
+ "minimum": 1
+ }
+ },
+ "required": [
+ "runtimeSurface",
+ "processModelClass",
+ "windowsOnly",
+ "rootHarnessInstanceId",
+ "planeCount"
+ ],
+ "additionalProperties": false
+ },
+ "suiteClass": {
+ "type": "string",
+ "enum": [
+ "single-compare",
+ "dual-plane-parity"
+ ]
+ },
+ "primaryPlane": {
+ "type": "string",
+ "minLength": 1
+ },
+ "requestedSimultaneous": {
+ "type": "boolean"
+ },
+ "planes": {
+ "type": "object",
+ "properties": {
+ "x64": {
+ "type": "object",
+ "properties": {
+ "plane": {
+ "type": "string",
+ "minLength": 1
+ },
+ "architecture": {
+ "type": "string",
+ "enum": [
+ "32-bit",
+ "64-bit"
+ ]
+ },
+ "labviewExePath": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "outputRoot": {
+ "type": "string",
+ "minLength": 1
+ },
+ "warmup": {
+ "type": "object",
+ "properties": {
+ "mode": {
+ "$ref": "#/definitions/teststand-compare-session/properties/warmup/properties/mode"
+ },
+ "events": {
+ "$ref": "#/definitions/teststand-compare-session/properties/warmup/properties/events"
+ }
+ },
+ "required": [
+ "mode",
+ "events"
+ ],
+ "additionalProperties": false
+ },
+ "compare": {
+ "$ref": "#/definitions/teststand-compare-session/properties/compare"
+ },
+ "outcome": {
+ "$ref": "#/definitions/teststand-compare-session/properties/outcome"
+ },
+ "error": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "exitCode": {
+ "type": "number"
+ },
+ "executionCell": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/teststand-compare-session/properties/executionCell/anyOf/0"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "harnessInstance": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/teststand-compare-session/properties/harnessInstance/anyOf/0"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "processModel": {
+ "$ref": "#/definitions/teststand-compare-session/properties/processModel"
+ }
+ },
+ "required": [
+ "plane",
+ "architecture",
+ "outputRoot",
+ "warmup",
+ "compare",
+ "outcome",
+ "exitCode"
+ ],
+ "additionalProperties": false
+ },
+ "x32": {
+ "$ref": "#/definitions/teststand-compare-session/properties/planes/properties/x64"
+ }
+ },
+ "required": [
+ "x64",
+ "x32"
+ ],
+ "additionalProperties": false
+ },
+ "parity": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "match",
+ "mismatch",
+ "incomplete"
+ ]
+ },
+ "comparedFields": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ },
+ "exitCodeParity": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "diffParity": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "mismatchCount": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "mismatches": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "field": {
+ "type": "string",
+ "minLength": 1
+ },
+ "x64": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "x32": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "required": [
+ "field"
+ ],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": [
+ "status",
+ "comparedFields",
+ "mismatchCount",
+ "mismatches"
+ ],
+ "additionalProperties": false
}
},
"required": [
diff --git a/docs/schemas/autonomous-governor-portfolio-summary-report-v1.schema.json b/docs/schemas/autonomous-governor-portfolio-summary-report-v1.schema.json
index 7edff0fb2..4b2370c87 100644
--- a/docs/schemas/autonomous-governor-portfolio-summary-report-v1.schema.json
+++ b/docs/schemas/autonomous-governor-portfolio-summary-report-v1.schema.json
@@ -51,7 +51,13 @@
"queueHandoffStatus",
"queueHandoffNextWakeCondition",
"queueHandoffPrUrl",
- "queueAuthoritySource"
+ "queueAuthoritySource",
+ "executionTopology",
+ "executionBundleStatus",
+ "executionBundlePlaneBinding",
+ "executionBundlePremiumSaganMode",
+ "executionBundleReciprocalLinkReady",
+ "executionBundleEffectiveBillableRateUsdPerHour"
],
"properties": {
"repository": { "type": ["string", "null"] },
@@ -64,13 +70,19 @@
"queueHandoffStatus": { "type": ["string", "null"] },
"queueHandoffNextWakeCondition": { "type": ["string", "null"] },
"queueHandoffPrUrl": { "type": ["string", "null"] },
- "queueAuthoritySource": { "type": ["string", "null"] }
+ "queueAuthoritySource": { "type": ["string", "null"] },
+ "executionTopology": { "$ref": "#/$defs/executionTopology" },
+ "executionBundleStatus": { "type": ["string", "null"] },
+ "executionBundlePlaneBinding": { "type": ["string", "null"] },
+ "executionBundlePremiumSaganMode": { "type": "boolean" },
+ "executionBundleReciprocalLinkReady": { "type": "boolean" },
+ "executionBundleEffectiveBillableRateUsdPerHour": { "type": ["number", "null"], "minimum": 0 }
}
},
"portfolio": {
"type": "object",
"additionalProperties": false,
- "required": ["repositoryCount", "repositories", "unsupportedPaths"],
+ "required": ["repositoryCount", "repositories", "dependencies", "unsupportedPaths"],
"properties": {
"repositoryCount": {
"type": "integer",
@@ -175,6 +187,49 @@
}
}
},
+ "dependencies": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "status",
+ "ownerRepository",
+ "dependentRepository",
+ "requiredCapability",
+ "source",
+ "releaseSigningStatus",
+ "releasePublicationState",
+ "publishedBundleState",
+ "publishedBundleReleaseTag",
+ "publishedBundleAuthoritativeConsumerPin",
+ "signingCapabilityState",
+ "signingAuthorityState",
+ "releaseConductorApplyState",
+ "externalBlocker",
+ "detail"
+ ],
+ "properties": {
+ "id": { "type": "string" },
+ "status": { "type": "string", "enum": ["ready", "blocked", "unknown"] },
+ "ownerRepository": { "type": ["string", "null"] },
+ "dependentRepository": { "type": ["string", "null"] },
+ "requiredCapability": { "type": "string" },
+ "source": { "type": "string" },
+ "releaseSigningStatus": { "type": ["string", "null"] },
+ "releasePublicationState": { "type": ["string", "null"] },
+ "publishedBundleState": { "type": ["string", "null"] },
+ "publishedBundleReleaseTag": { "type": ["string", "null"] },
+ "publishedBundleAuthoritativeConsumerPin": { "type": ["string", "null"] },
+ "signingCapabilityState": { "type": ["string", "null"] },
+ "signingAuthorityState": { "type": ["string", "null"] },
+ "releaseConductorApplyState": { "type": ["string", "null"] },
+ "externalBlocker": { "type": ["string", "null"] },
+ "detail": { "type": "string" }
+ }
+ }
+ },
"unsupportedPaths": {
"type": "array",
"items": {
@@ -207,6 +262,33 @@
"queueHandoffNextWakeCondition",
"queueHandoffPrUrl",
"queueAuthoritySource",
+ "executionTopologyStatus",
+ "executionTopologyExecutionPlane",
+ "executionTopologyProviderId",
+ "executionTopologyWorkerSlotId",
+ "executionTopologyActiveLogicalLaneCount",
+ "executionTopologySeededLogicalLaneCount",
+ "executionTopologyRuntimeSurface",
+ "executionTopologyProcessModelClass",
+ "executionTopologyWindowsOnly",
+ "executionTopologyRequestedSimultaneous",
+ "executionTopologyCellClass",
+ "executionTopologySuiteClass",
+ "executionTopologyOperatorAuthorizationRef",
+ "executionBundleStatus",
+ "executionBundlePlaneBinding",
+ "executionBundlePremiumSaganMode",
+ "executionBundleReciprocalLinkReady",
+ "executionBundleEffectiveBillableRateUsdPerHour",
+ "viHistoryDistributorDependencyStatus",
+ "viHistoryDistributorDependencyTargetRepository",
+ "viHistoryDistributorDependencyExternalBlocker",
+ "viHistoryDistributorDependencyPublicationState",
+ "viHistoryDistributorDependencyPublishedBundleState",
+ "viHistoryDistributorDependencyPublishedBundleReleaseTag",
+ "viHistoryDistributorDependencyAuthoritativeConsumerPin",
+ "viHistoryDistributorDependencySigningAuthorityState",
+ "viHistoryDistributorDependencyReleaseConductorApplyState",
"portfolioWakeConditionCount",
"triggeredWakeConditions"
],
@@ -227,6 +309,33 @@
"queueHandoffNextWakeCondition": { "type": ["string", "null"] },
"queueHandoffPrUrl": { "type": ["string", "null"] },
"queueAuthoritySource": { "type": ["string", "null"] },
+ "executionTopologyStatus": { "type": ["string", "null"] },
+ "executionTopologyExecutionPlane": { "type": ["string", "null"] },
+ "executionTopologyProviderId": { "type": ["string", "null"] },
+ "executionTopologyWorkerSlotId": { "type": ["string", "null"] },
+ "executionTopologyActiveLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "executionTopologySeededLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "executionTopologyRuntimeSurface": { "type": ["string", "null"] },
+ "executionTopologyProcessModelClass": { "type": ["string", "null"] },
+ "executionTopologyWindowsOnly": { "type": "boolean" },
+ "executionTopologyRequestedSimultaneous": { "type": "boolean" },
+ "executionTopologyCellClass": { "type": ["string", "null"] },
+ "executionTopologySuiteClass": { "type": ["string", "null"] },
+ "executionTopologyOperatorAuthorizationRef": { "type": ["string", "null"] },
+ "executionBundleStatus": { "type": ["string", "null"] },
+ "executionBundlePlaneBinding": { "type": ["string", "null"] },
+ "executionBundlePremiumSaganMode": { "type": "boolean" },
+ "executionBundleReciprocalLinkReady": { "type": "boolean" },
+ "executionBundleEffectiveBillableRateUsdPerHour": { "type": ["number", "null"], "minimum": 0 },
+ "viHistoryDistributorDependencyStatus": { "type": "string", "enum": ["ready", "blocked", "unknown"] },
+ "viHistoryDistributorDependencyTargetRepository": { "type": ["string", "null"] },
+ "viHistoryDistributorDependencyExternalBlocker": { "type": ["string", "null"] },
+ "viHistoryDistributorDependencyPublicationState": { "type": ["string", "null"] },
+ "viHistoryDistributorDependencyPublishedBundleState": { "type": ["string", "null"] },
+ "viHistoryDistributorDependencyPublishedBundleReleaseTag": { "type": ["string", "null"] },
+ "viHistoryDistributorDependencyAuthoritativeConsumerPin": { "type": ["string", "null"] },
+ "viHistoryDistributorDependencySigningAuthorityState": { "type": ["string", "null"] },
+ "viHistoryDistributorDependencyReleaseConductorApplyState": { "type": ["string", "null"] },
"portfolioWakeConditionCount": { "type": "integer", "minimum": 0 },
"triggeredWakeConditions": {
"type": "array",
@@ -234,5 +343,131 @@
}
}
}
+ },
+ "$defs": {
+ "executionBundle": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "planeBinding",
+ "cellClass",
+ "suiteClass",
+ "premiumSaganMode",
+ "reciprocalLinkReady",
+ "effectiveBillableRateUsdPerHour",
+ "executionCellLeaseId",
+ "dockerLaneLeaseId",
+ "harnessKind",
+ "harnessInstanceId",
+ "operatorAuthorizationRef",
+ "cellId",
+ "laneId",
+ "isolatedLaneGroupId",
+ "fingerprintSha256"
+ ],
+ "properties": {
+ "status": { "type": ["string", "null"] },
+ "planeBinding": { "type": ["string", "null"] },
+ "cellClass": { "type": ["string", "null"] },
+ "suiteClass": { "type": ["string", "null"] },
+ "premiumSaganMode": { "type": "boolean" },
+ "reciprocalLinkReady": { "type": "boolean" },
+ "effectiveBillableRateUsdPerHour": { "type": ["number", "null"], "minimum": 0 },
+ "executionCellLeaseId": { "type": ["string", "null"] },
+ "dockerLaneLeaseId": { "type": ["string", "null"] },
+ "harnessKind": { "type": ["string", "null"] },
+ "harnessInstanceId": { "type": ["string", "null"] },
+ "operatorAuthorizationRef": { "type": ["string", "null"] },
+ "cellId": { "type": ["string", "null"] },
+ "laneId": { "type": ["string", "null"] },
+ "isolatedLaneGroupId": { "type": ["string", "null"] },
+ "fingerprintSha256": { "type": ["string", "null"] }
+ }
+ },
+ "executionTopologyLogicalLaneActivation": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["activeLaneCount", "seededLaneCount", "catalogCount"],
+ "properties": {
+ "activeLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "seededLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "catalogCount": { "type": "integer", "minimum": 0 }
+ }
+ },
+ "executionTopologyProviderDispatch": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "providerId",
+ "providerKind",
+ "executionPlane",
+ "assignmentMode",
+ "dispatchSurface",
+ "completionMode",
+ "workerSlotId",
+ "dispatchStatus",
+ "completionStatus",
+ "failureClass"
+ ],
+ "properties": {
+ "providerId": { "type": ["string", "null"] },
+ "providerKind": { "type": ["string", "null"] },
+ "executionPlane": { "type": ["string", "null"] },
+ "assignmentMode": { "type": ["string", "null"] },
+ "dispatchSurface": { "type": ["string", "null"] },
+ "completionMode": { "type": ["string", "null"] },
+ "workerSlotId": { "type": ["string", "null"] },
+ "dispatchStatus": { "type": ["string", "null"] },
+ "completionStatus": { "type": ["string", "null"] },
+ "failureClass": { "type": ["string", "null"] }
+ }
+ },
+ "executionTopology": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "executionPlane",
+ "providerId",
+ "workerSlotId",
+ "activeLogicalLaneCount",
+ "seededLogicalLaneCount",
+ "catalogCount",
+ "runtimeSurface",
+ "processModelClass",
+ "windowsOnly",
+ "requestedSimultaneous",
+ "cellClass",
+ "suiteClass",
+ "operatorAuthorizationRef",
+ "premiumSaganMode",
+ "reciprocalLinkReady",
+ "logicalLaneActivation",
+ "providerDispatch",
+ "executionBundle"
+ ],
+ "properties": {
+ "status": { "type": ["string", "null"] },
+ "executionPlane": { "type": ["string", "null"] },
+ "providerId": { "type": ["string", "null"] },
+ "workerSlotId": { "type": ["string", "null"] },
+ "activeLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "seededLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "catalogCount": { "type": "integer", "minimum": 0 },
+ "runtimeSurface": { "type": ["string", "null"] },
+ "processModelClass": { "type": ["string", "null"] },
+ "windowsOnly": { "type": "boolean" },
+ "requestedSimultaneous": { "type": "boolean" },
+ "cellClass": { "type": ["string", "null"] },
+ "suiteClass": { "type": ["string", "null"] },
+ "operatorAuthorizationRef": { "type": ["string", "null"] },
+ "premiumSaganMode": { "type": "boolean" },
+ "reciprocalLinkReady": { "type": "boolean" },
+ "logicalLaneActivation": { "$ref": "#/$defs/executionTopologyLogicalLaneActivation" },
+ "providerDispatch": { "$ref": "#/$defs/executionTopologyProviderDispatch" },
+ "executionBundle": { "$ref": "#/$defs/executionBundle" }
+ }
+ }
}
}
diff --git a/docs/schemas/autonomous-governor-summary-report-v1.schema.json b/docs/schemas/autonomous-governor-summary-report-v1.schema.json
index 6e57c5c4e..31bd61c34 100644
--- a/docs/schemas/autonomous-governor-summary-report-v1.schema.json
+++ b/docs/schemas/autonomous-governor-summary-report-v1.schema.json
@@ -37,7 +37,8 @@
"monitoringModePath",
"wakeLifecyclePath",
"wakeInvestmentAccountingPath",
- "deliveryRuntimeStatePath"
+ "deliveryRuntimeStatePath",
+ "releaseSigningReadinessPath"
],
"properties": {
"queueEmptyReportPath": { "type": "string", "minLength": 1 },
@@ -45,7 +46,8 @@
"monitoringModePath": { "type": "string", "minLength": 1 },
"wakeLifecyclePath": { "type": "string", "minLength": 1 },
"wakeInvestmentAccountingPath": { "type": "string", "minLength": 1 },
- "deliveryRuntimeStatePath": { "type": "string", "minLength": 1 }
+ "deliveryRuntimeStatePath": { "type": "string", "minLength": 1 },
+ "releaseSigningReadinessPath": { "type": "string", "minLength": 1 }
}
},
"compare": {
@@ -55,6 +57,7 @@
"queueState",
"continuity",
"monitoringMode",
+ "releaseSigningReadiness",
"deliveryRuntime",
"queueAuthority"
],
@@ -62,6 +65,7 @@
"queueState": { "$ref": "#/$defs/queueState" },
"continuity": { "$ref": "#/$defs/continuity" },
"monitoringMode": { "$ref": "#/$defs/monitoringMode" },
+ "releaseSigningReadiness": { "$ref": "#/$defs/releaseSigningReadiness" },
"deliveryRuntime": { "$ref": "#/$defs/deliveryRuntime" },
"queueAuthority": { "$ref": "#/$defs/queueAuthority" }
}
@@ -134,6 +138,8 @@
"outcome",
"blockerClass",
"nextWakeCondition",
+ "executionTopology",
+ "executionBundle",
"queueAuthorityRefresh",
"prUrl",
"issueNumber",
@@ -157,12 +163,52 @@
"outcome": { "type": ["string", "null"] },
"blockerClass": { "type": ["string", "null"] },
"nextWakeCondition": { "type": ["string", "null"] },
+ "executionTopology": { "$ref": "#/$defs/executionTopology" },
+ "executionBundle": { "$ref": "#/$defs/executionBundle" },
"queueAuthorityRefresh": { "$ref": "#/$defs/queueAuthorityRefresh" },
"prUrl": { "type": ["string", "null"] },
"issueNumber": { "type": ["integer", "null"], "minimum": 1 },
"reason": { "type": ["string", "null"] }
}
},
+ "releaseSigningReadiness": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "codePathState",
+ "signingCapabilityState",
+ "signingAuthorityState",
+ "releaseConductorApplyState",
+ "publicationState",
+ "publishedBundleState",
+ "publishedBundleReleaseTag",
+ "publishedBundleAuthoritativeConsumerPin",
+ "externalBlocker",
+ "blockerCount"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "pass",
+ "warn",
+ "fail",
+ "missing"
+ ]
+ },
+ "codePathState": { "type": ["string", "null"] },
+ "signingCapabilityState": { "type": ["string", "null"] },
+ "signingAuthorityState": { "type": ["string", "null"] },
+ "releaseConductorApplyState": { "type": ["string", "null"] },
+ "publicationState": { "type": ["string", "null"] },
+ "publishedBundleState": { "type": ["string", "null"] },
+ "publishedBundleReleaseTag": { "type": ["string", "null"] },
+ "publishedBundleAuthoritativeConsumerPin": { "type": ["string", "null"] },
+ "externalBlocker": { "type": ["string", "null"] },
+ "blockerCount": { "type": "integer", "minimum": 0 }
+ }
+ },
"queueAuthority": {
"type": "object",
"additionalProperties": false,
@@ -281,6 +327,32 @@
"wakeTerminalState",
"monitoringStatus",
"futureAgentAction",
+ "releaseSigningStatus",
+ "releaseSigningAuthorityState",
+ "releaseConductorApplyState",
+ "releaseSigningExternalBlocker",
+ "releasePublicationState",
+ "releasePublishedBundleState",
+ "releasePublishedBundleReleaseTag",
+ "releasePublishedBundleAuthoritativeConsumerPin",
+ "executionTopologyStatus",
+ "executionTopologyExecutionPlane",
+ "executionTopologyProviderId",
+ "executionTopologyWorkerSlotId",
+ "executionTopologyActiveLogicalLaneCount",
+ "executionTopologySeededLogicalLaneCount",
+ "executionTopologyRuntimeSurface",
+ "executionTopologyProcessModelClass",
+ "executionTopologyWindowsOnly",
+ "executionTopologyRequestedSimultaneous",
+ "executionTopologyCellClass",
+ "executionTopologySuiteClass",
+ "executionTopologyOperatorAuthorizationRef",
+ "executionBundleStatus",
+ "executionBundlePlaneBinding",
+ "executionBundlePremiumSaganMode",
+ "executionBundleReciprocalLinkReady",
+ "executionBundleEffectiveBillableRateUsdPerHour",
"queueHandoffStatus",
"queueHandoffNextWakeCondition",
"queueHandoffPrUrl",
@@ -320,6 +392,40 @@
"wakeTerminalState": { "type": ["string", "null"] },
"monitoringStatus": { "type": ["string", "null"] },
"futureAgentAction": { "type": ["string", "null"] },
+ "releaseSigningStatus": {
+ "type": "string",
+ "enum": [
+ "pass",
+ "warn",
+ "fail",
+ "missing"
+ ]
+ },
+ "releaseSigningAuthorityState": { "type": ["string", "null"] },
+ "releaseConductorApplyState": { "type": ["string", "null"] },
+ "releaseSigningExternalBlocker": { "type": ["string", "null"] },
+ "releasePublicationState": { "type": ["string", "null"] },
+ "releasePublishedBundleState": { "type": ["string", "null"] },
+ "releasePublishedBundleReleaseTag": { "type": ["string", "null"] },
+ "releasePublishedBundleAuthoritativeConsumerPin": { "type": ["string", "null"] },
+ "executionTopologyStatus": { "type": ["string", "null"] },
+ "executionTopologyExecutionPlane": { "type": ["string", "null"] },
+ "executionTopologyProviderId": { "type": ["string", "null"] },
+ "executionTopologyWorkerSlotId": { "type": ["string", "null"] },
+ "executionTopologyActiveLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "executionTopologySeededLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "executionTopologyRuntimeSurface": { "type": ["string", "null"] },
+ "executionTopologyProcessModelClass": { "type": ["string", "null"] },
+ "executionTopologyWindowsOnly": { "type": "boolean" },
+ "executionTopologyRequestedSimultaneous": { "type": "boolean" },
+ "executionTopologyCellClass": { "type": ["string", "null"] },
+ "executionTopologySuiteClass": { "type": ["string", "null"] },
+ "executionTopologyOperatorAuthorizationRef": { "type": ["string", "null"] },
+ "executionBundleStatus": { "type": ["string", "null"] },
+ "executionBundlePlaneBinding": { "type": ["string", "null"] },
+ "executionBundlePremiumSaganMode": { "type": "boolean" },
+ "executionBundleReciprocalLinkReady": { "type": "boolean" },
+ "executionBundleEffectiveBillableRateUsdPerHour": { "type": ["number", "null"], "minimum": 0 },
"queueHandoffStatus": {
"type": "string",
"enum": [
@@ -382,6 +488,130 @@
"autoMergeEnabled": { "type": ["boolean", "null"] },
"mergedAt": { "type": ["string", "null"] }
}
+ },
+ "executionBundle": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "planeBinding",
+ "cellClass",
+ "suiteClass",
+ "premiumSaganMode",
+ "reciprocalLinkReady",
+ "effectiveBillableRateUsdPerHour",
+ "executionCellLeaseId",
+ "dockerLaneLeaseId",
+ "harnessKind",
+ "harnessInstanceId",
+ "operatorAuthorizationRef",
+ "cellId",
+ "laneId",
+ "isolatedLaneGroupId",
+ "fingerprintSha256"
+ ],
+ "properties": {
+ "status": { "type": ["string", "null"] },
+ "planeBinding": { "type": ["string", "null"] },
+ "cellClass": { "type": ["string", "null"] },
+ "suiteClass": { "type": ["string", "null"] },
+ "premiumSaganMode": { "type": "boolean" },
+ "reciprocalLinkReady": { "type": "boolean" },
+ "effectiveBillableRateUsdPerHour": { "type": ["number", "null"], "minimum": 0 },
+ "executionCellLeaseId": { "type": ["string", "null"] },
+ "dockerLaneLeaseId": { "type": ["string", "null"] },
+ "harnessKind": { "type": ["string", "null"] },
+ "harnessInstanceId": { "type": ["string", "null"] },
+ "operatorAuthorizationRef": { "type": ["string", "null"] },
+ "cellId": { "type": ["string", "null"] },
+ "laneId": { "type": ["string", "null"] },
+ "isolatedLaneGroupId": { "type": ["string", "null"] },
+ "fingerprintSha256": { "type": ["string", "null"] }
+ }
+ },
+ "executionTopologyLogicalLaneActivation": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["activeLaneCount", "seededLaneCount", "catalogCount"],
+ "properties": {
+ "activeLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "seededLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "catalogCount": { "type": "integer", "minimum": 0 }
+ }
+ },
+ "executionTopologyProviderDispatch": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "providerId",
+ "providerKind",
+ "executionPlane",
+ "assignmentMode",
+ "dispatchSurface",
+ "completionMode",
+ "workerSlotId",
+ "dispatchStatus",
+ "completionStatus",
+ "failureClass"
+ ],
+ "properties": {
+ "providerId": { "type": ["string", "null"] },
+ "providerKind": { "type": ["string", "null"] },
+ "executionPlane": { "type": ["string", "null"] },
+ "assignmentMode": { "type": ["string", "null"] },
+ "dispatchSurface": { "type": ["string", "null"] },
+ "completionMode": { "type": ["string", "null"] },
+ "workerSlotId": { "type": ["string", "null"] },
+ "dispatchStatus": { "type": ["string", "null"] },
+ "completionStatus": { "type": ["string", "null"] },
+ "failureClass": { "type": ["string", "null"] }
+ }
+ },
+ "executionTopology": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "executionPlane",
+ "providerId",
+ "workerSlotId",
+ "activeLogicalLaneCount",
+ "seededLogicalLaneCount",
+ "catalogCount",
+ "runtimeSurface",
+ "processModelClass",
+ "windowsOnly",
+ "requestedSimultaneous",
+ "cellClass",
+ "suiteClass",
+ "operatorAuthorizationRef",
+ "premiumSaganMode",
+ "reciprocalLinkReady",
+ "logicalLaneActivation",
+ "providerDispatch",
+ "executionBundle"
+ ],
+ "properties": {
+ "status": { "type": ["string", "null"] },
+ "executionPlane": { "type": ["string", "null"] },
+ "providerId": { "type": ["string", "null"] },
+ "workerSlotId": { "type": ["string", "null"] },
+ "activeLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "seededLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "catalogCount": { "type": "integer", "minimum": 0 },
+ "runtimeSurface": { "type": ["string", "null"] },
+ "processModelClass": { "type": ["string", "null"] },
+ "windowsOnly": { "type": "boolean" },
+ "requestedSimultaneous": { "type": "boolean" },
+ "cellClass": { "type": ["string", "null"] },
+ "suiteClass": { "type": ["string", "null"] },
+ "operatorAuthorizationRef": { "type": ["string", "null"] },
+ "premiumSaganMode": { "type": "boolean" },
+ "reciprocalLinkReady": { "type": "boolean" },
+ "logicalLaneActivation": { "$ref": "#/$defs/executionTopologyLogicalLaneActivation" },
+ "providerDispatch": { "$ref": "#/$defs/executionTopologyProviderDispatch" },
+ "executionBundle": { "$ref": "#/$defs/executionBundle" }
+ }
}
}
}
diff --git a/docs/schemas/comparevi-tools-docker-image-contract-v1.schema.json b/docs/schemas/comparevi-tools-docker-image-contract-v1.schema.json
new file mode 100644
index 000000000..d8fe8cd87
--- /dev/null
+++ b/docs/schemas/comparevi-tools-docker-image-contract-v1.schema.json
@@ -0,0 +1,62 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://labview-community-ci-cd.github.io/compare-vi-cli-action/schemas/comparevi-tools-docker-image-contract-v1.schema.json",
+ "title": "CompareVI.Tools Docker Image Contract v1",
+ "type": "object",
+ "required": [
+ "schema",
+ "schemaUrl",
+ "images",
+ "notes"
+ ],
+ "properties": {
+ "schema": {
+ "const": "comparevi-tools/docker-image-contract@v1"
+ },
+ "schemaUrl": {
+ "type": "string"
+ },
+ "images": {
+ "type": "object",
+ "required": [
+ "hostedNiLinuxRunner"
+ ],
+ "properties": {
+ "hostedNiLinuxRunner": {
+ "type": "object",
+ "required": [
+ "imageRef",
+ "consumerRole",
+ "notes"
+ ],
+ "properties": {
+ "imageRef": {
+ "type": "string"
+ },
+ "consumerRole": {
+ "type": "string",
+ "enum": [
+ "hosted-ni-linux-runner"
+ ]
+ },
+ "notes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "notes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/docs/schemas/comparevi-tools-docker-profile-capability-v1.schema.json b/docs/schemas/comparevi-tools-docker-profile-capability-v1.schema.json
new file mode 100644
index 000000000..568ed87be
--- /dev/null
+++ b/docs/schemas/comparevi-tools-docker-profile-capability-v1.schema.json
@@ -0,0 +1,68 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://labview-community-ci-cd.github.io/compare-vi-cli-action/schemas/comparevi-tools-docker-profile-capability-v1.schema.json",
+ "title": "CompareVI.Tools Docker Profile Capability v1",
+ "type": "object",
+ "required": [
+ "schema",
+ "capabilityId",
+ "displayName",
+ "distributionRole",
+ "distributionModel",
+ "bundleMetadataPath",
+ "bundleImportPath",
+ "releaseAssetPattern",
+ "authoritativeConsumerPinFieldPath",
+ "authoritativeConsumerPinKindFieldPath",
+ "authoritativeImageContractSource",
+ "notes"
+ ],
+ "properties": {
+ "schema": {
+ "const": "comparevi-tools/docker-profile-capability@v1"
+ },
+ "capabilityId": {
+ "const": "docker-profile"
+ },
+ "displayName": {
+ "type": "string"
+ },
+ "distributionRole": {
+ "type": "string",
+ "enum": [
+ "upstream-producer"
+ ]
+ },
+ "distributionModel": {
+ "type": "string",
+ "enum": [
+ "release-bundle"
+ ]
+ },
+ "bundleMetadataPath": {
+ "type": "string"
+ },
+ "bundleImportPath": {
+ "type": "string"
+ },
+ "releaseAssetPattern": {
+ "type": "string"
+ },
+ "authoritativeConsumerPinFieldPath": {
+ "type": "string"
+ },
+ "authoritativeConsumerPinKindFieldPath": {
+ "type": "string"
+ },
+ "authoritativeImageContractSource": {
+ "type": "string"
+ },
+ "notes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/docs/schemas/comparevi-tools-release-manifest-v1.schema.json b/docs/schemas/comparevi-tools-release-manifest-v1.schema.json
index a990c87dd..8d8c5459b 100644
--- a/docs/schemas/comparevi-tools-release-manifest-v1.schema.json
+++ b/docs/schemas/comparevi-tools-release-manifest-v1.schema.json
@@ -178,7 +178,8 @@
"capabilities": {
"type": "object",
"required": [
- "viHistory"
+ "viHistory",
+ "dockerProfile"
],
"properties": {
"viHistory": {
@@ -270,6 +271,71 @@
}
},
"additionalProperties": false
+ },
+ "dockerProfile": {
+ "type": "object",
+ "required": [
+ "schema",
+ "capabilityId",
+ "displayName",
+ "distributionRole",
+ "distributionModel",
+ "bundleMetadataPath",
+ "bundleImportPath",
+ "releaseAssetPattern",
+ "authoritativeConsumerPinFieldPath",
+ "authoritativeConsumerPinKindFieldPath",
+ "authoritativeImageContractSource",
+ "notes"
+ ],
+ "properties": {
+ "schema": {
+ "const": "comparevi-tools/docker-profile-capability@v1"
+ },
+ "capabilityId": {
+ "const": "docker-profile"
+ },
+ "displayName": {
+ "type": "string"
+ },
+ "distributionRole": {
+ "type": "string",
+ "enum": [
+ "upstream-producer"
+ ]
+ },
+ "distributionModel": {
+ "type": "string",
+ "enum": [
+ "release-bundle"
+ ]
+ },
+ "bundleMetadataPath": {
+ "type": "string"
+ },
+ "bundleImportPath": {
+ "type": "string"
+ },
+ "releaseAssetPattern": {
+ "type": "string"
+ },
+ "authoritativeConsumerPinFieldPath": {
+ "type": "string"
+ },
+ "authoritativeConsumerPinKindFieldPath": {
+ "type": "string"
+ },
+ "authoritativeImageContractSource": {
+ "type": "string"
+ },
+ "notes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
}
},
"additionalProperties": false
@@ -473,6 +539,65 @@
}
},
"additionalProperties": false
+ },
+ "dockerImageContract": {
+ "type": "object",
+ "required": [
+ "schema",
+ "schemaUrl",
+ "images",
+ "notes"
+ ],
+ "properties": {
+ "schema": {
+ "const": "comparevi-tools/docker-image-contract@v1"
+ },
+ "schemaUrl": {
+ "type": "string"
+ },
+ "images": {
+ "type": "object",
+ "required": [
+ "hostedNiLinuxRunner"
+ ],
+ "properties": {
+ "hostedNiLinuxRunner": {
+ "type": "object",
+ "required": [
+ "imageRef",
+ "consumerRole",
+ "notes"
+ ],
+ "properties": {
+ "imageRef": {
+ "type": "string"
+ },
+ "consumerRole": {
+ "type": "string",
+ "enum": [
+ "hosted-ni-linux-runner"
+ ]
+ },
+ "notes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "notes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
}
},
"additionalProperties": false
diff --git a/docs/schemas/concurrent-lane-status-receipt-v1.schema.json b/docs/schemas/concurrent-lane-status-receipt-v1.schema.json
index 57bd571fd..d34158a6c 100644
--- a/docs/schemas/concurrent-lane-status-receipt-v1.schema.json
+++ b/docs/schemas/concurrent-lane-status-receipt-v1.schema.json
@@ -246,6 +246,50 @@
}
}
},
+ "executionBundle": {
+ "type": ["object", "null"],
+ "additionalProperties": false,
+ "required": [
+ "path",
+ "schema",
+ "status",
+ "cellId",
+ "laneId",
+ "cellClass",
+ "suiteClass",
+ "executionCellLeaseId",
+ "dockerLaneLeaseId",
+ "harnessKind",
+ "harnessInstanceId",
+ "planeBinding",
+ "premiumSaganMode",
+ "reciprocalLinkReady",
+ "effectiveBillableRateUsdPerHour",
+ "operatorAuthorizationRef",
+ "isolatedLaneGroupId",
+ "fingerprintSha256"
+ ],
+ "properties": {
+ "path": { "type": ["string", "null"] },
+ "schema": { "type": ["string", "null"] },
+ "status": { "type": ["string", "null"] },
+ "cellId": { "type": ["string", "null"] },
+ "laneId": { "type": ["string", "null"] },
+ "cellClass": { "type": ["string", "null"] },
+ "suiteClass": { "type": ["string", "null"] },
+ "executionCellLeaseId": { "type": ["string", "null"] },
+ "dockerLaneLeaseId": { "type": ["string", "null"] },
+ "harnessKind": { "type": ["string", "null"] },
+ "harnessInstanceId": { "type": ["string", "null"] },
+ "planeBinding": { "type": ["string", "null"] },
+ "premiumSaganMode": { "type": "boolean" },
+ "reciprocalLinkReady": { "type": "boolean" },
+ "effectiveBillableRateUsdPerHour": { "type": ["number", "null"] },
+ "operatorAuthorizationRef": { "type": ["string", "null"] },
+ "isolatedLaneGroupId": { "type": ["string", "null"] },
+ "fingerprintSha256": { "type": ["string", "null"] }
+ }
+ },
"laneStatuses": {
"type": "array",
"items": {
@@ -352,6 +396,9 @@
"deferredLaneCount",
"manualLaneCount",
"shadowLaneCount",
+ "executionBundleStatus",
+ "executionBundleReciprocalLinkReady",
+ "executionBundlePremiumSaganMode",
"idleClassificationCoverage",
"pullRequestStatus",
"orchestratorDisposition"
@@ -396,6 +443,15 @@
"type": "integer",
"minimum": 0
},
+ "executionBundleStatus": {
+ "type": ["string", "null"]
+ },
+ "executionBundleReciprocalLinkReady": {
+ "type": "boolean"
+ },
+ "executionBundlePremiumSaganMode": {
+ "type": "boolean"
+ },
"idleClassificationCoverage": {
"type": "object",
"additionalProperties": false,
diff --git a/docs/schemas/delivery-agent-runtime-state-v1.schema.json b/docs/schemas/delivery-agent-runtime-state-v1.schema.json
index f72b3aa9a..3f4aa961c 100644
--- a/docs/schemas/delivery-agent-runtime-state-v1.schema.json
+++ b/docs/schemas/delivery-agent-runtime-state-v1.schema.json
@@ -322,6 +322,34 @@
"requiresLocalCheckout": { "type": ["boolean", "null"] }
}
},
+ "executionTopology": {
+ "type": ["object", "null"],
+ "additionalProperties": true,
+ "properties": {
+ "status": { "type": ["string", "null"] },
+ "executionPlane": { "type": ["string", "null"] },
+ "providerId": { "type": ["string", "null"] },
+ "workerSlotId": { "type": ["string", "null"] },
+ "cellId": { "type": ["string", "null"] },
+ "laneId": { "type": ["string", "null"] },
+ "cellClass": { "type": ["string", "null"] },
+ "suiteClass": { "type": ["string", "null"] },
+ "planeBinding": { "type": ["string", "null"] },
+ "harnessKind": { "type": ["string", "null"] },
+ "harnessInstanceId": { "type": ["string", "null"] },
+ "executionCellLeaseId": { "type": ["string", "null"] },
+ "dockerLaneLeaseId": { "type": ["string", "null"] },
+ "premiumSaganMode": { "type": "boolean" },
+ "reciprocalLinkReady": { "type": "boolean" },
+ "operatorAuthorizationRef": { "type": ["string", "null"] },
+ "activeLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "seededLogicalLaneCount": { "type": ["integer", "null"], "minimum": 0 },
+ "runtimeSurface": { "type": ["string", "null"] },
+ "processModelClass": { "type": ["string", "null"] },
+ "windowsOnly": { "type": "boolean" },
+ "requestedSimultaneous": { "type": "boolean" }
+ }
+ },
"providerDispatch": {
"type": ["object", "null"],
"additionalProperties": true,
diff --git a/docs/schemas/docker-lane-handshake-report-v1.schema.json b/docs/schemas/docker-lane-handshake-report-v1.schema.json
new file mode 100644
index 000000000..6a657a279
--- /dev/null
+++ b/docs/schemas/docker-lane-handshake-report-v1.schema.json
@@ -0,0 +1,117 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://schemas.comparevi.dev/docker-lane-handshake-report-v1.schema.json",
+ "title": "Docker Lane Handshake Report v1",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "action",
+ "status",
+ "laneId",
+ "handshakePath",
+ "policy",
+ "handshake",
+ "summary"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/docker-lane-handshake-report@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "action": {
+ "enum": ["request", "grant", "commit", "heartbeat", "release", "inspect"]
+ },
+ "status": {
+ "enum": [
+ "requested",
+ "granted",
+ "committed",
+ "released",
+ "renewed",
+ "active",
+ "busy",
+ "denied",
+ "not-found",
+ "mismatch",
+ "invalid-state",
+ "stale"
+ ]
+ },
+ "laneId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "handshakePath": {
+ "type": "string",
+ "minLength": 1
+ },
+ "policy": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["operatorId", "currency", "laborRateUsdPerHour", "premiumSaganRateMultiplier"],
+ "properties": {
+ "operatorId": { "type": ["string", "null"] },
+ "currency": { "type": ["string", "null"] },
+ "laborRateUsdPerHour": { "type": ["number", "null"], "minimum": 0 },
+ "premiumSaganRateMultiplier": { "type": "number", "minimum": 1 }
+ }
+ },
+ "handshake": {
+ "anyOf": [
+ { "type": "null" },
+ { "$ref": "docker-lane-handshake-v1.schema.json" }
+ ]
+ },
+ "summary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "handshakeState",
+ "leaseId",
+ "holder",
+ "premiumSaganMode",
+ "billableRateMultiplier",
+ "billableRateUsdPerHour",
+ "operatorAuthorizationRef",
+ "isolatedLaneGroupId",
+ "fingerprintSha256",
+ "linkedExecutionCellId",
+ "linkedExecutionCellLeaseId",
+ "isStale",
+ "ageSeconds",
+ "ttlSeconds",
+ "denialReasons",
+ "observations"
+ ],
+ "properties": {
+ "handshakeState": { "type": ["string", "null"] },
+ "leaseId": { "type": ["string", "null"] },
+ "holder": { "type": ["string", "null"] },
+ "premiumSaganMode": { "type": "boolean" },
+ "billableRateMultiplier": { "type": ["number", "null"], "minimum": 1 },
+ "billableRateUsdPerHour": { "type": ["number", "null"], "minimum": 0 },
+ "operatorAuthorizationRef": { "type": ["string", "null"] },
+ "isolatedLaneGroupId": { "type": ["string", "null"] },
+ "fingerprintSha256": { "type": ["string", "null"] },
+ "linkedExecutionCellId": { "type": ["string", "null"] },
+ "linkedExecutionCellLeaseId": { "type": ["string", "null"] },
+ "isStale": { "type": "boolean" },
+ "ageSeconds": { "type": ["number", "null"], "minimum": 0 },
+ "ttlSeconds": { "type": ["integer", "null"], "minimum": 1 },
+ "denialReasons": {
+ "type": "array",
+ "items": { "type": "string", "minLength": 1 }
+ },
+ "observations": {
+ "type": "array",
+ "items": { "type": "string", "minLength": 1 }
+ }
+ }
+ }
+ }
+}
diff --git a/docs/schemas/docker-lane-handshake-v1.schema.json b/docs/schemas/docker-lane-handshake-v1.schema.json
new file mode 100644
index 000000000..a8044c9ec
--- /dev/null
+++ b/docs/schemas/docker-lane-handshake-v1.schema.json
@@ -0,0 +1,172 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://schemas.comparevi.dev/docker-lane-handshake-v1.schema.json",
+ "title": "Docker Lane Handshake v1",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "laneId",
+ "resourceKind",
+ "state",
+ "sequence",
+ "heartbeatAt",
+ "host",
+ "request",
+ "grant",
+ "commit",
+ "release"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/docker-lane-handshake@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "laneId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "resourceKind": {
+ "const": "docker-lane"
+ },
+ "state": {
+ "enum": ["requested", "granted", "active", "released"]
+ },
+ "sequence": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "heartbeatAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "host": {
+ "anyOf": [
+ { "type": "null" },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["isolatedLaneGroupId", "fingerprintSha256", "platform", "computerName", "canonical"],
+ "properties": {
+ "isolatedLaneGroupId": { "type": ["string", "null"] },
+ "fingerprintSha256": { "type": ["string", "null"] },
+ "platform": { "type": ["string", "null"] },
+ "computerName": { "type": ["string", "null"] },
+ "canonical": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["version", "buildNumber", "ubr"],
+ "properties": {
+ "version": { "type": ["string", "null"] },
+ "buildNumber": { "type": ["string", "null"] },
+ "ubr": { "type": ["integer", "null"], "minimum": 0 }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "request": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "requestId",
+ "requestedAt",
+ "agentId",
+ "agentClass",
+ "capabilities",
+ "premiumDualLaneRequested",
+ "operatorId",
+ "operatorAuthorizationRef"
+ ],
+ "properties": {
+ "requestId": { "type": "string", "minLength": 1 },
+ "requestedAt": { "type": "string", "format": "date-time" },
+ "agentId": { "type": "string", "minLength": 1 },
+ "agentClass": { "enum": ["sagan", "subagent", "other"] },
+ "capabilities": {
+ "type": "array",
+ "minItems": 1,
+ "items": { "type": "string", "minLength": 1 }
+ },
+ "premiumDualLaneRequested": { "type": "boolean" },
+ "operatorId": { "type": ["string", "null"] },
+ "operatorAuthorizationRef": { "type": ["string", "null"] }
+ }
+ },
+ "grant": {
+ "anyOf": [
+ { "type": "null" },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "grantedAt",
+ "grantor",
+ "leaseId",
+ "ttlSeconds",
+ "grantedCapabilities",
+ "billableRateMultiplier",
+ "billableRateUsdPerHour",
+ "premiumSaganMode",
+ "policyDecision",
+ "operatorAuthorizationRef"
+ ],
+ "properties": {
+ "grantedAt": { "type": "string", "format": "date-time" },
+ "grantor": { "type": "string", "minLength": 1 },
+ "leaseId": { "type": "string", "minLength": 1 },
+ "ttlSeconds": { "type": "integer", "minimum": 1 },
+ "grantedCapabilities": {
+ "type": "array",
+ "minItems": 1,
+ "items": { "type": "string", "minLength": 1 }
+ },
+ "billableRateMultiplier": { "type": "number", "minimum": 1 },
+ "billableRateUsdPerHour": { "type": "number", "minimum": 0 },
+ "premiumSaganMode": { "type": "boolean" },
+ "policyDecision": { "enum": ["ordinary-docker-lane", "sagan-premium-dual-lane"] },
+ "operatorAuthorizationRef": { "type": ["string", "null"] }
+ }
+ }
+ ]
+ },
+ "commit": {
+ "anyOf": [
+ { "type": "null" },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["committedAt", "executionCellId", "executionCellLeaseId"],
+ "properties": {
+ "committedAt": { "type": "string", "format": "date-time" },
+ "executionCellId": { "type": ["string", "null"] },
+ "executionCellLeaseId": { "type": ["string", "null"] }
+ }
+ }
+ ]
+ },
+ "release": {
+ "anyOf": [
+ { "type": "null" },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["releasedAt", "finalStatus", "artifactPaths"],
+ "properties": {
+ "releasedAt": { "type": "string", "format": "date-time" },
+ "finalStatus": { "type": "string", "minLength": 1 },
+ "artifactPaths": {
+ "type": "array",
+ "items": { "type": "string", "minLength": 1 }
+ }
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/docs/schemas/execution-cell-bundle-report-v1.schema.json b/docs/schemas/execution-cell-bundle-report-v1.schema.json
new file mode 100644
index 000000000..3e9543b1e
--- /dev/null
+++ b/docs/schemas/execution-cell-bundle-report-v1.schema.json
@@ -0,0 +1,315 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://schemas.comparevi.dev/execution-cell-bundle-report-v1.schema.json",
+ "title": "Execution Cell Bundle Report",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "action",
+ "status",
+ "cellId",
+ "laneId",
+ "outputPath",
+ "executionCellReportPath",
+ "dockerLaneReportPath",
+ "executionCell",
+ "dockerLane",
+ "rollbacks",
+ "summary"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/execution-cell-bundle-report@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "action": {
+ "type": "string",
+ "enum": [
+ "request",
+ "grant",
+ "commit",
+ "heartbeat",
+ "release",
+ "inspect"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "requested",
+ "granted",
+ "committed",
+ "renewed",
+ "released",
+ "active",
+ "busy",
+ "denied",
+ "not-found",
+ "mismatch",
+ "invalid-state",
+ "stale",
+ "partial"
+ ]
+ },
+ "cellId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "laneId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "outputPath": {
+ "type": "string",
+ "minLength": 1
+ },
+ "executionCellReportPath": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "dockerLaneReportPath": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "executionCell": {
+ "oneOf": [
+ {
+ "$ref": "execution-cell-lease-report-v1.schema.json"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "dockerLane": {
+ "oneOf": [
+ {
+ "$ref": "docker-lane-handshake-report-v1.schema.json"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "rollbacks": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "executionCell",
+ "dockerLane"
+ ],
+ "properties": {
+ "executionCell": {
+ "oneOf": [
+ {
+ "$ref": "execution-cell-lease-report-v1.schema.json"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "dockerLane": {
+ "oneOf": [
+ {
+ "$ref": "docker-lane-handshake-report-v1.schema.json"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ }
+ },
+ "summary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "holder",
+ "agentClass",
+ "cellClass",
+ "suiteClass",
+ "planeBinding",
+ "harnessKind",
+ "harnessInstanceId",
+ "executionCellLeaseId",
+ "dockerLaneLeaseId",
+ "linkedExecutionCellId",
+ "linkedExecutionCellLeaseId",
+ "linkedDockerLaneId",
+ "linkedDockerLaneLeaseId",
+ "reciprocalLinkReady",
+ "dockerRequested",
+ "windowsNativeTestStand",
+ "effectiveBillableRateMultiplier",
+ "effectiveBillableRateUsdPerHour",
+ "premiumSaganMode",
+ "operatorAuthorizationRef",
+ "isolatedLaneGroupId",
+ "fingerprintSha256",
+ "capabilities",
+ "denialReasons",
+ "observations"
+ ],
+ "properties": {
+ "holder": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "agentClass": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "cellClass": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "suiteClass": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "planeBinding": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "harnessKind": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "harnessInstanceId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "executionCellLeaseId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "dockerLaneLeaseId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "linkedExecutionCellId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "linkedExecutionCellLeaseId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "linkedDockerLaneId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "linkedDockerLaneLeaseId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "reciprocalLinkReady": {
+ "type": "boolean"
+ },
+ "dockerRequested": {
+ "type": "boolean"
+ },
+ "windowsNativeTestStand": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "effectiveBillableRateMultiplier": {
+ "type": [
+ "number",
+ "null"
+ ],
+ "minimum": 0
+ },
+ "effectiveBillableRateUsdPerHour": {
+ "type": [
+ "number",
+ "null"
+ ],
+ "minimum": 0
+ },
+ "premiumSaganMode": {
+ "type": "boolean"
+ },
+ "operatorAuthorizationRef": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "isolatedLaneGroupId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "fingerprintSha256": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "capabilities": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ },
+ "denialReasons": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ },
+ "observations": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/docs/schemas/execution-cell-lease-report-v1.schema.json b/docs/schemas/execution-cell-lease-report-v1.schema.json
new file mode 100644
index 000000000..a4c2e4fc1
--- /dev/null
+++ b/docs/schemas/execution-cell-lease-report-v1.schema.json
@@ -0,0 +1,277 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://schemas.comparevi.dev/execution-cell-lease-report-v1.schema.json",
+ "title": "Execution Cell Lease Report",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "action",
+ "status",
+ "cellId",
+ "leasePath",
+ "lease",
+ "summary",
+ "policy"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/execution-cell-lease-report@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "action": {
+ "type": "string",
+ "enum": [
+ "request",
+ "grant",
+ "commit",
+ "heartbeat",
+ "release",
+ "inspect"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "requested",
+ "granted",
+ "committed",
+ "renewed",
+ "released",
+ "active",
+ "busy",
+ "denied",
+ "not-found",
+ "mismatch",
+ "invalid-state",
+ "stale"
+ ]
+ },
+ "cellId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "leasePath": {
+ "type": "string",
+ "minLength": 1
+ },
+ "lease": {
+ "oneOf": [
+ {
+ "$ref": "execution-cell-lease-v1.schema.json"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "policy": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "operatorId",
+ "currency",
+ "laborRateUsdPerHour"
+ ],
+ "properties": {
+ "operatorId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "currency": {
+ "type": "string",
+ "minLength": 1
+ },
+ "laborRateUsdPerHour": {
+ "type": [
+ "number",
+ "null"
+ ],
+ "minimum": 0
+ }
+ }
+ },
+ "summary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "leaseState",
+ "leaseId",
+ "holder",
+ "agentClass",
+ "cellClass",
+ "harnessKind",
+ "harnessInstanceId",
+ "suiteClass",
+ "planeBinding",
+ "premiumSaganMode",
+ "billableRateMultiplier",
+ "billableRateUsdPerHour",
+ "operatorAuthorizationRef",
+ "isolatedLaneGroupId",
+ "fingerprintSha256",
+ "linkedDockerLaneId",
+ "linkedDockerLaneLeaseId",
+ "workingRoot",
+ "artifactRoot",
+ "isStale",
+ "ageSeconds",
+ "ttlSeconds",
+ "denialReasons",
+ "observations"
+ ],
+ "properties": {
+ "leaseState": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "leaseId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "holder": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "agentClass": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "cellClass": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "harnessKind": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "harnessInstanceId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "suiteClass": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "planeBinding": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "premiumSaganMode": {
+ "type": "boolean"
+ },
+ "billableRateMultiplier": {
+ "type": [
+ "number",
+ "null"
+ ],
+ "minimum": 0
+ },
+ "billableRateUsdPerHour": {
+ "type": [
+ "number",
+ "null"
+ ],
+ "minimum": 0
+ },
+ "operatorAuthorizationRef": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "isolatedLaneGroupId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "fingerprintSha256": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "linkedDockerLaneId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "linkedDockerLaneLeaseId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "workingRoot": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "artifactRoot": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "isStale": {
+ "type": "boolean"
+ },
+ "ageSeconds": {
+ "type": [
+ "number",
+ "null"
+ ],
+ "minimum": 0
+ },
+ "ttlSeconds": {
+ "type": [
+ "integer",
+ "null"
+ ],
+ "minimum": 0
+ },
+ "denialReasons": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ },
+ "observations": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/docs/schemas/execution-cell-lease-v1.schema.json b/docs/schemas/execution-cell-lease-v1.schema.json
new file mode 100644
index 000000000..121ea84e2
--- /dev/null
+++ b/docs/schemas/execution-cell-lease-v1.schema.json
@@ -0,0 +1,365 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://schemas.comparevi.dev/execution-cell-lease-v1.schema.json",
+ "title": "Execution Cell Lease",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "cellId",
+ "resourceKind",
+ "state",
+ "sequence",
+ "heartbeatAt",
+ "request",
+ "grant",
+ "commit",
+ "release"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/execution-cell-lease@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "cellId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "resourceKind": {
+ "const": "execution-cell"
+ },
+ "state": {
+ "type": "string",
+ "enum": [
+ "requested",
+ "granted",
+ "active",
+ "released"
+ ]
+ },
+ "sequence": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "heartbeatAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "host": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "isolatedLaneGroupId",
+ "fingerprintSha256",
+ "platform",
+ "computerName",
+ "canonical"
+ ],
+ "properties": {
+ "isolatedLaneGroupId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "fingerprintSha256": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "computerName": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "canonical": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "buildNumber",
+ "ubr"
+ ],
+ "properties": {
+ "version": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "buildNumber": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "ubr": {
+ "type": [
+ "integer",
+ "null"
+ ],
+ "minimum": 0
+ }
+ }
+ }
+ }
+ },
+ "request": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "requestId",
+ "requestedAt",
+ "agentId",
+ "agentClass",
+ "cellClass",
+ "suiteClass",
+ "planeBinding",
+ "harnessKind",
+ "capabilities",
+ "premiumDualLaneRequested",
+ "operatorId",
+ "operatorAuthorizationRef",
+ "workingRoot",
+ "artifactRoot"
+ ],
+ "properties": {
+ "requestId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "requestedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "agentId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "agentClass": {
+ "type": "string",
+ "enum": [
+ "sagan",
+ "subagent",
+ "other"
+ ]
+ },
+ "cellClass": {
+ "type": "string",
+ "enum": [
+ "worker",
+ "coordinator",
+ "kernel-coordinator"
+ ]
+ },
+ "suiteClass": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "planeBinding": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "harnessKind": {
+ "type": "string",
+ "minLength": 1
+ },
+ "capabilities": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ },
+ "premiumDualLaneRequested": {
+ "type": "boolean"
+ },
+ "operatorId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "operatorAuthorizationRef": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "workingRoot": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "artifactRoot": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ },
+ "grant": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "grantedAt",
+ "grantor",
+ "leaseId",
+ "ttlSeconds",
+ "premiumDualLaneRequested",
+ "premiumSaganMode",
+ "policyDecision",
+ "grantedCapabilities",
+ "billableRateMultiplier",
+ "billableRateUsdPerHour"
+ ],
+ "properties": {
+ "grantedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "grantor": {
+ "type": "string",
+ "minLength": 1
+ },
+ "leaseId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "ttlSeconds": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "premiumDualLaneRequested": {
+ "type": "boolean"
+ },
+ "premiumSaganMode": {
+ "type": "boolean"
+ },
+ "policyDecision": {
+ "type": "string",
+ "minLength": 1
+ },
+ "grantedCapabilities": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ },
+ "billableRateMultiplier": {
+ "type": "number",
+ "minimum": 0
+ },
+ "billableRateUsdPerHour": {
+ "type": [
+ "number",
+ "null"
+ ],
+ "minimum": 0
+ }
+ }
+ },
+ "commit": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "committedAt",
+ "harnessInstanceId",
+ "dockerLaneId",
+ "dockerLaneLeaseId",
+ "workingRoot",
+ "artifactRoot"
+ ],
+ "properties": {
+ "committedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "harnessInstanceId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "dockerLaneId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "dockerLaneLeaseId": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "workingRoot": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "artifactRoot": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ },
+ "release": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "releasedAt",
+ "artifactPaths"
+ ],
+ "properties": {
+ "releasedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "artifactPaths": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/docs/schemas/github-comment-budget-hook-policy-v1.schema.json b/docs/schemas/github-comment-budget-hook-policy-v1.schema.json
new file mode 100644
index 000000000..5eb2d3dc4
--- /dev/null
+++ b/docs/schemas/github-comment-budget-hook-policy-v1.schema.json
@@ -0,0 +1,37 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://schemas.labview-community-cicd.example/compare-vi-cli-action/github-comment-budget-hook-policy-v1.schema.json",
+ "title": "GitHub Comment Budget Hook Policy v1",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "costRollupPath",
+ "materializationPolicyPath",
+ "materializationReportPath",
+ "outputPath",
+ "markdownOutputPath",
+ "operatorBudgetCapUsd",
+ "materializeCostRollup",
+ "reservedFundingPurposes",
+ "reservedActivationStates"
+ ],
+ "properties": {
+ "schema": { "const": "priority/github-comment-budget-hook-policy@v1" },
+ "costRollupPath": { "type": "string", "minLength": 1 },
+ "materializationPolicyPath": { "type": "string", "minLength": 1 },
+ "materializationReportPath": { "type": "string", "minLength": 1 },
+ "outputPath": { "type": "string", "minLength": 1 },
+ "markdownOutputPath": { "type": "string", "minLength": 1 },
+ "operatorBudgetCapUsd": { "type": "number", "minimum": 0 },
+ "materializeCostRollup": { "type": "boolean" },
+ "reservedFundingPurposes": {
+ "type": "array",
+ "items": { "type": "string", "minLength": 1 }
+ },
+ "reservedActivationStates": {
+ "type": "array",
+ "items": { "type": "string", "minLength": 1 }
+ }
+ }
+}
diff --git a/docs/schemas/github-comment-budget-hook-report-v1.schema.json b/docs/schemas/github-comment-budget-hook-report-v1.schema.json
new file mode 100644
index 000000000..9506f490e
--- /dev/null
+++ b/docs/schemas/github-comment-budget-hook-report-v1.schema.json
@@ -0,0 +1,146 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://schemas.labview-community-cicd.example/compare-vi-cli-action/github-comment-budget-hook-report-v1.schema.json",
+ "title": "GitHub Comment Budget Hook Report v1",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "repository",
+ "target",
+ "summary",
+ "turns",
+ "funding",
+ "source",
+ "blockers"
+ ],
+ "properties": {
+ "schema": { "const": "priority/github-comment-budget-hook@v1" },
+ "generatedAt": { "type": "string", "format": "date-time" },
+ "repository": { "type": ["string", "null"] },
+ "target": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["kind", "number"],
+ "properties": {
+ "kind": { "type": "string", "minLength": 1 },
+ "number": { "type": ["integer", "null"], "minimum": 1 }
+ }
+ },
+ "summary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "recommendation",
+ "tokenSpendUsd",
+ "operatorLaborObservedUsd",
+ "operatorLaborMissingTurnCount",
+ "observedBlendedLowerBoundUsd",
+ "knownBlendedUsd",
+ "operatorBudgetCapUsd",
+ "operatorBudgetRemainingLowerBoundUsd",
+ "operatorBudgetRemainingStatus"
+ ],
+ "properties": {
+ "status": { "type": "string", "enum": ["pass", "warn", "blocked"] },
+ "recommendation": { "type": "string", "minLength": 1 },
+ "tokenSpendUsd": { "type": "number", "minimum": 0 },
+ "operatorLaborObservedUsd": { "type": "number", "minimum": 0 },
+ "operatorLaborMissingTurnCount": { "type": "integer", "minimum": 0 },
+ "observedBlendedLowerBoundUsd": { "type": "number", "minimum": 0 },
+ "knownBlendedUsd": { "type": ["number", "null"], "minimum": 0 },
+ "operatorBudgetCapUsd": { "type": ["number", "null"], "minimum": 0 },
+ "operatorBudgetRemainingLowerBoundUsd": { "type": ["number", "null"], "minimum": 0 },
+ "operatorBudgetRemainingStatus": { "type": "string", "enum": ["observed", "lower-bound", "unknown"] }
+ }
+ },
+ "turns": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["totalTurns", "liveTurnCount", "backgroundTurnCount"],
+ "properties": {
+ "totalTurns": { "type": "integer", "minimum": 0 },
+ "liveTurnCount": { "type": "integer", "minimum": 0 },
+ "backgroundTurnCount": { "type": "integer", "minimum": 0 }
+ }
+ },
+ "funding": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["billingWindow", "reservedFunding"],
+ "properties": {
+ "billingWindow": {
+ "type": ["object", "null"],
+ "additionalProperties": false,
+ "required": ["invoiceTurnId", "invoiceId", "fundingPurpose", "activationState", "prepaidUsd", "tokenSpendUsd", "remainingUsd", "pricingBasis", "selectionMode", "selectionReason"],
+ "properties": {
+ "invoiceTurnId": { "type": ["string", "null"] },
+ "invoiceId": { "type": ["string", "null"] },
+ "fundingPurpose": { "type": ["string", "null"] },
+ "activationState": { "type": ["string", "null"] },
+ "prepaidUsd": { "type": ["number", "null"], "minimum": 0 },
+ "tokenSpendUsd": { "type": "number", "minimum": 0 },
+ "remainingUsd": { "type": ["number", "null"], "minimum": 0 },
+ "pricingBasis": { "type": ["string", "null"] },
+ "selectionMode": { "type": ["string", "null"] },
+ "selectionReason": { "type": ["string", "null"] }
+ }
+ },
+ "reservedFunding": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["count", "totalReservedUsd", "windows"],
+ "properties": {
+ "count": { "type": "integer", "minimum": 0 },
+ "totalReservedUsd": { "type": "number", "minimum": 0 },
+ "windows": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["invoiceTurnId", "invoiceId", "fundingPurpose", "activationState", "prepaidUsd", "operatorNote"],
+ "properties": {
+ "invoiceTurnId": { "type": ["string", "null"] },
+ "invoiceId": { "type": ["string", "null"] },
+ "fundingPurpose": { "type": ["string", "null"] },
+ "activationState": { "type": ["string", "null"] },
+ "prepaidUsd": { "type": ["number", "null"], "minimum": 0 },
+ "operatorNote": { "type": ["string", "null"] }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "source": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["policyPath", "costRollupPath", "costRollupMaterialized", "costRollupMaterializationReportPath", "operatorCostProfilePath", "outputPath", "markdownOutputPath"],
+ "properties": {
+ "policyPath": { "type": ["string", "null"] },
+ "costRollupPath": { "type": ["string", "null"] },
+ "costRollupMaterialized": { "type": "boolean" },
+ "costRollupMaterializationReportPath": { "type": ["string", "null"] },
+ "operatorCostProfilePath": { "type": ["string", "null"] },
+ "outputPath": { "type": ["string", "null"] },
+ "markdownOutputPath": { "type": ["string", "null"] }
+ }
+ },
+ "blockers": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["code", "message", "details"],
+ "properties": {
+ "code": { "type": "string", "minLength": 1 },
+ "message": { "type": "string", "minLength": 1 },
+ "details": { "type": ["string", "null"] }
+ }
+ }
+ }
+ }
+}
diff --git a/docs/schemas/labview-2026-host-plane-report-v1.schema.json b/docs/schemas/labview-2026-host-plane-report-v1.schema.json
index b12e59526..7c677a0a9 100644
--- a/docs/schemas/labview-2026-host-plane-report-v1.schema.json
+++ b/docs/schemas/labview-2026-host-plane-report-v1.schema.json
@@ -23,10 +23,11 @@
},
"host": {
"type": "object",
- "required": ["os", "computerName"],
+ "required": ["os", "computerName", "osFingerprint"],
"properties": {
"os": { "type": "string" },
- "computerName": { "type": "string" }
+ "computerName": { "type": "string" },
+ "osFingerprint": { "$ref": "#/definitions/osFingerprint" }
},
"additionalProperties": false
},
@@ -183,6 +184,94 @@
}
},
"additionalProperties": false
+ },
+ "osFingerprint": {
+ "type": "object",
+ "required": [
+ "role",
+ "comparisonScope",
+ "platform",
+ "fingerprintSha256",
+ "isolatedLaneGroupId",
+ "canonical",
+ "advisory",
+ "sources"
+ ],
+ "properties": {
+ "role": { "const": "canonical-host-baseline" },
+ "comparisonScope": { "const": "isolated-lane-group" },
+ "platform": { "type": "string" },
+ "fingerprintSha256": {
+ "type": "string",
+ "pattern": "^[a-f0-9]{64}$"
+ },
+ "isolatedLaneGroupId": {
+ "type": "string",
+ "pattern": "^host-os-fingerprint:[a-f0-9]{64}$"
+ },
+ "canonical": {
+ "type": "object",
+ "required": [
+ "version",
+ "buildNumber",
+ "ubr",
+ "displayVersion",
+ "editionId",
+ "installationType",
+ "architecture",
+ "systemType",
+ "buildLabEx"
+ ],
+ "properties": {
+ "version": { "type": "string" },
+ "buildNumber": { "type": "string" },
+ "ubr": { "type": "integer", "minimum": 0 },
+ "displayVersion": { "type": "string" },
+ "editionId": { "type": "string" },
+ "installationType": { "type": "string" },
+ "architecture": { "type": "string" },
+ "systemType": { "type": "string" },
+ "buildLabEx": { "type": "string" }
+ },
+ "additionalProperties": false
+ },
+ "advisory": {
+ "type": "object",
+ "required": [
+ "caption",
+ "productName",
+ "currentVersionCompatibility",
+ "brandingMismatch",
+ "installDate",
+ "lastBootUpTime"
+ ],
+ "properties": {
+ "caption": { "type": "string" },
+ "productName": { "type": "string" },
+ "currentVersionCompatibility": { "type": "string" },
+ "brandingMismatch": { "type": "boolean" },
+ "installDate": { "type": "string" },
+ "lastBootUpTime": { "type": "string" }
+ },
+ "additionalProperties": false
+ },
+ "sources": {
+ "type": "object",
+ "required": ["registryPath", "cimClass", "systemClass", "comparisonFields"],
+ "properties": {
+ "registryPath": { "type": "string" },
+ "cimClass": { "type": "string" },
+ "systemClass": { "type": "string" },
+ "comparisonFields": {
+ "type": "array",
+ "items": { "type": "string" },
+ "minItems": 1
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
}
},
"additionalProperties": false
diff --git a/docs/schemas/loop-final-status-v1.schema.json b/docs/schemas/loop-final-status-v1.schema.json
index 006d9ea22..c4fc3257d 100644
--- a/docs/schemas/loop-final-status-v1.schema.json
+++ b/docs/schemas/loop-final-status-v1.schema.json
@@ -17,7 +17,31 @@
"histogram": {"type": ["array","null"], "items": {"type": "object"}},
"diffSummaryEmitted": {"type": "boolean"},
"basePath": {"type": "string"},
- "headPath": {"type": "string"}
+ "headPath": {"type": "string"},
+ "harness": {
+ "type": "object",
+ "properties": {
+ "path": {"type": "string"},
+ "output": {"type": "string"},
+ "suiteClass": {"type": "string"},
+ "runtimeSurface": {"const": "windows-native-teststand"},
+ "processModelClass": {
+ "type": "string",
+ "enum": ["sequential-process-model", "parallel-process-model"]
+ },
+ "windowsOnly": {"type": "boolean"},
+ "requestedSimultaneous": {"type": "boolean"},
+ "cellClass": {"type": ["string", "null"]},
+ "operatorAuthorizationRef": {"type": ["string", "null"]},
+ "premiumSaganMode": {"type": "boolean"},
+ "executionCellLeasePath": {"type": "string"},
+ "executionCellId": {"type": "string"},
+ "executionCellLeaseId": {"type": "string"},
+ "harnessInstanceId": {"type": "string"}
+ },
+ "required": ["path", "output", "suiteClass", "runtimeSurface", "processModelClass", "windowsOnly", "requestedSimultaneous"],
+ "additionalProperties": true
+ }
},
"additionalProperties": true
}
diff --git a/docs/schemas/release-conductor-report-v1.schema.json b/docs/schemas/release-conductor-report-v1.schema.json
index d7391ed03..f0179c964 100644
--- a/docs/schemas/release-conductor-report-v1.schema.json
+++ b/docs/schemas/release-conductor-report-v1.schema.json
@@ -46,8 +46,13 @@
"targetTag",
"proposalOnly",
"tagCreated",
+ "tagPushed",
"tagError",
- "signingMaterial"
+ "tagPushError",
+ "tagPushRemote",
+ "signingMaterial",
+ "repair",
+ "publicationReplay"
],
"properties": {
"stream": { "type": "string" },
@@ -56,15 +61,94 @@
"targetTag": { "type": ["string", "null"] },
"proposalOnly": { "type": "boolean" },
"tagCreated": { "type": "boolean" },
+ "tagPushed": { "type": "boolean" },
"tagError": { "type": ["string", "null"] },
+ "tagPushError": { "type": ["string", "null"] },
+ "tagPushRemote": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["remoteName", "remoteSlug", "source"],
+ "properties": {
+ "remoteName": { "type": ["string", "null"] },
+ "remoteSlug": { "type": ["string", "null"] },
+ "source": { "type": "string" }
+ }
+ },
"signingMaterial": {
"type": "object",
"additionalProperties": false,
- "required": ["available", "signingKey", "source"],
+ "required": ["available", "signingKey", "source", "backend", "identity"],
"properties": {
"available": { "type": "boolean" },
"signingKey": { "type": ["string", "null"] },
- "source": { "type": "string" }
+ "source": { "type": "string" },
+ "backend": { "type": "string" },
+ "identity": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["available", "name", "email", "source", "login", "accountId"],
+ "properties": {
+ "available": { "type": "boolean" },
+ "name": { "type": ["string", "null"] },
+ "email": { "type": ["string", "null"] },
+ "source": { "type": "string" },
+ "login": { "type": ["string", "null"] },
+ "accountId": { "type": ["string", "null"] }
+ }
+ }
+ }
+ },
+ "repair": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "requested",
+ "status",
+ "remoteTagRef",
+ "remoteTagExists",
+ "remoteTagAnnotated",
+ "remoteTagObjectOid",
+ "remoteTargetCommitOid",
+ "localTagPresent",
+ "localTagDeleted",
+ "tagRecreated",
+ "pushLeaseExpectedOid",
+ "lookupError"
+ ],
+ "properties": {
+ "requested": { "type": "boolean" },
+ "status": {
+ "type": "string",
+ "enum": ["not-requested", "repair-available", "ready", "repaired", "blocked"]
+ },
+ "remoteTagRef": { "type": ["string", "null"] },
+ "remoteTagExists": { "type": "boolean" },
+ "remoteTagAnnotated": { "type": ["boolean", "null"] },
+ "remoteTagObjectOid": { "type": ["string", "null"] },
+ "remoteTargetCommitOid": { "type": ["string", "null"] },
+ "localTagPresent": { "type": "boolean" },
+ "localTagDeleted": { "type": "boolean" },
+ "tagRecreated": { "type": "boolean" },
+ "pushLeaseExpectedOid": { "type": ["string", "null"] },
+ "lookupError": { "type": ["string", "null"] }
+ }
+ },
+ "publicationReplay": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["requested", "workflow", "ref", "tagInputName", "tagInputValue", "dispatched", "status", "error"],
+ "properties": {
+ "requested": { "type": "boolean" },
+ "workflow": { "type": "string" },
+ "ref": { "type": ["string", "null"] },
+ "tagInputName": { "type": ["string", "null"] },
+ "tagInputValue": { "type": ["string", "null"] },
+ "dispatched": { "type": "boolean" },
+ "status": {
+ "type": "string",
+ "enum": ["not-requested", "blocked", "dispatched", "dispatch-failed"]
+ },
+ "error": { "type": ["string", "null"] }
}
}
}
diff --git a/docs/schemas/release-published-bundle-observer-report-v1.schema.json b/docs/schemas/release-published-bundle-observer-report-v1.schema.json
new file mode 100644
index 000000000..295ba50e3
--- /dev/null
+++ b/docs/schemas/release-published-bundle-observer-report-v1.schema.json
@@ -0,0 +1,196 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://labview-community-ci-cd.github.io/compare-vi-cli-action/schemas/release-published-bundle-observer-report-v1.schema.json",
+ "title": "Release Published Bundle Observer Report",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "repository",
+ "inputs",
+ "selection",
+ "bundle",
+ "bundleContract",
+ "summary"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/release-published-bundle-observer-report@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "repository": {
+ "type": "string",
+ "minLength": 1
+ },
+ "inputs": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["requestedTag", "resultsDir"],
+ "properties": {
+ "requestedTag": { "type": ["string", "null"] },
+ "resultsDir": { "type": "string", "minLength": 1 }
+ }
+ },
+ "selection": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "releaseTag",
+ "publishedAt",
+ "releaseName",
+ "releaseId",
+ "prerelease",
+ "draft",
+ "assetName",
+ "assetId"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": ["selected", "release-unobserved", "release-not-found", "asset-missing"]
+ },
+ "releaseTag": { "type": ["string", "null"] },
+ "publishedAt": { "type": ["string", "null"], "format": "date-time" },
+ "releaseName": { "type": ["string", "null"] },
+ "releaseId": { "type": ["integer", "null"] },
+ "prerelease": { "type": ["boolean", "null"] },
+ "draft": { "type": ["boolean", "null"] },
+ "assetName": { "type": ["string", "null"] },
+ "assetId": { "type": ["integer", "null"] }
+ }
+ },
+ "bundle": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["status", "archivePath", "extractionRoot", "downloadDirectory"],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": ["not-downloaded", "downloaded", "extracted", "download-failed", "extract-failed"]
+ },
+ "archivePath": { "type": ["string", "null"] },
+ "extractionRoot": { "type": ["string", "null"] },
+ "downloadDirectory": { "type": "string", "minLength": 1 },
+ "error": { "type": ["string", "null"] }
+ }
+ },
+ "bundleContract": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "metadataPath",
+ "schema",
+ "authoritativeConsumerPin",
+ "authoritativeConsumerPinKind",
+ "capabilityId",
+ "distributionRole",
+ "distributionModel",
+ "bundleImportPath",
+ "bundleImportPathExists",
+ "releaseAssetPattern",
+ "contractPathResolutions",
+ "dockerCapabilityId",
+ "dockerDistributionRole",
+ "dockerDistributionModel",
+ "authoritativeImageContractSource",
+ "authoritativeImageContractSourceResolved",
+ "dockerBundleImportPath",
+ "dockerBundleImportPathExists",
+ "dockerReleaseAssetPattern",
+ "dockerImageContractSchema",
+ "metadataPresent",
+ "metadataSchemaMatches",
+ "viHistoryCapabilityPresent",
+ "viHistoryCapabilityProducerNative",
+ "dockerProfileCapabilityPresent",
+ "dockerProfileCapabilityProducerNative",
+ "bundleContractPinResolved",
+ "bundleContractPathsResolved"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "release-unobserved",
+ "unobserved",
+ "metadata-missing",
+ "producer-native-incomplete",
+ "producer-native-ready",
+ "download-failed",
+ "extract-failed"
+ ]
+ },
+ "metadataPath": { "type": ["string", "null"] },
+ "schema": { "type": ["string", "null"] },
+ "authoritativeConsumerPin": { "type": ["string", "null"] },
+ "authoritativeConsumerPinKind": { "type": ["string", "null"] },
+ "capabilityId": { "type": ["string", "null"] },
+ "distributionRole": { "type": ["string", "null"] },
+ "distributionModel": { "type": ["string", "null"] },
+ "bundleImportPath": { "type": ["string", "null"] },
+ "bundleImportPathExists": { "type": "boolean" },
+ "releaseAssetPattern": { "type": ["string", "null"] },
+ "contractPathResolutions": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["name", "path", "resolved"],
+ "properties": {
+ "name": { "type": "string", "minLength": 1 },
+ "path": { "type": "string", "minLength": 1 },
+ "resolved": { "type": "boolean" }
+ }
+ }
+ },
+ "dockerCapabilityId": { "type": ["string", "null"] },
+ "dockerDistributionRole": { "type": ["string", "null"] },
+ "dockerDistributionModel": { "type": ["string", "null"] },
+ "authoritativeImageContractSource": { "type": ["string", "null"] },
+ "authoritativeImageContractSourceResolved": { "type": "boolean" },
+ "dockerBundleImportPath": { "type": ["string", "null"] },
+ "dockerBundleImportPathExists": { "type": "boolean" },
+ "dockerReleaseAssetPattern": { "type": ["string", "null"] },
+ "dockerImageContractSchema": { "type": ["string", "null"] },
+ "metadataPresent": { "type": "boolean" },
+ "metadataSchemaMatches": { "type": "boolean" },
+ "viHistoryCapabilityPresent": { "type": "boolean" },
+ "viHistoryCapabilityProducerNative": { "type": "boolean" },
+ "dockerProfileCapabilityPresent": { "type": "boolean" },
+ "dockerProfileCapabilityProducerNative": { "type": "boolean" },
+ "bundleContractPinResolved": { "type": "boolean" },
+ "bundleContractPathsResolved": { "type": "boolean" }
+ }
+ },
+ "summary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["status", "releaseTag", "assetName", "publishedAt", "authoritativeConsumerPin"],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "release-unobserved",
+ "release-not-found",
+ "asset-missing",
+ "download-failed",
+ "extract-failed",
+ "metadata-missing",
+ "producer-native-incomplete",
+ "producer-native-ready"
+ ]
+ },
+ "releaseTag": { "type": ["string", "null"] },
+ "assetName": { "type": ["string", "null"] },
+ "publishedAt": { "type": ["string", "null"], "format": "date-time" },
+ "authoritativeConsumerPin": { "type": ["string", "null"] }
+ }
+ }
+ }
+}
diff --git a/docs/schemas/release-signing-readiness-report-v1.schema.json b/docs/schemas/release-signing-readiness-report-v1.schema.json
new file mode 100644
index 000000000..7b84e4396
--- /dev/null
+++ b/docs/schemas/release-signing-readiness-report-v1.schema.json
@@ -0,0 +1,356 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://labview-community-ci-cd.github.io/compare-vi-cli-action/schemas/release-signing-readiness-report-v1.schema.json",
+ "title": "Release Signing Readiness Report",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "repository",
+ "inputs",
+ "workflowContract",
+ "secretInventory",
+ "releaseConductorApply",
+ "signingAuthority",
+ "publication",
+ "publishedBundleObserver",
+ "summary",
+ "blockers"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/release-signing-readiness-report@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "repository": {
+ "type": "string",
+ "minLength": 1
+ },
+ "inputs": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "releaseConductorReportPath",
+ "releasePublishedBundleObserverPath"
+ ],
+ "properties": {
+ "releaseConductorReportPath": {
+ "type": "string",
+ "minLength": 1
+ },
+ "releasePublishedBundleObserverPath": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ },
+ "workflowContract": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "ready",
+ "workflowPath",
+ "reasons"
+ ],
+ "properties": {
+ "ready": { "type": "boolean" },
+ "workflowPath": { "type": "string", "minLength": 1 },
+ "reasons": {
+ "type": "array",
+ "items": { "type": "string", "minLength": 1 }
+ }
+ }
+ },
+ "secretInventory": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "requiredSecretPresent",
+ "optionalPublicKeyPresent",
+ "listedSecretCount",
+ "listedSecretNames",
+ "source",
+ "error"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "configured",
+ "missing",
+ "unverifiable"
+ ]
+ },
+ "requiredSecretPresent": { "type": ["boolean", "null"] },
+ "optionalPublicKeyPresent": { "type": ["boolean", "null"] },
+ "listedSecretCount": { "type": ["integer", "null"], "minimum": 0 },
+ "listedSecretNames": {
+ "type": "array",
+ "items": { "type": "string", "minLength": 1 }
+ },
+ "source": { "type": "string", "minLength": 1 },
+ "error": { "type": ["string", "null"] }
+ }
+ },
+ "releaseConductorApply": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "variablePresent",
+ "enabled",
+ "configuredValue",
+ "listedVariableCount",
+ "listedVariableNames",
+ "source",
+ "error"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "enabled",
+ "disabled",
+ "unverifiable"
+ ]
+ },
+ "variablePresent": { "type": ["boolean", "null"] },
+ "enabled": { "type": ["boolean", "null"] },
+ "configuredValue": { "type": ["string", "null"] },
+ "listedVariableCount": { "type": ["integer", "null"], "minimum": 0 },
+ "listedVariableNames": {
+ "type": "array",
+ "items": { "type": "string", "minLength": 1 }
+ },
+ "source": { "type": "string", "minLength": 1 },
+ "error": { "type": ["string", "null"] }
+ }
+ },
+ "signingAuthority": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "requiredScope",
+ "scopeAvailable",
+ "listedKeyCount",
+ "source",
+ "error"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "ready",
+ "keys-missing",
+ "scope-missing",
+ "unverifiable"
+ ]
+ },
+ "requiredScope": { "type": "string", "minLength": 1 },
+ "scopeAvailable": { "type": ["boolean", "null"] },
+ "listedKeyCount": { "type": ["integer", "null"], "minimum": 0 },
+ "source": { "type": "string", "minLength": 1 },
+ "error": { "type": ["string", "null"] }
+ }
+ },
+ "publication": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "tagCreated",
+ "tagPushed",
+ "targetTag"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "unobserved",
+ "not-attempted",
+ "tag-created-not-pushed",
+ "authoritative-publication-successful"
+ ]
+ },
+ "tagCreated": { "type": "boolean" },
+ "tagPushed": { "type": "boolean" },
+ "targetTag": { "type": ["string", "null"] }
+ }
+ },
+ "publishedBundleObserver": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "releaseTag",
+ "assetName",
+ "publishedAt",
+ "authoritativeConsumerPin"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "unobserved",
+ "release-unobserved",
+ "release-not-found",
+ "asset-missing",
+ "download-failed",
+ "extract-failed",
+ "metadata-missing",
+ "producer-native-incomplete",
+ "producer-native-ready"
+ ]
+ },
+ "releaseTag": { "type": ["string", "null"] },
+ "assetName": { "type": ["string", "null"] },
+ "publishedAt": { "type": ["string", "null"], "format": "date-time" },
+ "authoritativeConsumerPin": { "type": ["string", "null"] }
+ }
+ },
+ "summary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "codePathState",
+ "signingCapabilityState",
+ "signingAuthorityState",
+ "releaseConductorApplyState",
+ "publicationState",
+ "publishedBundleState",
+ "publishedBundleReleaseTag",
+ "publishedBundleAuthoritativeConsumerPin",
+ "externalBlocker",
+ "blockerCount"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "pass",
+ "warn"
+ ]
+ },
+ "codePathState": {
+ "type": "string",
+ "enum": [
+ "ready",
+ "missing-contract"
+ ]
+ },
+ "signingCapabilityState": {
+ "type": "string",
+ "enum": [
+ "configured",
+ "missing",
+ "unverifiable"
+ ]
+ },
+ "signingAuthorityState": {
+ "type": "string",
+ "enum": [
+ "ready",
+ "keys-missing",
+ "scope-missing",
+ "unverifiable"
+ ]
+ },
+ "releaseConductorApplyState": {
+ "type": "string",
+ "enum": [
+ "enabled",
+ "disabled",
+ "unverifiable"
+ ]
+ },
+ "publicationState": {
+ "type": "string",
+ "enum": [
+ "unobserved",
+ "not-attempted",
+ "tag-created-not-pushed",
+ "authoritative-publication-successful"
+ ]
+ },
+ "publishedBundleState": {
+ "type": "string",
+ "enum": [
+ "unobserved",
+ "release-unobserved",
+ "release-not-found",
+ "asset-missing",
+ "download-failed",
+ "extract-failed",
+ "metadata-missing",
+ "producer-native-incomplete",
+ "producer-native-ready"
+ ]
+ },
+ "publishedBundleReleaseTag": {
+ "type": ["string", "null"]
+ },
+ "publishedBundleAuthoritativeConsumerPin": {
+ "type": ["string", "null"]
+ },
+ "externalBlocker": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "enum": [
+ "workflow-signing-secret-missing",
+ "workflow-signing-secret-unverifiable",
+ "workflow-signing-admin-scope-missing",
+ "workflow-signing-key-missing",
+ "workflow-signing-authority-unverifiable",
+ "release-conductor-apply-disabled",
+ "release-conductor-apply-unverifiable",
+ null
+ ]
+ },
+ "blockerCount": { "type": "integer", "minimum": 0 }
+ }
+ },
+ "blockers": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "code",
+ "message"
+ ],
+ "properties": {
+ "code": {
+ "type": "string",
+ "enum": [
+ "workflow-signing-contract-missing",
+ "workflow-signing-secret-missing",
+ "workflow-signing-secret-unverifiable",
+ "workflow-signing-admin-scope-missing",
+ "workflow-signing-key-missing",
+ "workflow-signing-authority-unverifiable",
+ "release-conductor-apply-disabled",
+ "release-conductor-apply-unverifiable",
+ "published-bundle-release-unobserved",
+ "published-bundle-release-not-found",
+ "published-bundle-asset-missing",
+ "published-bundle-download-failed",
+ "published-bundle-extract-failed",
+ "published-bundle-metadata-missing",
+ "published-bundle-producer-native-incomplete"
+ ]
+ },
+ "message": { "type": "string", "minLength": 1 }
+ }
+ }
+ }
+ }
+}
diff --git a/docs/schemas/sagan-context-concentrator-report-v1.schema.json b/docs/schemas/sagan-context-concentrator-report-v1.schema.json
new file mode 100644
index 000000000..2ccc390dc
--- /dev/null
+++ b/docs/schemas/sagan-context-concentrator-report-v1.schema.json
@@ -0,0 +1,311 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://labview-community-ci-cd.github.io/compare-vi-cli-action/schemas/sagan-context-concentrator-report-v1.schema.json",
+ "title": "Sagan Context Concentrator Report v1",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "repository",
+ "inputs",
+ "sources",
+ "focus",
+ "memory",
+ "episodes",
+ "cost",
+ "summary"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/sagan-context-concentrator-report@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "repository": {
+ "type": ["string", "null"]
+ },
+ "inputs": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "priorityCachePath",
+ "governorSummaryPath",
+ "governorPortfolioSummaryPath",
+ "monitoringModePath",
+ "operatorSteeringEventPath",
+ "episodeDirectoryPath"
+ ],
+ "properties": {
+ "priorityCachePath": { "type": ["string", "null"] },
+ "governorSummaryPath": { "type": ["string", "null"] },
+ "governorPortfolioSummaryPath": { "type": ["string", "null"] },
+ "monitoringModePath": { "type": ["string", "null"] },
+ "operatorSteeringEventPath": { "type": ["string", "null"] },
+ "episodeDirectoryPath": { "type": ["string", "null"] }
+ }
+ },
+ "sources": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "priorityCache",
+ "governorSummary",
+ "governorPortfolioSummary",
+ "monitoringMode",
+ "operatorSteeringEvent",
+ "episodeDirectory"
+ ],
+ "properties": {
+ "priorityCache": { "$ref": "#/$defs/sourcePathState" },
+ "governorSummary": { "$ref": "#/$defs/sourcePathState" },
+ "governorPortfolioSummary": { "$ref": "#/$defs/sourcePathState" },
+ "monitoringMode": { "$ref": "#/$defs/sourcePathState" },
+ "operatorSteeringEvent": { "$ref": "#/$defs/sourcePathState" },
+ "episodeDirectory": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["path", "exists", "fileCount", "validEpisodeCount", "invalidEpisodeCount"],
+ "properties": {
+ "path": { "type": ["string", "null"] },
+ "exists": { "type": "boolean" },
+ "fileCount": { "type": "integer", "minimum": 0 },
+ "validEpisodeCount": { "type": "integer", "minimum": 0 },
+ "invalidEpisodeCount": { "type": "integer", "minimum": 0 }
+ }
+ }
+ }
+ },
+ "focus": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "activeIssue",
+ "currentOwnerRepository",
+ "nextOwnerRepository",
+ "nextAction",
+ "governorMode",
+ "monitoringStatus"
+ ],
+ "properties": {
+ "activeIssue": {
+ "type": ["object", "null"],
+ "additionalProperties": false,
+ "required": ["number", "title", "url", "state", "repository"],
+ "properties": {
+ "number": { "type": "integer", "minimum": 1 },
+ "title": { "type": ["string", "null"] },
+ "url": { "type": ["string", "null"] },
+ "state": { "type": ["string", "null"] },
+ "repository": { "type": ["string", "null"] }
+ }
+ },
+ "currentOwnerRepository": { "type": ["string", "null"] },
+ "nextOwnerRepository": { "type": ["string", "null"] },
+ "nextAction": { "type": ["string", "null"] },
+ "governorMode": { "type": ["string", "null"] },
+ "monitoringStatus": { "type": ["string", "null"] }
+ }
+ },
+ "memory": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["hotWorkingSet", "warmMemory", "archiveCount"],
+ "properties": {
+ "hotWorkingSet": {
+ "type": "array",
+ "items": { "$ref": "#/$defs/memoryItem" }
+ },
+ "warmMemory": {
+ "type": "array",
+ "items": { "$ref": "#/$defs/memoryItem" }
+ },
+ "archiveCount": { "type": "integer", "minimum": 0 }
+ }
+ },
+ "episodes": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "totalCount",
+ "validCount",
+ "invalidCount",
+ "invalidEpisodes",
+ "byStatus",
+ "byAgent",
+ "recent"
+ ],
+ "properties": {
+ "totalCount": { "type": "integer", "minimum": 0 },
+ "validCount": { "type": "integer", "minimum": 0 },
+ "invalidCount": { "type": "integer", "minimum": 0 },
+ "invalidEpisodes": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["path", "error"],
+ "properties": {
+ "path": { "type": "string" },
+ "error": { "type": "string" }
+ }
+ }
+ },
+ "byStatus": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["status", "count"],
+ "properties": {
+ "status": { "type": "string" },
+ "count": { "type": "integer", "minimum": 0 }
+ }
+ }
+ },
+ "byAgent": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["agentId", "agentName", "count"],
+ "properties": {
+ "agentId": { "type": "string" },
+ "agentName": { "type": ["string", "null"] },
+ "count": { "type": "integer", "minimum": 0 }
+ }
+ }
+ },
+ "recent": {
+ "type": "array",
+ "items": { "$ref": "#/$defs/episodeDigest" }
+ }
+ }
+ },
+ "cost": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "episodeCountWithCost",
+ "tokenUsd",
+ "operatorLaborUsd",
+ "blendedLowerBoundUsd",
+ "observedDurationSeconds"
+ ],
+ "properties": {
+ "episodeCountWithCost": { "type": "integer", "minimum": 0 },
+ "tokenUsd": { "type": "number", "minimum": 0 },
+ "operatorLaborUsd": { "type": "number", "minimum": 0 },
+ "blendedLowerBoundUsd": { "type": "number", "minimum": 0 },
+ "observedDurationSeconds": { "type": "number", "minimum": 0 }
+ }
+ },
+ "summary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status",
+ "concentrationStatus",
+ "currentOwnerRepository",
+ "nextOwnerRepository",
+ "nextAction",
+ "activeIssueNumber",
+ "hotWorkingSetCount",
+ "warmMemoryCount",
+ "archiveCount",
+ "blockerCount",
+ "recentEpisodeCount",
+ "blendedLowerBoundUsd"
+ ],
+ "properties": {
+ "status": { "type": "string", "enum": ["active", "monitoring"] },
+ "concentrationStatus": { "type": "string", "enum": ["pass", "warn", "incomplete"] },
+ "currentOwnerRepository": { "type": ["string", "null"] },
+ "nextOwnerRepository": { "type": ["string", "null"] },
+ "nextAction": { "type": ["string", "null"] },
+ "activeIssueNumber": { "type": ["integer", "null"], "minimum": 1 },
+ "hotWorkingSetCount": { "type": "integer", "minimum": 0 },
+ "warmMemoryCount": { "type": "integer", "minimum": 0 },
+ "archiveCount": { "type": "integer", "minimum": 0 },
+ "blockerCount": { "type": "integer", "minimum": 0 },
+ "recentEpisodeCount": { "type": "integer", "minimum": 0 },
+ "blendedLowerBoundUsd": { "type": "number", "minimum": 0 }
+ }
+ }
+ },
+ "$defs": {
+ "sourcePathState": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["path", "exists"],
+ "properties": {
+ "path": { "type": ["string", "null"] },
+ "exists": { "type": "boolean" }
+ }
+ },
+ "memoryItem": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "kind",
+ "label",
+ "status",
+ "detail",
+ "sourcePath",
+ "updatedAt",
+ "issueNumber",
+ "repository",
+ "agentName",
+ "nextAction"
+ ],
+ "properties": {
+ "id": { "type": ["string", "null"] },
+ "kind": { "type": ["string", "null"] },
+ "label": { "type": ["string", "null"] },
+ "status": { "type": ["string", "null"] },
+ "detail": { "type": ["string", "null"] },
+ "sourcePath": { "type": ["string", "null"] },
+ "updatedAt": { "type": ["string", "null"] },
+ "issueNumber": { "type": ["integer", "null"], "minimum": 1 },
+ "repository": { "type": ["string", "null"] },
+ "agentName": { "type": ["string", "null"] },
+ "nextAction": { "type": ["string", "null"] }
+ }
+ },
+ "episodeDigest": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "episodeId",
+ "generatedAt",
+ "agentId",
+ "agentName",
+ "agentRole",
+ "status",
+ "taskSummary",
+ "nextAction",
+ "blocker",
+ "executionPlane",
+ "dockerLaneId",
+ "sourcePath"
+ ],
+ "properties": {
+ "episodeId": { "type": ["string", "null"] },
+ "generatedAt": { "type": ["string", "null"] },
+ "agentId": { "type": ["string", "null"] },
+ "agentName": { "type": ["string", "null"] },
+ "agentRole": { "type": ["string", "null"] },
+ "status": { "type": ["string", "null"] },
+ "taskSummary": { "type": ["string", "null"] },
+ "nextAction": { "type": ["string", "null"] },
+ "blocker": { "type": ["string", "null"] },
+ "executionPlane": { "type": ["string", "null"] },
+ "dockerLaneId": { "type": ["string", "null"] },
+ "sourcePath": { "type": ["string", "null"] }
+ }
+ }
+ }
+}
diff --git a/docs/schemas/subagent-episode-report-v1.schema.json b/docs/schemas/subagent-episode-report-v1.schema.json
new file mode 100644
index 000000000..1636a936c
--- /dev/null
+++ b/docs/schemas/subagent-episode-report-v1.schema.json
@@ -0,0 +1,121 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://labview-community-ci-cd.github.io/compare-vi-cli-action/schemas/subagent-episode-report-v1.schema.json",
+ "title": "Subagent Episode Report v1",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "generatedAt",
+ "repository",
+ "inputs",
+ "episodeId",
+ "agent",
+ "task",
+ "execution",
+ "summary",
+ "evidence",
+ "cost"
+ ],
+ "properties": {
+ "schema": {
+ "const": "priority/subagent-episode-report@v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "repository": {
+ "type": ["string", "null"]
+ },
+ "inputs": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["sourcePath"],
+ "properties": {
+ "sourcePath": {
+ "type": ["string", "null"]
+ }
+ }
+ },
+ "episodeId": {
+ "type": "string",
+ "minLength": 1
+ },
+ "agent": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["id", "name", "role", "model"],
+ "properties": {
+ "id": { "type": ["string", "null"] },
+ "name": { "type": ["string", "null"] },
+ "role": { "type": ["string", "null"] },
+ "model": { "type": ["string", "null"] }
+ }
+ },
+ "task": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["summary", "class", "issueNumber", "issueUrl"],
+ "properties": {
+ "summary": { "type": "string", "minLength": 1 },
+ "class": { "type": ["string", "null"] },
+ "issueNumber": { "type": ["integer", "null"], "minimum": 1 },
+ "issueUrl": { "type": ["string", "null"] }
+ }
+ },
+ "execution": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["status", "lane", "branch", "executionPlane", "dockerLaneId", "hostCapabilityLeaseId"],
+ "properties": {
+ "status": { "type": "string", "minLength": 1 },
+ "lane": { "type": ["string", "null"] },
+ "branch": { "type": ["string", "null"] },
+ "executionPlane": { "type": ["string", "null"] },
+ "dockerLaneId": { "type": ["string", "null"] },
+ "hostCapabilityLeaseId": { "type": ["string", "null"] }
+ }
+ },
+ "summary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["status", "outcome", "blocker", "nextAction", "detail"],
+ "properties": {
+ "status": { "type": "string", "minLength": 1 },
+ "outcome": { "type": ["string", "null"] },
+ "blocker": { "type": ["string", "null"] },
+ "nextAction": { "type": ["string", "null"] },
+ "detail": { "type": ["string", "null"] }
+ }
+ },
+ "evidence": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["filesTouched", "receipts", "commands", "notes"],
+ "properties": {
+ "filesTouched": { "$ref": "#/$defs/stringArray" },
+ "receipts": { "$ref": "#/$defs/stringArray" },
+ "commands": { "$ref": "#/$defs/stringArray" },
+ "notes": { "$ref": "#/$defs/stringArray" }
+ }
+ },
+ "cost": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["observedDurationSeconds", "tokenUsd", "operatorLaborUsd", "blendedLowerBoundUsd"],
+ "properties": {
+ "observedDurationSeconds": { "type": ["number", "null"] },
+ "tokenUsd": { "type": ["number", "null"] },
+ "operatorLaborUsd": { "type": ["number", "null"] },
+ "blendedLowerBoundUsd": { "type": ["number", "null"] }
+ }
+ }
+ },
+ "$defs": {
+ "stringArray": {
+ "type": "array",
+ "items": { "type": "string" }
+ }
+ }
+}
diff --git a/fixtures/teststand-session/session-index.dual-plane-parity.json b/fixtures/teststand-session/session-index.dual-plane-parity.json
new file mode 100644
index 000000000..3370a0a02
--- /dev/null
+++ b/fixtures/teststand-session/session-index.dual-plane-parity.json
@@ -0,0 +1,202 @@
+{
+ "schema": "teststand-compare-session/v2",
+ "at": "2026-03-24T00:30:00.000Z",
+ "suiteClass": "dual-plane-parity",
+ "primaryPlane": "native-labview-2026-64",
+ "requestedSimultaneous": true,
+ "warmup": {
+ "mode": "skip",
+ "events": null
+ },
+ "compare": {
+ "events": "planes/x64/compare/compare-events.ndjson",
+ "capture": "planes/x64/compare/lvcompare-capture.json",
+ "report": true,
+ "command": "LabVIEWCLI64 CreateComparisonReport",
+ "cliPath": "C:/Program Files (x86)/National Instruments/Shared/LabVIEW CLI/LabVIEWCLI.exe",
+ "policy": "cli-only",
+ "mode": "labview-cli",
+ "autoCli": false,
+ "sameName": false,
+ "timeoutSeconds": 600
+ },
+ "outcome": {
+ "exitCode": 0,
+ "seconds": 9.2,
+ "command": "LabVIEWCLI64 CreateComparisonReport",
+ "diff": false
+ },
+ "error": null,
+ "executionCell": {
+ "cellId": "exec-cell-sagan-01",
+ "leaseId": "lease-sagan-01",
+ "leasePath": "tests/results/_agent/runtime/execution-cell-sagan-01.json",
+ "agentId": "sagan",
+ "agentClass": "sagan",
+ "cellClass": "kernel-coordinator",
+ "suiteClass": "dual-plane-parity",
+ "planeBinding": "dual-plane-parity",
+ "runtimeSurface": "windows-native-teststand",
+ "premiumSaganMode": false,
+ "operatorAuthorizationRef": null,
+ "workingRoot": "tests/results/teststand-session",
+ "artifactRoot": "tests/results/teststand-session",
+ "isolatedLaneGroupId": "host-os-fingerprint:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
+ "hostOsFingerprintSha256": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
+ },
+ "harnessInstance": {
+ "harnessKind": "teststand-compare-harness",
+ "instanceId": "ts-harness-sagan-01",
+ "role": "coordinator",
+ "processModelClass": "parallel-process-model",
+ "planeBinding": "dual-plane-parity",
+ "parentInstanceId": null
+ },
+ "processModel": {
+ "runtimeSurface": "windows-native-teststand",
+ "processModelClass": "parallel-process-model",
+ "windowsOnly": true,
+ "rootHarnessInstanceId": "ts-harness-sagan-01",
+ "planeCount": 2
+ },
+ "planes": {
+ "x64": {
+ "plane": "native-labview-2026-64",
+ "architecture": "64-bit",
+ "labviewExePath": "C:/Program Files/National Instruments/LabVIEW 2026/LabVIEW.exe",
+ "outputRoot": "planes/x64",
+ "warmup": {
+ "mode": "skip",
+ "events": null
+ },
+ "compare": {
+ "events": "planes/x64/compare/compare-events.ndjson",
+ "capture": "planes/x64/compare/lvcompare-capture.json",
+ "report": true,
+ "command": "LabVIEWCLI64 CreateComparisonReport",
+ "cliPath": "C:/Program Files (x86)/National Instruments/Shared/LabVIEW CLI/LabVIEWCLI.exe",
+ "policy": "cli-only",
+ "mode": "labview-cli",
+ "autoCli": false,
+ "sameName": false,
+ "timeoutSeconds": 600
+ },
+ "outcome": {
+ "exitCode": 0,
+ "seconds": 9.2,
+ "command": "LabVIEWCLI64 CreateComparisonReport",
+ "diff": false
+ },
+ "error": null,
+ "exitCode": 0,
+ "executionCell": {
+ "cellId": "exec-cell-sagan-01",
+ "leaseId": "lease-sagan-01",
+ "leasePath": "tests/results/_agent/runtime/execution-cell-sagan-01.json",
+ "agentId": "sagan",
+ "agentClass": "sagan",
+ "cellClass": "kernel-coordinator",
+ "suiteClass": "dual-plane-parity",
+ "planeBinding": "native-labview-2026-64",
+ "runtimeSurface": "windows-native-teststand",
+ "premiumSaganMode": false,
+ "operatorAuthorizationRef": null,
+ "workingRoot": "tests/results/teststand-session/planes/x64",
+ "artifactRoot": "tests/results/teststand-session/planes/x64",
+ "isolatedLaneGroupId": "host-os-fingerprint:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
+ "hostOsFingerprintSha256": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
+ },
+ "harnessInstance": {
+ "harnessKind": "teststand-compare-harness",
+ "instanceId": "ts-harness-sagan-01-x64",
+ "role": "plane-child",
+ "processModelClass": "parallel-process-model",
+ "planeBinding": "native-labview-2026-64",
+ "parentInstanceId": "ts-harness-sagan-01"
+ },
+ "processModel": {
+ "runtimeSurface": "windows-native-teststand",
+ "processModelClass": "parallel-process-model",
+ "windowsOnly": true,
+ "rootHarnessInstanceId": "ts-harness-sagan-01",
+ "planeCount": 2
+ }
+ },
+ "x32": {
+ "plane": "native-labview-2026-32",
+ "architecture": "32-bit",
+ "labviewExePath": "C:/Program Files (x86)/National Instruments/LabVIEW 2026/LabVIEW.exe",
+ "outputRoot": "planes/x32",
+ "warmup": {
+ "mode": "skip",
+ "events": null
+ },
+ "compare": {
+ "events": "planes/x32/compare/compare-events.ndjson",
+ "capture": "planes/x32/compare/lvcompare-capture.json",
+ "report": true,
+ "command": "LabVIEWCLI32 CreateComparisonReport",
+ "cliPath": "C:/Program Files (x86)/National Instruments/Shared/LabVIEW CLI/LabVIEWCLI.exe",
+ "policy": "cli-only",
+ "mode": "labview-cli",
+ "autoCli": false,
+ "sameName": false,
+ "timeoutSeconds": 600
+ },
+ "outcome": {
+ "exitCode": 0,
+ "seconds": 9.8,
+ "command": "LabVIEWCLI32 CreateComparisonReport",
+ "diff": false
+ },
+ "error": null,
+ "exitCode": 0,
+ "executionCell": {
+ "cellId": "exec-cell-sagan-01",
+ "leaseId": "lease-sagan-01",
+ "leasePath": "tests/results/_agent/runtime/execution-cell-sagan-01.json",
+ "agentId": "sagan",
+ "agentClass": "sagan",
+ "cellClass": "kernel-coordinator",
+ "suiteClass": "dual-plane-parity",
+ "planeBinding": "native-labview-2026-32",
+ "runtimeSurface": "windows-native-teststand",
+ "premiumSaganMode": false,
+ "operatorAuthorizationRef": null,
+ "workingRoot": "tests/results/teststand-session/planes/x32",
+ "artifactRoot": "tests/results/teststand-session/planes/x32",
+ "isolatedLaneGroupId": "host-os-fingerprint:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
+ "hostOsFingerprintSha256": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
+ },
+ "harnessInstance": {
+ "harnessKind": "teststand-compare-harness",
+ "instanceId": "ts-harness-sagan-01-x32",
+ "role": "plane-child",
+ "processModelClass": "parallel-process-model",
+ "planeBinding": "native-labview-2026-32",
+ "parentInstanceId": "ts-harness-sagan-01"
+ },
+ "processModel": {
+ "runtimeSurface": "windows-native-teststand",
+ "processModelClass": "parallel-process-model",
+ "windowsOnly": true,
+ "rootHarnessInstanceId": "ts-harness-sagan-01",
+ "planeCount": 2
+ }
+ }
+ },
+ "parity": {
+ "status": "match",
+ "comparedFields": [
+ "outcome.exitCode",
+ "outcome.diff",
+ "compare.report",
+ "compare.mode",
+ "compare.policy"
+ ],
+ "exitCodeParity": true,
+ "diffParity": true,
+ "mismatchCount": 0,
+ "mismatches": []
+ }
+}
diff --git a/fixtures/teststand-session/session-index.json b/fixtures/teststand-session/session-index.json
index 26eae5343..48a13acc4 100644
--- a/fixtures/teststand-session/session-index.json
+++ b/fixtures/teststand-session/session-index.json
@@ -54,5 +54,37 @@
"command": "lvcompare --diff --nobdcosm --nofppos --noattr --out compare-report.html VI1.vi VI2.vi",
"diff": false
},
- "error": null
+ "error": null,
+ "executionCell": {
+ "cellId": "exec-cell-hooke-01",
+ "leaseId": "lease-hooke-01",
+ "leasePath": "tests/results/_agent/runtime/execution-cell-hooke-01.json",
+ "agentId": "hooke",
+ "agentClass": "subagent",
+ "cellClass": "worker",
+ "suiteClass": "single-compare",
+ "planeBinding": "native-labview-2025-64",
+ "runtimeSurface": "windows-native-teststand",
+ "premiumSaganMode": false,
+ "operatorAuthorizationRef": null,
+ "workingRoot": "tests/results/teststand-session",
+ "artifactRoot": "tests/results/teststand-session",
+ "isolatedLaneGroupId": "host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+ "hostOsFingerprintSha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+ },
+ "harnessInstance": {
+ "harnessKind": "teststand-compare-harness",
+ "instanceId": "ts-harness-hooke-01",
+ "role": "single-plane",
+ "processModelClass": "sequential-process-model",
+ "planeBinding": "native-labview-2025-64",
+ "parentInstanceId": null
+ },
+ "processModel": {
+ "runtimeSurface": "windows-native-teststand",
+ "processModelClass": "sequential-process-model",
+ "windowsOnly": true,
+ "rootHarnessInstanceId": "ts-harness-hooke-01",
+ "planeCount": 1
+ }
}
diff --git a/package-lock.json b/package-lock.json
index bd19b367e..1fa871b76 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "compare-vi-cli-action",
- "version": "0.6.3",
+ "version": "0.6.4-rc.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "compare-vi-cli-action",
- "version": "0.6.3",
+ "version": "0.6.4-rc.1",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
diff --git a/package.json b/package.json
index cb1e0dcee..a87f9e0e7 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "compare-vi-cli-action",
"private": true,
- "version": "0.6.4-rc.1",
+ "version": "0.6.4-rc.2",
"license": "MIT",
"type": "module",
"scripts": {
@@ -87,6 +87,8 @@
"priority:monitoring:mode": "node tools/priority/handoff-monitoring-mode.mjs",
"priority:governor:summary": "node tools/priority/autonomous-governor-summary.mjs",
"priority:governor:portfolio": "node tools/priority/autonomous-governor-portfolio-summary.mjs",
+ "priority:subagent:episode": "node tools/priority/subagent-episode.mjs",
+ "priority:context:concentrate": "node tools/priority/sagan-context-concentrator.mjs",
"priority:monitoring:inject-work": "node tools/priority/monitoring-work-injection.mjs",
"priority:wake:adjudicate": "node tools/priority/wake-adjudication.mjs",
"priority:wake:accounting": "node tools/priority/wake-investment-accounting.mjs",
@@ -97,6 +99,9 @@
"priority:lease": "node tools/priority/agent-writer-lease.mjs",
"priority:continuity": "node tools/priority/continuity-telemetry.mjs",
"priority:lane:marketplace": "node tools/priority/lane-marketplace.mjs",
+ "priority:lane:docker:handshake": "node tools/priority/docker-lane-handshake.mjs",
+ "priority:lane:execution-cell": "node tools/priority/execution-cell-lease.mjs",
+ "priority:lane:execution-cell:bundle": "node tools/priority/execution-cell-bundle.mjs",
"priority:lane:concurrency:plan": "node tools/priority/concurrent-lane-plan.mjs",
"priority:lane:concurrency:apply": "node tools/priority/concurrent-lane-apply.mjs",
"priority:lane:concurrency:status": "node tools/priority/concurrent-lane-status.mjs",
@@ -128,6 +133,8 @@
"priority:throughput:scorecard": "node tools/priority/throughput-scorecard.mjs",
"priority:release:cadence": "node tools/priority/release-cadence-check.mjs",
"priority:release:conductor": "node tools/priority/release-conductor.mjs",
+ "priority:release:signing:readiness": "node tools/priority/release-signing-readiness.mjs",
+ "priority:release:published:bundle": "node tools/priority/release-published-bundle-observer.mjs",
"priority:remediation:slo": "node tools/priority/remediation-slo-evaluator.mjs",
"priority:weekly:scorecard": "node tools/priority/weekly-scorecard.mjs",
"priority:security:audit": "node tools/priority/dependency-audit.mjs",
@@ -139,6 +146,7 @@
"priority:cost:turn": "node tools/priority/agent-cost-turn.mjs",
"priority:cost:rollup": "node tools/priority/agent-cost-rollup.mjs",
"priority:cost:rollup:materialize": "node tools/priority/materialize-agent-cost-rollup.mjs",
+ "priority:cost:comment-hook": "node tools/priority/github-comment-budget-hook.mjs",
"priority:cost:pr-spend": "node tools/priority/pr-spend-projection.mjs",
"priority:model:select": "node tools/priority/live-agent-model-selection.mjs",
"priority:onboard:downstream": "node tools/priority/downstream-onboarding.mjs",
@@ -236,7 +244,7 @@
"session-index:test": "node tools/npm/run-script.mjs build && node --test src/session-index/__tests__/*.test.mjs",
"session-index:v2-contract": "pwsh -NoLogo -NoProfile -File tools/Test-SessionIndexV2Contract.ps1",
"session-index:validate": "node tools/npm/run-script.mjs schema:validate -- --schema docs/schema/generated/session-index-v2.schema.json --data tests/results/_agent/session-index-v2-sample.json --optional",
- "session:teststand:validate": "node tools/npm/run-script.mjs schema:validate -- --schema docs/schema/generated/teststand-compare-session.schema.json --data fixtures/teststand-session/session-index.json --data tests/results/teststand-session/session-index.json --optional",
+ "session:teststand:validate": "node tools/npm/run-script.mjs schema:validate -- --schema docs/schema/generated/teststand-compare-session.schema.json --data fixtures/teststand-session/session-index.json --data fixtures/teststand-session/session-index.dual-plane-parity.json --data tests/results/teststand-session/session-index.json --optional",
"smoke:vi-history": "pwsh -NoLogo -NoProfile -File tools/Test-PRVIHistorySmoke.ps1",
"smoke:vi-stage": "pwsh -NoLogo -NoProfile -File tools/Test-PRVIStagingSmoke.ps1",
"tests:comparevi": "pwsh -NoLogo -NoProfile -File Invoke-PesterTests.ps1 -IncludePatterns CompareVI*",
diff --git a/scripts/Run-AutonomousIntegrationLoop.ps1 b/scripts/Run-AutonomousIntegrationLoop.ps1
index f0638bf7e..2dd5292d9 100644
--- a/scripts/Run-AutonomousIntegrationLoop.ps1
+++ b/scripts/Run-AutonomousIntegrationLoop.ps1
@@ -138,13 +138,22 @@ param(
, [string]$TestStandHarnessPath = $env:LOOP_TESTSTAND_HARNESS_PATH
, [string]$TestStandOutputRoot = $env:LOOP_TESTSTAND_OUTPUT_ROOT
, [ValidateSet('detect','spawn','skip')][string]$TestStandWarmup = $( if ($env:LOOP_TESTSTAND_WARMUP) { $env:LOOP_TESTSTAND_WARMUP } else { 'skip' } )
+ , [ValidateSet('single-compare','dual-plane-parity')][string]$TestStandSuiteClass = $( if ($env:LOOP_TESTSTAND_SUITE_CLASS) { $env:LOOP_TESTSTAND_SUITE_CLASS } else { 'single-compare' } )
, [switch]$TestStandRenderReport
, [switch]$TestStandCloseLabVIEW
, [switch]$TestStandCloseLVCompare
, [int]$TestStandTimeoutSeconds = ($env:LOOP_TESTSTAND_TIMEOUT_SECONDS -as [int])
, [switch]$TestStandDisableTimeout
, [string]$TestStandLabVIEWPath = $env:LOOP_TESTSTAND_LABVIEW_PATH
+, [string]$TestStandLabVIEW64Path = $env:LOOP_TESTSTAND_LABVIEW64_PATH
+, [string]$TestStandLabVIEW32Path = $env:LOOP_TESTSTAND_LABVIEW32_PATH
, [string]$TestStandLVComparePath = $env:LOOP_TESTSTAND_LVCOMPARE_PATH
+, [string]$TestStandAgentId = $env:LOOP_TESTSTAND_AGENT_ID
+, [string]$TestStandAgentClass = $env:LOOP_TESTSTAND_AGENT_CLASS
+, [string]$TestStandExecutionCellLeasePath = $env:LOOP_TESTSTAND_EXECUTION_CELL_LEASE_PATH
+, [string]$TestStandExecutionCellId = $env:LOOP_TESTSTAND_EXECUTION_CELL_ID
+, [string]$TestStandExecutionCellLeaseId = $env:LOOP_TESTSTAND_EXECUTION_CELL_LEASE_ID
+, [string]$TestStandHarnessInstanceId = $env:LOOP_TESTSTAND_HARNESS_INSTANCE_ID
, [switch]$TestStandReplaceFlags
)
@@ -154,6 +163,62 @@ function Set-LoopExit {
exit $Code
}
+function Get-ExecutionCellLeaseMetadata {
+ param([string]$LeasePath)
+
+ $metadata = [ordered]@{
+ cellClass = $null
+ suiteClass = $null
+ operatorAuthorizationRef = $null
+ premiumSaganMode = $false
+ }
+
+ if ([string]::IsNullOrWhiteSpace($LeasePath)) {
+ return [pscustomobject]$metadata
+ }
+
+ try {
+ $resolvedLeasePath = (Resolve-Path -LiteralPath $LeasePath -ErrorAction Stop).Path
+ $payload = Get-Content -LiteralPath $resolvedLeasePath -Raw | ConvertFrom-Json -ErrorAction Stop
+ $summary = if ($payload -and $payload.PSObject.Properties.Name -contains 'summary') { $payload.summary } else { $null }
+ $lease = if ($payload -and $payload.PSObject.Properties.Name -contains 'lease') { $payload.lease } else { $null }
+ $request = if ($lease -and $lease.PSObject.Properties.Name -contains 'request') { $lease.request } else { $null }
+ $grant = if ($lease -and $lease.PSObject.Properties.Name -contains 'grant') { $lease.grant } else { $null }
+
+ $summaryCellClass = if ($summary) { $summary.cellClass } else { $null }
+ $requestCellClass = if ($request) { $request.cellClass } else { $null }
+ foreach ($candidate in @($summaryCellClass, $requestCellClass)) {
+ if (-not [string]::IsNullOrWhiteSpace($candidate)) {
+ $metadata.cellClass = [string]$candidate
+ break
+ }
+ }
+ $summarySuiteClass = if ($summary) { $summary.suiteClass } else { $null }
+ $requestSuiteClass = if ($request) { $request.suiteClass } else { $null }
+ foreach ($candidate in @($summarySuiteClass, $requestSuiteClass)) {
+ if (-not [string]::IsNullOrWhiteSpace($candidate)) {
+ $metadata.suiteClass = [string]$candidate
+ break
+ }
+ }
+ $summaryOperatorAuthorizationRef = if ($summary) { $summary.operatorAuthorizationRef } else { $null }
+ $requestOperatorAuthorizationRef = if ($request) { $request.operatorAuthorizationRef } else { $null }
+ foreach ($candidate in @($summaryOperatorAuthorizationRef, $requestOperatorAuthorizationRef)) {
+ if (-not [string]::IsNullOrWhiteSpace($candidate)) {
+ $metadata.operatorAuthorizationRef = [string]$candidate
+ break
+ }
+ }
+ if ($summary -and $summary.PSObject.Properties.Name -contains 'premiumSaganMode') {
+ $metadata.premiumSaganMode = [bool]$summary.premiumSaganMode
+ } elseif ($grant -and $grant.PSObject.Properties.Name -contains 'premiumSaganMode') {
+ $metadata.premiumSaganMode = [bool]$grant.premiumSaganMode
+ }
+ } catch {}
+
+ return [pscustomobject]$metadata
+}
+
# Defaults / fallbacks
if (-not $MaxIterations) { $MaxIterations = 1 }
if ($null -eq $IntervalSeconds) { $IntervalSeconds = 0 }
@@ -277,8 +342,17 @@ if ($UseTestStandHarness) {
$disableTimeout = [bool]$TestStandDisableTimeout
$timeoutValue = if ($PSBoundParameters.ContainsKey('TestStandTimeoutSeconds') -or $env:LOOP_TESTSTAND_TIMEOUT_SECONDS) { $TestStandTimeoutSeconds } else { $null }
$labviewPath = $TestStandLabVIEWPath
+ $labview64Path = $TestStandLabVIEW64Path
+ $labview32Path = $TestStandLabVIEW32Path
$lvcomparePath = $TestStandLVComparePath
$replaceFlags = [bool]$TestStandReplaceFlags
+ $executionCellLeasePath = $TestStandExecutionCellLeasePath
+ $executionCellId = $TestStandExecutionCellId
+ $executionCellLeaseId = $TestStandExecutionCellLeaseId
+ $executionCellLeaseMetadata = Get-ExecutionCellLeaseMetadata -LeasePath $executionCellLeasePath
+ $agentId = $TestStandAgentId
+ $agentClass = $TestStandAgentClass
+ $harnessInstanceId = $TestStandHarnessInstanceId
$harnessIteration = [ref]0
$executor = {
@@ -298,7 +372,16 @@ if ($UseTestStandHarness) {
Warmup = $warmupMode
}
if ($labviewPath) { $harnessParams.LabVIEWExePath = $labviewPath }
+ if ($labview64Path) { $harnessParams.LabVIEW64ExePath = $labview64Path }
+ if ($labview32Path) { $harnessParams.LabVIEW32ExePath = $labview32Path }
if ($lvcomparePath) { $harnessParams.LVComparePath = $lvcomparePath }
+ if ($TestStandSuiteClass -ne 'single-compare') { $harnessParams.SuiteClass = $TestStandSuiteClass }
+ if ($agentId) { $harnessParams.AgentId = $agentId }
+ if ($agentClass) { $harnessParams.AgentClass = $agentClass }
+ if ($executionCellLeasePath) { $harnessParams.ExecutionCellLeasePath = $executionCellLeasePath }
+ if ($executionCellId) { $harnessParams.ExecutionCellId = $executionCellId }
+ if ($executionCellLeaseId) { $harnessParams.ExecutionCellLeaseId = $executionCellLeaseId }
+ if ($harnessInstanceId) { $harnessParams.HarnessInstanceId = $harnessInstanceId }
if ($renderReport) { $harnessParams.RenderReport = $true }
if ($closeLabVIEW) { $harnessParams.CloseLabVIEW = $true }
if ($closeLVCompare) { $harnessParams.CloseLVCompare = $true }
@@ -344,11 +427,28 @@ if ($UseTestStandHarness) {
path = $resolvedHarness
output = $resolvedOutputRoot
warmup = $warmupMode
+ suiteClass = $TestStandSuiteClass
+ runtimeSurface = 'windows-native-teststand'
+ processModelClass = if ($TestStandSuiteClass -eq 'dual-plane-parity') { 'parallel-process-model' } else { 'sequential-process-model' }
+ windowsOnly = $true
+ requestedSimultaneous = ($TestStandSuiteClass -eq 'dual-plane-parity')
renderReport = $renderReport
closeLabVIEW = $closeLabVIEW
closeLVCompare = $closeLVCompare
disableTimeout = $disableTimeout
timeout = $timeoutValue
+ labviewPath = $labviewPath
+ labview64Path = $labview64Path
+ labview32Path = $labview32Path
+ agentId = $agentId
+ agentClass = $agentClass
+ cellClass = $executionCellLeaseMetadata.cellClass
+ operatorAuthorizationRef = $executionCellLeaseMetadata.operatorAuthorizationRef
+ premiumSaganMode = [bool]$executionCellLeaseMetadata.premiumSaganMode
+ executionCellLeasePath = $executionCellLeasePath
+ executionCellId = $executionCellId
+ executionCellLeaseId = $executionCellLeaseId
+ harnessInstanceId = $harnessInstanceId
}
}
@@ -453,6 +553,8 @@ function Invoke-LabVIEWCloser {
}
}
+$shouldCloseLabVIEW = (-not $UseTestStandHarness) -and (-not $executor)
+
function Ensure-JsonLog {
param([string]$Path)
if (-not $Path) { return }
@@ -517,6 +619,9 @@ if ($UseTestStandHarness -and $harnessPlan) {
$planPayload.harnessOutput = $harnessPlan.output
$planPayload.harnessWarmup = $harnessPlan.warmup
$planPayload.harnessRenderReport = $harnessPlan.renderReport
+ $planPayload.harnessRuntimeSurface = $harnessPlan.runtimeSurface
+ $planPayload.harnessProcessModelClass = $harnessPlan.processModelClass
+ $planPayload.harnessRequestedSimultaneous = $harnessPlan.requestedSimultaneous
}
Write-JsonEvent 'plan' $planPayload
@@ -533,6 +638,8 @@ if ($DryRun) {
if ($UseTestStandHarness -and $harnessPlan) {
$dryRunPayload.harnessPath = $harnessPlan.path
$dryRunPayload.harnessOutput = $harnessPlan.output
+ $dryRunPayload.harnessRuntimeSurface = $harnessPlan.runtimeSurface
+ $dryRunPayload.harnessProcessModelClass = $harnessPlan.processModelClass
}
Write-JsonEvent 'dryRun' $dryRunPayload
Set-LoopExit 0
@@ -541,7 +648,9 @@ if ($DryRun) {
try {
$result = Invoke-IntegrationCompareLoop @invokeParams
} catch {
- Invoke-LabVIEWCloser -Context 'invoke-exception'
+ if ($shouldCloseLabVIEW) {
+ Invoke-LabVIEWCloser -Context 'invoke-exception'
+ }
throw
}
Write-JsonEvent 'result' (@{ iterations=$result.Iterations; diffs=$result.DiffCount; errors=$result.ErrorCount; succeeded=$result.Succeeded })
@@ -564,6 +673,24 @@ if ($FinalStatusJsonPath) {
basePath = $result.BasePath
headPath = $result.HeadPath
}
+ if ($UseTestStandHarness -and $harnessPlan) {
+ $obj.harness = [ordered]@{
+ path = $harnessPlan.path
+ output = $harnessPlan.output
+ suiteClass = $harnessPlan.suiteClass
+ runtimeSurface = $harnessPlan.runtimeSurface
+ processModelClass = $harnessPlan.processModelClass
+ windowsOnly = $harnessPlan.windowsOnly
+ requestedSimultaneous = $harnessPlan.requestedSimultaneous
+ cellClass = $harnessPlan.cellClass
+ operatorAuthorizationRef = $harnessPlan.operatorAuthorizationRef
+ premiumSaganMode = $harnessPlan.premiumSaganMode
+ executionCellLeasePath = $harnessPlan.executionCellLeasePath
+ executionCellId = $harnessPlan.executionCellId
+ executionCellLeaseId = $harnessPlan.executionCellLeaseId
+ harnessInstanceId = $harnessPlan.harnessInstanceId
+ }
+ }
$json = $obj | ConvertTo-Json -Depth 5
$finalDir = Split-Path -Parent $FinalStatusJsonPath
if ($finalDir -and -not (Test-Path $finalDir)) { New-Item -ItemType Directory -Path $finalDir | Out-Null }
@@ -595,7 +722,9 @@ if (-not $NoStepSummary -and $env:GITHUB_STEP_SUMMARY -and $result.DiffSummary)
Write-Detail 'Step summary append skipped (suppressed or not in Actions).' 'Debug'
}
-Invoke-LabVIEWCloser -Context 'post-loop'
+if ($shouldCloseLabVIEW) {
+ Invoke-LabVIEWCloser -Context 'post-loop'
+}
# Exit code semantics: 0 when succeeded (even if diffs unless FailOnDiff terminated early), 1 if any errors encountered
if (-not $result.Succeeded) { Set-LoopExit 1 }
diff --git a/tests/AgentHandoff.Local.Tests.ps1 b/tests/AgentHandoff.Local.Tests.ps1
index ddeb5a778..a00415fa3 100644
--- a/tests/AgentHandoff.Local.Tests.ps1
+++ b/tests/AgentHandoff.Local.Tests.ps1
@@ -29,4 +29,23 @@ Describe 'Local Agent Handoff' -Tag 'Unit' {
$planeTransition.schema | Should -Be 'agent-handoff/plane-transition-v1'
$planeTransition.status | Should -Not -BeNullOrEmpty
}
+
+ It 'declares governor execution process-model fields in the handoff printer' {
+ $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
+ $script = Join-Path $repoRoot 'tools' 'Print-AgentHandoff.ps1'
+ Test-Path -LiteralPath $script | Should -BeTrue
+ $content = Get-Content -LiteralPath $script -Raw
+ $content | Should -Match 'execSurf\s*:'
+ $content | Should -Match 'executionTopologyRuntimeSurface'
+ $content | Should -Match 'execProc\s*:'
+ $content | Should -Match 'executionTopologyProcessModelClass'
+ $content | Should -Match 'execSim\s*:'
+ $content | Should -Match 'executionTopologyRequestedSimultaneous'
+ $content | Should -Match 'execCell\s*:'
+ $content | Should -Match 'executionTopologyCellClass'
+ $content | Should -Match 'execSuite\s*:'
+ $content | Should -Match 'executionTopologySuiteClass'
+ $content | Should -Match 'execAuth\s*:'
+ $content | Should -Match 'executionTopologyOperatorAuthorizationRef'
+ }
}
diff --git a/tests/CompareVITools.Artifact.Tests.ps1 b/tests/CompareVITools.Artifact.Tests.ps1
index b1f7384ab..e84f84cc4 100644
--- a/tests/CompareVITools.Artifact.Tests.ps1
+++ b/tests/CompareVITools.Artifact.Tests.ps1
@@ -113,6 +113,18 @@ Describe 'CompareVI.Tools artifact publishing' -Tag 'REQ:DOTNET_CLI_RELEASE_ASSE
$metadata.consumerContract.capabilities.viHistory.contractPaths.hostedNiLinuxRunner | Should -Be 'consumerContract.hostedNiLinuxRunner'
((@($metadata.consumerContract.capabilities.viHistory.notes) -join [Environment]::NewLine)) | Should -Match 'LabviewGitHubCiTemplate'
((@($metadata.consumerContract.capabilities.viHistory.notes) -join [Environment]::NewLine)) | Should -Match 'authoritativeConsumerPin'
+ $metadata.consumerContract.capabilities.dockerProfile.schema | Should -Be 'comparevi-tools/docker-profile-capability@v1'
+ $metadata.consumerContract.capabilities.dockerProfile.capabilityId | Should -Be 'docker-profile'
+ $metadata.consumerContract.capabilities.dockerProfile.displayName | Should -Be 'Docker Profile'
+ $metadata.consumerContract.capabilities.dockerProfile.distributionRole | Should -Be 'upstream-producer'
+ $metadata.consumerContract.capabilities.dockerProfile.distributionModel | Should -Be 'release-bundle'
+ $metadata.consumerContract.capabilities.dockerProfile.bundleMetadataPath | Should -Be 'comparevi-tools-release.json'
+ $metadata.consumerContract.capabilities.dockerProfile.bundleImportPath | Should -Be 'tools/CompareVI.Tools/CompareVI.Tools.psd1'
+ $metadata.consumerContract.capabilities.dockerProfile.releaseAssetPattern | Should -Be 'CompareVI.Tools-v.zip'
+ $metadata.consumerContract.capabilities.dockerProfile.authoritativeConsumerPinFieldPath | Should -Be 'versionContract.authoritativeConsumerPin'
+ $metadata.consumerContract.capabilities.dockerProfile.authoritativeConsumerPinKindFieldPath | Should -Be 'versionContract.authoritativeConsumerPinKind'
+ $metadata.consumerContract.capabilities.dockerProfile.authoritativeImageContractSource | Should -Be 'consumerContract.dockerImageContract'
+ ((@($metadata.consumerContract.capabilities.dockerProfile.notes) -join [Environment]::NewLine)) | Should -Match 'Producer-published Docker image contract'
$metadata.consumerContract.historyFacade.schema | Should -Be 'comparevi-tools/history-facade@v1'
$metadata.consumerContract.historyFacade.exportedFunction | Should -Be 'Invoke-CompareVIHistoryFacade'
$metadata.consumerContract.historyFacade.resultsRelativePath | Should -Be 'history-summary.json'
@@ -163,6 +175,11 @@ Describe 'CompareVI.Tools artifact publishing' -Tag 'REQ:DOTNET_CLI_RELEASE_ASSE
)
$metadata.consumerContract.hostedNiLinuxRunner.captureFileName | Should -Be 'ni-linux-container-capture.json'
$metadata.consumerContract.hostedNiLinuxRunner.defaultImage | Should -Be 'nationalinstruments/labview:2026q1-linux'
+ $metadata.consumerContract.dockerImageContract.schema | Should -Be 'comparevi-tools/docker-image-contract@v1'
+ $metadata.consumerContract.dockerImageContract.schemaUrl | Should -Be 'https://labview-community-ci-cd.github.io/compare-vi-cli-action/schemas/comparevi-tools-docker-image-contract-v1.schema.json'
+ $metadata.consumerContract.dockerImageContract.images.hostedNiLinuxRunner.imageRef | Should -Be 'nationalinstruments/labview:2026q1-linux'
+ $metadata.consumerContract.dockerImageContract.images.hostedNiLinuxRunner.consumerRole | Should -Be 'hosted-ni-linux-runner'
+ ((@($metadata.consumerContract.dockerImageContract.notes) -join [Environment]::NewLine)) | Should -Match 'authoritative Producer-published image contract'
$archivePath = Join-Path $outDir $metadata.bundle.archiveName
Test-Path -LiteralPath $archivePath | Should -BeTrue
@@ -219,6 +236,9 @@ Describe 'CompareVI.Tools artifact publishing' -Tag 'REQ:DOTNET_CLI_RELEASE_ASSE
$archiveMetadata.bundle.files.Count | Should -BeGreaterThan 5
$archiveMetadata.consumerContract.capabilities.viHistory.schema | Should -Be 'comparevi-tools/vi-history-capability@v1'
$archiveMetadata.consumerContract.capabilities.viHistory.contractPaths.historyFacade | Should -Be 'consumerContract.historyFacade'
+ $archiveMetadata.consumerContract.capabilities.dockerProfile.schema | Should -Be 'comparevi-tools/docker-profile-capability@v1'
+ $archiveMetadata.consumerContract.capabilities.dockerProfile.authoritativeImageContractSource | Should -Be 'consumerContract.dockerImageContract'
+ $archiveMetadata.consumerContract.dockerImageContract.images.hostedNiLinuxRunner.imageRef | Should -Be 'nationalinstruments/labview:2026q1-linux'
@($archiveMetadata.bundle.files.path) | Should -Contain 'tools/Build-VIHistoryDevImage.ps1'
@($archiveMetadata.bundle.files.path) | Should -Contain 'tools/Invoke-VIHistoryLocalOperatorSession.ps1'
@($archiveMetadata.bundle.files.path) | Should -Contain 'tools/Invoke-VIHistoryLocalRefinement.ps1'
diff --git a/tests/Import-HandoffState.Tests.ps1 b/tests/Import-HandoffState.Tests.ps1
index 53ee9ba56..70a501d15 100644
--- a/tests/Import-HandoffState.Tests.ps1
+++ b/tests/Import-HandoffState.Tests.ps1
@@ -204,11 +204,63 @@ Describe 'Import-HandoffState' -Tag 'Unit' {
monitoringModePath = 'tests/results/_agent/handoff/monitoring-mode.json'
wakeLifecyclePath = 'tests/results/_agent/issue/wake-lifecycle.json'
wakeInvestmentAccountingPath = 'tests/results/_agent/capital/wake-investment-accounting.json'
+ deliveryRuntimeStatePath = 'tests/results/_agent/runtime/delivery-agent-state.json'
+ releaseSigningReadinessPath = 'tests/results/_agent/release/release-signing-readiness.json'
}
compare = [ordered]@{
queueState = [ordered]@{ status = 'queue-empty'; reason = 'queue-empty'; openIssueCount = 11; ready = $true }
continuity = [ordered]@{ status = 'maintained'; turnBoundary = 'safe-idle'; supervisionState = 'safe-idle'; operatorPromptRequiredToResume = $false }
monitoringMode = [ordered]@{ status = 'active'; futureAgentAction = 'future-agent-may-pivot'; wakeConditionCount = 0 }
+ releaseSigningReadiness = [ordered]@{
+ status = 'warn'
+ codePathState = 'ready'
+ signingCapabilityState = 'missing'
+ publicationState = 'tag-created-not-pushed'
+ publishedBundleState = 'producer-native-incomplete'
+ publishedBundleReleaseTag = 'v0.6.3-tools.14'
+ publishedBundleAuthoritativeConsumerPin = $null
+ externalBlocker = 'workflow-signing-secret-missing'
+ blockerCount = 1
+ }
+ deliveryRuntime = [ordered]@{
+ status = 'none'
+ runtimeStatus = $null
+ laneLifecycle = $null
+ actionType = $null
+ outcome = $null
+ blockerClass = $null
+ nextWakeCondition = $null
+ queueAuthorityRefresh = [ordered]@{
+ attempted = $false
+ status = $null
+ reason = $null
+ summaryPath = $null
+ mergeSummaryPath = $null
+ receiptGeneratedAt = $null
+ receiptStatus = $null
+ receiptReason = $null
+ evidenceFreshness = $null
+ nextWakeCondition = $null
+ mergeStateStatus = $null
+ isInMergeQueue = $null
+ autoMergeEnabled = $null
+ mergedAt = $null
+ }
+ prUrl = $null
+ issueNumber = $null
+ reason = $null
+ }
+ queueAuthority = [ordered]@{
+ status = 'none'
+ source = 'none'
+ nextWakeCondition = $null
+ summaryPath = $null
+ promotionStatus = $null
+ mergeStateStatus = $null
+ isInMergeQueue = $false
+ autoMergeEnabled = $false
+ prUrl = $null
+ }
}
wake = [ordered]@{
terminalState = 'compare-work'
@@ -247,6 +299,16 @@ Describe 'Import-HandoffState' -Tag 'Unit' {
wakeTerminalState = 'compare-work'
monitoringStatus = 'active'
futureAgentAction = 'future-agent-may-pivot'
+ releaseSigningStatus = 'warn'
+ releaseSigningExternalBlocker = 'workflow-signing-secret-missing'
+ releasePublicationState = 'tag-created-not-pushed'
+ releasePublishedBundleState = 'producer-native-incomplete'
+ releasePublishedBundleReleaseTag = 'v0.6.3-tools.14'
+ releasePublishedBundleAuthoritativeConsumerPin = $null
+ queueHandoffStatus = 'none'
+ queueHandoffNextWakeCondition = $null
+ queueHandoffPrUrl = $null
+ queueAuthoritySource = 'none'
}
} | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $handoffDir 'autonomous-governor-summary.json') -Encoding utf8
@@ -255,6 +317,10 @@ Describe 'Import-HandoffState' -Tag 'Unit' {
$output | Should -Match '\[handoff\] Autonomous governor summary'
$output | Should -Match 'mode\s+: compare-governance-work'
$output | Should -Match 'next\s+: continue-compare-governance-work'
+ $output | Should -Match 'release\s+: warn'
+ $output | Should -Match 'blocker\s+: workflow-signing-secret-missing'
+ $output | Should -Match 'bundle\s+: producer-native-incomplete'
+ $output | Should -Match 'bundleTag: v0.6.3-tools.14'
$global:HandoffAutonomousGovernorSummary.schema | Should -Be 'priority/autonomous-governor-summary-report@v1'
Remove-Variable -Name HandoffAutonomousGovernorSummary -Scope Global -ErrorAction SilentlyContinue
@@ -283,10 +349,32 @@ Describe 'Import-HandoffState' -Tag 'Unit' {
futureAgentAction = 'stay-in-compare-monitoring'
governorMode = 'compare-governance-work'
nextAction = 'continue-compare-governance-work'
+ queueHandoffStatus = $null
+ queueHandoffNextWakeCondition = $null
+ queueHandoffPrUrl = $null
+ queueAuthoritySource = $null
}
portfolio = [ordered]@{
repositoryCount = 4
repositories = @()
+ dependencies = @(
+ [ordered]@{
+ id = 'vi-history-producer-native-distributor'
+ status = 'blocked'
+ ownerRepository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ dependentRepository = 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate'
+ requiredCapability = 'vi-history'
+ source = 'compare-release-signing-readiness'
+ releaseSigningStatus = 'warn'
+ releasePublicationState = 'unobserved'
+ publishedBundleState = 'producer-native-incomplete'
+ publishedBundleReleaseTag = 'v0.6.3-tools.14'
+ publishedBundleAuthoritativeConsumerPin = $null
+ signingCapabilityState = 'missing'
+ externalBlocker = 'workflow-signing-secret-missing'
+ detail = 'awaiting-compare-release-signing-blocker-clear'
+ }
+ )
unsupportedPaths = @()
}
summary = [ordered]@{
@@ -299,6 +387,17 @@ Describe 'Import-HandoffState' -Tag 'Unit' {
templateMonitoringStatus = 'pass'
supportedProofStatus = 'pass'
repoGraphStatus = 'pass'
+ queueHandoffStatus = $null
+ queueHandoffNextWakeCondition = $null
+ queueHandoffPrUrl = $null
+ queueAuthoritySource = $null
+ viHistoryDistributorDependencyStatus = 'blocked'
+ viHistoryDistributorDependencyTargetRepository = 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate'
+ viHistoryDistributorDependencyExternalBlocker = 'workflow-signing-secret-missing'
+ viHistoryDistributorDependencyPublicationState = 'unobserved'
+ viHistoryDistributorDependencyPublishedBundleState = 'producer-native-incomplete'
+ viHistoryDistributorDependencyPublishedBundleReleaseTag = 'v0.6.3-tools.14'
+ viHistoryDistributorDependencyAuthoritativeConsumerPin = $null
portfolioWakeConditionCount = 3
triggeredWakeConditions = @(
'compare-queue-not-empty',
@@ -313,8 +412,120 @@ Describe 'Import-HandoffState' -Tag 'Unit' {
$output | Should -Match '\[handoff\] Governor portfolio summary'
$output | Should -Match 'mode\s+: compare-governance-work'
$output | Should -Match 'proof\s+: pass'
+ $output | Should -Match 'vhist\s+: blocked'
+ $output | Should -Match 'vhistRepo: LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate'
+ $output | Should -Match 'vhistBlk : workflow-signing-secret-missing'
+ $output | Should -Match 'vhistPub : producer-native-incomplete'
+ $output | Should -Match 'vhistTag : v0.6.3-tools.14'
$global:HandoffAutonomousGovernorPortfolioSummary.schema | Should -Be 'priority/autonomous-governor-portfolio-summary-report@v1'
Remove-Variable -Name HandoffAutonomousGovernorPortfolioSummary -Scope Global -ErrorAction SilentlyContinue
}
+
+ It 'surfaces context concentrator summary when present' {
+ $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
+ $scriptPath = Join-Path $repoRoot 'tools' 'priority' 'Import-HandoffState.ps1'
+ $handoffDir = Join-Path $TestDrive 'handoff'
+ New-Item -ItemType Directory -Force -Path $handoffDir | Out-Null
+
+ [ordered]@{
+ schema = 'priority/sagan-context-concentrator-report@v1'
+ generatedAt = '2026-03-23T23:25:00Z'
+ repository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ inputs = [ordered]@{
+ priorityCachePath = '.agent_priority_cache.json'
+ governorSummaryPath = 'tests/results/_agent/handoff/autonomous-governor-summary.json'
+ governorPortfolioSummaryPath = 'tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json'
+ monitoringModePath = 'tests/results/_agent/handoff/monitoring-mode.json'
+ operatorSteeringEventPath = 'tests/results/_agent/handoff/operator-steering-event.json'
+ episodeDirectoryPath = 'tests/results/_agent/memory/subagent-episodes'
+ }
+ sources = [ordered]@{
+ priorityCache = [ordered]@{ path = '.agent_priority_cache.json'; exists = $true }
+ governorSummary = [ordered]@{ path = 'tests/results/_agent/handoff/autonomous-governor-summary.json'; exists = $true }
+ governorPortfolioSummary = [ordered]@{ path = 'tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json'; exists = $true }
+ monitoringMode = [ordered]@{ path = 'tests/results/_agent/handoff/monitoring-mode.json'; exists = $true }
+ operatorSteeringEvent = [ordered]@{ path = 'tests/results/_agent/handoff/operator-steering-event.json'; exists = $false }
+ episodeDirectory = [ordered]@{
+ path = 'tests/results/_agent/memory/subagent-episodes'
+ exists = $true
+ fileCount = 2
+ validEpisodeCount = 2
+ invalidEpisodeCount = 0
+ }
+ }
+ focus = [ordered]@{
+ activeIssue = [ordered]@{
+ number = 1909
+ title = '[governor]: build Sagan context concentrator for durable subagent memory'
+ url = 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/issues/1909'
+ state = 'OPEN'
+ repository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ }
+ currentOwnerRepository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ nextOwnerRepository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ nextAction = 'merge concentrator handoff support'
+ governorMode = 'compare-governance-work'
+ monitoringStatus = 'active'
+ }
+ memory = [ordered]@{
+ hotWorkingSet = @(
+ [ordered]@{
+ id = 'issue-1909'
+ kind = 'active-issue'
+ label = '#1909: [governor]: build Sagan context concentrator for durable subagent memory'
+ status = 'OPEN'
+ detail = 'Current standing-priority objective'
+ sourcePath = '.agent_priority_cache.json'
+ updatedAt = '2026-03-23T23:24:00Z'
+ issueNumber = 1909
+ repository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ agentName = $null
+ nextAction = 'merge concentrator handoff support'
+ }
+ )
+ warmMemory = @()
+ archiveCount = 1
+ }
+ episodes = [ordered]@{
+ totalCount = 2
+ validCount = 2
+ invalidCount = 0
+ invalidEpisodes = @()
+ byStatus = @([ordered]@{ status = 'reported'; count = 2 })
+ byAgent = @([ordered]@{ agentId = 'euler-id'; agentName = 'Euler'; count = 1 })
+ recent = @()
+ }
+ cost = [ordered]@{
+ episodeCountWithCost = 2
+ tokenUsd = 0.12
+ operatorLaborUsd = 10.416667
+ blendedLowerBoundUsd = 10.536667
+ observedDurationSeconds = 150
+ }
+ summary = [ordered]@{
+ status = 'active'
+ concentrationStatus = 'pass'
+ currentOwnerRepository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ nextOwnerRepository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ nextAction = 'merge concentrator handoff support'
+ activeIssueNumber = 1909
+ hotWorkingSetCount = 1
+ warmMemoryCount = 0
+ archiveCount = 1
+ blockerCount = 0
+ recentEpisodeCount = 2
+ blendedLowerBoundUsd = 10.536667
+ }
+ } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $handoffDir 'sagan-context-concentrator.json') -Encoding utf8
+
+ $output = & $scriptPath -HandoffDir $handoffDir *>&1 | Out-String
+
+ $output | Should -Match '\[handoff\] Context concentrator'
+ $output | Should -Match 'issue\s+: #1909'
+ $output | Should -Match 'hot/warm\s+: 1/0'
+ $global:HandoffContextConcentrator.schema | Should -Be 'priority/sagan-context-concentrator-report@v1'
+
+ Remove-Variable -Name HandoffContextConcentrator -Scope Global -ErrorAction SilentlyContinue
+ }
}
diff --git a/tests/Post-IssueComment.Tests.ps1 b/tests/Post-IssueComment.Tests.ps1
index 2c5d5135c..b8c466f09 100644
--- a/tests/Post-IssueComment.Tests.ps1
+++ b/tests/Post-IssueComment.Tests.ps1
@@ -46,15 +46,15 @@ $payload | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath $env:GH_CAPTURE_PA
$bodyText = "Comment from file`n"
[System.IO.File]::WriteAllText($bodyPath, $bodyText)
- & $scriptPath -Issue 1396 -BodyFile $bodyPath -Quiet
+ & $scriptPath -Issue 1396 -BodyFile $bodyPath -SkipBudgetHook -Quiet
$capture = Get-Content -LiteralPath $script:capturePath -Raw | ConvertFrom-Json -ErrorAction Stop
$capture.args[0] | Should -Be 'issue'
$capture.args[1] | Should -Be 'comment'
$capture.args[2] | Should -Be '1396'
$capture.args | Should -Contain '--body-file'
- $capture.bodyPath | Should -Be (Resolve-Path -LiteralPath $bodyPath).Path
- $capture.bodyContent | Should -BeExactly $bodyText
+ [string]::IsNullOrWhiteSpace($capture.bodyPath) | Should -BeFalse
+ $capture.bodyContent.TrimEnd("`r", "`n") | Should -BeExactly $bodyText.TrimEnd("`r", "`n")
}
It 'routes inline body text through a temporary body file' {
@@ -63,7 +63,7 @@ Continuity line
`upstream/develop...HEAD`
'@.TrimEnd("`r", "`n")
- & $scriptPath -Issue 1396 -Body $bodyText -Quiet
+ & $scriptPath -Issue 1396 -Body $bodyText -SkipBudgetHook -Quiet
$capture = Get-Content -LiteralPath $script:capturePath -Raw | ConvertFrom-Json -ErrorAction Stop
$capture.args | Should -Contain '--body-file'
@@ -76,10 +76,28 @@ Continuity line
$bodyPath = Join-Path $TestDrive 'edit-last.md'
Set-Content -LiteralPath $bodyPath -Value 'Edit last comment' -Encoding utf8
- & $scriptPath -Issue 1396 -BodyFile $bodyPath -EditLast -Quiet
+ & $scriptPath -Issue 1396 -BodyFile $bodyPath -EditLast -SkipBudgetHook -Quiet
$capture = Get-Content -LiteralPath $script:capturePath -Raw | ConvertFrom-Json -ErrorAction Stop
$capture.args | Should -Contain '--edit-last'
$capture.args | Should -Contain '--body-file'
}
+
+ It 'appends the budget hook when a stub markdown hook file is supplied' {
+ $bodyPath = Join-Path $TestDrive 'comment.md'
+ $hookPath = Join-Path $TestDrive 'hook.md'
+ Set-Content -LiteralPath $bodyPath -Value 'Body before hook' -Encoding utf8
+ Set-Content -LiteralPath $hookPath -Value @'
+
+_Budget hook_: blended lower bound `$42.500000`.
+
+'@ -Encoding utf8
+
+ & $scriptPath -Issue 1396 -BodyFile $bodyPath -BudgetHookMarkdownFile $hookPath -Quiet
+
+ $capture = Get-Content -LiteralPath $script:capturePath -Raw | ConvertFrom-Json -ErrorAction Stop
+ $capture.bodyContent | Should -Match ''
+ $capture.bodyContent | Should -Match 'Body before hook'
+ $capture.bodyContent | Should -Match 'blended lower bound'
+ }
}
diff --git a/tests/Post-PullRequestComment.Tests.ps1 b/tests/Post-PullRequestComment.Tests.ps1
index 1ea86e8bd..1362e93ab 100644
--- a/tests/Post-PullRequestComment.Tests.ps1
+++ b/tests/Post-PullRequestComment.Tests.ps1
@@ -46,7 +46,7 @@ $payload | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath $env:GH_CAPTURE_PA
$bodyText = "PR comment from file`n"
[System.IO.File]::WriteAllText($bodyPath, $bodyText)
- & $scriptPath -PullRequest 1396 -Repo 'LabVIEW-Community-CI-CD/compare-vi-cli-action' -BodyFile $bodyPath -Quiet
+ & $scriptPath -PullRequest 1396 -Repo 'LabVIEW-Community-CI-CD/compare-vi-cli-action' -BodyFile $bodyPath -SkipBudgetHook -Quiet
$capture = Get-Content -LiteralPath $script:capturePath -Raw | ConvertFrom-Json -ErrorAction Stop
$capture.args[0] | Should -Be 'pr'
@@ -55,8 +55,8 @@ $payload | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath $env:GH_CAPTURE_PA
$capture.args | Should -Contain '--repo'
$capture.args | Should -Contain 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
$capture.args | Should -Contain '--body-file'
- $capture.bodyPath | Should -Be (Resolve-Path -LiteralPath $bodyPath).Path
- $capture.bodyContent | Should -BeExactly $bodyText
+ [string]::IsNullOrWhiteSpace($capture.bodyPath) | Should -BeFalse
+ $capture.bodyContent.TrimEnd("`r", "`n") | Should -BeExactly $bodyText.TrimEnd("`r", "`n")
}
It 'routes inline PR comment text through a temporary body file' {
@@ -65,7 +65,7 @@ Continuity line
`upstream/develop...HEAD`
'@.TrimEnd("`r", "`n")
- & $scriptPath -PullRequest 1396 -Repo 'LabVIEW-Community-CI-CD/compare-vi-cli-action' -Body $bodyText -Quiet
+ & $scriptPath -PullRequest 1396 -Repo 'LabVIEW-Community-CI-CD/compare-vi-cli-action' -Body $bodyText -SkipBudgetHook -Quiet
$capture = Get-Content -LiteralPath $script:capturePath -Raw | ConvertFrom-Json -ErrorAction Stop
$capture.args | Should -Contain '--body-file'
@@ -78,10 +78,28 @@ Continuity line
$bodyPath = Join-Path $TestDrive 'edit-last.md'
Set-Content -LiteralPath $bodyPath -Value 'Edit last PR comment' -Encoding utf8
- & $scriptPath -PullRequest 1396 -Repo 'LabVIEW-Community-CI-CD/compare-vi-cli-action' -BodyFile $bodyPath -EditLast -Quiet
+ & $scriptPath -PullRequest 1396 -Repo 'LabVIEW-Community-CI-CD/compare-vi-cli-action' -BodyFile $bodyPath -EditLast -SkipBudgetHook -Quiet
$capture = Get-Content -LiteralPath $script:capturePath -Raw | ConvertFrom-Json -ErrorAction Stop
$capture.args | Should -Contain '--edit-last'
$capture.args | Should -Contain '--body-file'
}
+
+ It 'appends the budget hook when a stub markdown hook file is supplied' {
+ $bodyPath = Join-Path $TestDrive 'comment.md'
+ $hookPath = Join-Path $TestDrive 'hook.md'
+ Set-Content -LiteralPath $bodyPath -Value 'Body before hook' -Encoding utf8
+ Set-Content -LiteralPath $hookPath -Value @'
+
+_Budget hook_: operator cap `$50000.000000`.
+
+'@ -Encoding utf8
+
+ & $scriptPath -PullRequest 1396 -Repo 'LabVIEW-Community-CI-CD/compare-vi-cli-action' -BodyFile $bodyPath -BudgetHookMarkdownFile $hookPath -Quiet
+
+ $capture = Get-Content -LiteralPath $script:capturePath -Raw | ConvertFrom-Json -ErrorAction Stop
+ $capture.bodyContent | Should -Match ''
+ $capture.bodyContent | Should -Match 'Body before hook'
+ $capture.bodyContent | Should -Match 'operator cap'
+ }
}
diff --git a/tests/Run-AutonomousIntegrationLoop.Tests.ps1 b/tests/Run-AutonomousIntegrationLoop.Tests.ps1
index 6a25a01dd..0b576e71c 100644
--- a/tests/Run-AutonomousIntegrationLoop.Tests.ps1
+++ b/tests/Run-AutonomousIntegrationLoop.Tests.ps1
@@ -77,8 +77,20 @@ Describe 'Run-AutonomousIntegrationLoop TestStand harness mode' -Tag 'Unit' {
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
$base = Join-Path $outDir 'BaseHarness.vi'
$head = Join-Path $outDir 'HeadHarness.vi'
+ $leasePath = Join-Path $outDir 'execution-cell.json'
New-Item -ItemType File -Path $base -Force | Out-Null
New-Item -ItemType File -Path $head -Force | Out-Null
+ @'
+{
+ "schema": "priority/execution-cell-lease-report@v1",
+ "summary": {
+ "cellClass": "worker",
+ "suiteClass": "dual-plane-parity",
+ "operatorAuthorizationRef": "budget-auth://operator/session-2026-03-24",
+ "premiumSaganMode": false
+ }
+}
+'@ | Set-Content -LiteralPath $leasePath -Encoding UTF8
$harnessStub = Join-Path $outDir 'TestStand-CompareHarness.ps1'
$logPath = Join-Path $outDir 'harness-log.ndjson'
@@ -88,9 +100,18 @@ param(
[string]`$BaseVi,
[string]`$HeadVi,
[Alias('LabVIEWPath')][string]`$LabVIEWExePath,
+ [string]`$LabVIEW64ExePath,
+ [string]`$LabVIEW32ExePath,
[Alias('LVCompareExePath')][string]`$LVComparePath,
+ [string]`$AgentId,
+ [string]`$AgentClass,
+ [string]`$ExecutionCellLeasePath,
+ [string]`$ExecutionCellId,
+ [string]`$ExecutionCellLeaseId,
+ [string]`$HarnessInstanceId,
[string]`$OutputRoot,
[ValidateSet('detect','spawn','skip')][string]`$Warmup,
+ [ValidateSet('single-compare','dual-plane-parity')][string]`$SuiteClass = 'single-compare',
[string[]]`$Flags,
[switch]`$RenderReport,
[switch]`$CloseLabVIEW,
@@ -108,6 +129,16 @@ if (`$logDir -and -not (Test-Path `$logDir)) { New-Item -ItemType Directory -Pat
head = `$HeadVi
output = `$OutputRoot
warmup = `$Warmup
+ suiteClass = `$SuiteClass
+ labviewExe = `$LabVIEWExePath
+ labview64Exe = `$LabVIEW64ExePath
+ labview32Exe = `$LabVIEW32ExePath
+ agentId = `$AgentId
+ agentClass = `$AgentClass
+ executionCellLeasePath = `$ExecutionCellLeasePath
+ executionCellId = `$ExecutionCellId
+ executionCellLeaseId = `$ExecutionCellLeaseId
+ harnessInstanceId = `$HarnessInstanceId
flags = @(`$Flags)
renderReport = `$RenderReport.IsPresent
closeLabVIEW = `$CloseLabVIEW.IsPresent
@@ -126,7 +157,7 @@ exit 0
try {
$runner = Join-Path $outDir 'runner-harness.ps1'
$runnerContent = @"
-& '$scriptPath' -Base '$base' -Head '$head' -MaxIterations 2 -IntervalSeconds 0 -LogVerbosity Quiet -LvCompareArgs '-foo 1 -bar' -UseTestStandHarness -TestStandHarnessPath '$harnessStub' -TestStandOutputRoot '$outputRoot' -TestStandWarmup detect -TestStandRenderReport -TestStandCloseLabVIEW -TestStandCloseLVCompare -TestStandTimeoutSeconds 45 -TestStandReplaceFlags -FinalStatusJsonPath '$outDir/final.json'
+& '$scriptPath' -Base '$base' -Head '$head' -MaxIterations 2 -IntervalSeconds 0 -LogVerbosity Quiet -LvCompareArgs '-foo 1 -bar' -UseTestStandHarness -TestStandHarnessPath '$harnessStub' -TestStandOutputRoot '$outputRoot' -TestStandWarmup detect -TestStandSuiteClass dual-plane-parity -TestStandLabVIEW64Path 'C:\Program Files\National Instruments\LabVIEW 2026\LabVIEW.exe' -TestStandLabVIEW32Path 'C:\Program Files (x86)\National Instruments\LabVIEW 2026\LabVIEW.exe' -TestStandAgentId 'hooke' -TestStandAgentClass 'subagent' -TestStandExecutionCellLeasePath '$leasePath' -TestStandExecutionCellId 'exec-cell-hooke-loop-01' -TestStandExecutionCellLeaseId 'lease-hooke-loop-01' -TestStandHarnessInstanceId 'ts-loop-hooke-01' -TestStandRenderReport -TestStandCloseLabVIEW -TestStandCloseLVCompare -TestStandTimeoutSeconds 45 -TestStandReplaceFlags -FinalStatusJsonPath '$outDir/final.json'
exit `$LASTEXITCODE
"@
Set-Content -LiteralPath $runner -Encoding UTF8 -Value $runnerContent
@@ -140,12 +171,37 @@ exit `$LASTEXITCODE
$entries[0].output | Should -Match 'iteration-0001$'
$entries[1].output | Should -Match 'iteration-0002$'
$entries | ForEach-Object { $_.warmup } | Sort-Object -Unique | Should -Be @('detect')
+ $entries | ForEach-Object { $_.suiteClass } | Sort-Object -Unique | Should -Be @('dual-plane-parity')
+ $entries | ForEach-Object { $_.labview64Exe } | Sort-Object -Unique | Should -Be @('C:\Program Files\National Instruments\LabVIEW 2026\LabVIEW.exe')
+ $entries | ForEach-Object { $_.labview32Exe } | Sort-Object -Unique | Should -Be @('C:\Program Files (x86)\National Instruments\LabVIEW 2026\LabVIEW.exe')
+ $entries | ForEach-Object { $_.agentId } | Sort-Object -Unique | Should -Be @('hooke')
+ $entries | ForEach-Object { $_.agentClass } | Sort-Object -Unique | Should -Be @('subagent')
+ $entries | ForEach-Object { $_.executionCellLeasePath } | Sort-Object -Unique | Should -Be @($leasePath)
+ $entries | ForEach-Object { $_.executionCellId } | Sort-Object -Unique | Should -Be @('exec-cell-hooke-loop-01')
+ $entries | ForEach-Object { $_.executionCellLeaseId } | Sort-Object -Unique | Should -Be @('lease-hooke-loop-01')
+ $entries | ForEach-Object { $_.harnessInstanceId } | Sort-Object -Unique | Should -Be @('ts-loop-hooke-01')
$entries | ForEach-Object { $_.renderReport } | Sort-Object -Unique | Should -Be @($true)
$entries | ForEach-Object { $_.closeLabVIEW } | Sort-Object -Unique | Should -Be @($true)
$entries | ForEach-Object { $_.closeLVCompare } | Sort-Object -Unique | Should -Be @($true)
$entries | ForEach-Object { [int]$_.timeout } | Sort-Object -Unique | Should -Be @(45)
$entries | ForEach-Object { $_.replaceFlags } | Sort-Object -Unique | Should -Be @($true)
$entries | ForEach-Object { $_.flags } | ForEach-Object { $_ } | Sort-Object -Unique | Should -Be @('-bar','-foo','1')
+
+ $finalStatus = Get-Content -LiteralPath (Join-Path $outDir 'final.json') -Raw | ConvertFrom-Json
+ $finalStatus.harness.path | Should -Be $harnessStub
+ $finalStatus.harness.output | Should -Be $outputRoot
+ $finalStatus.harness.suiteClass | Should -Be 'dual-plane-parity'
+ $finalStatus.harness.runtimeSurface | Should -Be 'windows-native-teststand'
+ $finalStatus.harness.processModelClass | Should -Be 'parallel-process-model'
+ $finalStatus.harness.windowsOnly | Should -BeTrue
+ $finalStatus.harness.requestedSimultaneous | Should -BeTrue
+ $finalStatus.harness.cellClass | Should -Be 'worker'
+ $finalStatus.harness.operatorAuthorizationRef | Should -Be 'budget-auth://operator/session-2026-03-24'
+ $finalStatus.harness.premiumSaganMode | Should -BeFalse
+ $finalStatus.harness.executionCellLeasePath | Should -Be $leasePath
+ $finalStatus.harness.executionCellId | Should -Be 'exec-cell-hooke-loop-01'
+ $finalStatus.harness.executionCellLeaseId | Should -Be 'lease-hooke-loop-01'
+ $finalStatus.harness.harnessInstanceId | Should -Be 'ts-loop-hooke-01'
}
finally {
Remove-Item Env:HARNESS_LOG -ErrorAction SilentlyContinue
diff --git a/tests/Run-DX.Tests.ps1 b/tests/Run-DX.Tests.ps1
index 069193c41..cc8e6dcb9 100644
--- a/tests/Run-DX.Tests.ps1
+++ b/tests/Run-DX.Tests.ps1
@@ -18,12 +18,21 @@ Describe 'Run-DX.ps1 (TestStand staging)' -Tag 'Unit' {
New-Item -ItemType Directory -Path 'tools' | Out-Null
Copy-Item -LiteralPath $script:RunDxPath -Destination 'tools/Run-DX.ps1'
Copy-Item -LiteralPath $script:StageScriptPath -Destination 'tools/Stage-CompareInputs.ps1'
+ $runDxContent = Get-Content -LiteralPath (Join-Path $work 'tools/Run-DX.ps1') -Raw
+ $runDxContent = $runDxContent -replace '(?m)^exit \$exit$', 'return $exit'
+ Set-Content -LiteralPath (Join-Path $work 'tools/Run-DX.ps1') -Value $runDxContent -Encoding UTF8
$harnessStub = @'
param(
[string]$BaseVi,
[string]$HeadVi,
[string]$OutputRoot,
[string]$StagingRoot,
+ [string]$AgentId,
+ [string]$AgentClass,
+ [string]$ExecutionCellLeasePath,
+ [string]$ExecutionCellId,
+ [string]$ExecutionCellLeaseId,
+ [string]$HarnessInstanceId,
[switch]$SameNameHint,
[switch]$AllowSameLeaf,
[string]$NoiseProfile,
@@ -34,6 +43,12 @@ $log = [ordered]@{
base = $BaseVi
head = $HeadVi
stagingRoot = $StagingRoot
+ agentId = $AgentId
+ agentClass = $AgentClass
+ executionCellLeasePath = $ExecutionCellLeasePath
+ executionCellId = $ExecutionCellId
+ executionCellLeaseId = $ExecutionCellLeaseId
+ harnessInstanceId = $HarnessInstanceId
sameNameHint = $SameNameHint.IsPresent
allowSameLeaf = $AllowSameLeaf.IsPresent
noiseProfile = $NoiseProfile
@@ -42,6 +57,8 @@ $log = [ordered]@{
$log | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $OutputRoot 'harness-log.json') -Encoding utf8
$session = [ordered]@{
schema = 'teststand-compare-session/v1'
+ suiteClass = 'single-compare'
+ requestedSimultaneous = $false
warmup = @{
mode = $Warmup
events = $null
@@ -60,6 +77,30 @@ $session = [ordered]@{
}
outcome = $null
error = $null
+ executionCell = @{
+ cellId = $ExecutionCellId
+ leaseId = $ExecutionCellLeaseId
+ leasePath = $ExecutionCellLeasePath
+ agentId = $AgentId
+ agentClass = $AgentClass
+ cellClass = 'worker'
+ suiteClass = 'single-compare'
+ operatorAuthorizationRef = 'budget-auth://operator/session-2026-03-24'
+ premiumSaganMode = $false
+ }
+ harnessInstance = @{
+ harnessKind = 'teststand-compare-harness'
+ instanceId = $HarnessInstanceId
+ role = 'single-plane'
+ processModelClass = 'sequential-process-model'
+ }
+ processModel = @{
+ runtimeSurface = 'windows-native-teststand'
+ processModelClass = 'sequential-process-model'
+ windowsOnly = $true
+ rootHarnessInstanceId = $HarnessInstanceId
+ planeCount = 1
+ }
}
$session | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputRoot 'session-index.json') -Encoding utf8
exit 0
@@ -78,13 +119,20 @@ exit 0
$outputRoot = Join-Path $work 'results'
$runDx = Join-Path $work 'tools/Run-DX.ps1'
- & pwsh -NoLogo -NoProfile -File $runDx `
+ $result = & $runDx `
-Suite TestStand `
-BaseVi $baseVi `
-HeadVi $headVi `
-OutputRoot $outputRoot `
- -Warmup skip *> $null
- $LASTEXITCODE | Should -Be 0
+ -ResultsPath $outputRoot `
+ -Warmup skip `
+ -AgentId hooke `
+ -AgentClass subagent `
+ -ExecutionCellLeasePath 'E:\comparevi-lanes\cells\hooke-01\execution-cell.json' `
+ -ExecutionCellId 'exec-cell-hooke-01' `
+ -ExecutionCellLeaseId 'lease-hooke-01' `
+ -HarnessInstanceId 'harness-hooke-01'
+ $result | Should -Be 0
$logPath = Join-Path $outputRoot 'harness-log.json'
Test-Path -LiteralPath $logPath | Should -BeTrue
@@ -96,6 +144,11 @@ exit 0
$log.sameNameHint | Should -BeTrue
$log.allowSameLeaf | Should -BeFalse
$log.stagingRoot | Should -Not -BeNullOrEmpty
+ $log.agentId | Should -Be 'hooke'
+ $log.agentClass | Should -Be 'subagent'
+ $log.executionCellId | Should -Be 'exec-cell-hooke-01'
+ $log.executionCellLeaseId | Should -Be 'lease-hooke-01'
+ $log.harnessInstanceId | Should -Be 'harness-hooke-01'
$log.noiseProfile | Should -Be 'full'
Test-Path -LiteralPath $log.stagingRoot | Should -BeFalse
@@ -104,6 +157,23 @@ exit 0
$session.compare.staging.enabled | Should -BeTrue
$session.compare.staging.root | Should -Be $log.stagingRoot
$session.compare.allowSameLeaf | Should -BeFalse
+ $session.executionCell.cellId | Should -Be 'exec-cell-hooke-01'
+ $session.executionCell.leaseId | Should -Be 'lease-hooke-01'
+ $session.harnessInstance.instanceId | Should -Be 'harness-hooke-01'
+ $session.processModel.runtimeSurface | Should -Be 'windows-native-teststand'
+ $session.processModel.processModelClass | Should -Be 'sequential-process-model'
+ $statusPath = Join-Path $outputRoot '_agent/dx-status.json'
+ $status = Get-Content -LiteralPath $statusPath -Raw | ConvertFrom-Json
+ $status.executionTopology.suiteClass | Should -Be 'single-compare'
+ $status.executionTopology.runtimeSurface | Should -Be 'windows-native-teststand'
+ $status.executionTopology.processModelClass | Should -Be 'sequential-process-model'
+ $status.executionTopology.requestedSimultaneous | Should -BeFalse
+ $status.executionTopology.cellClass | Should -Be 'worker'
+ $status.executionTopology.operatorAuthorizationRef | Should -Be 'budget-auth://operator/session-2026-03-24'
+ $status.executionTopology.premiumSaganMode | Should -BeFalse
+ $status.executionTopology.harnessKind | Should -Be 'teststand-compare-harness'
+ $status.executionTopology.executionCellId | Should -Be 'exec-cell-hooke-01'
+ $status.executionTopology.executionCellLeaseId | Should -Be 'lease-hooke-01'
}
finally { Pop-Location }
}
@@ -116,12 +186,21 @@ exit 0
New-Item -ItemType Directory -Path 'tools' | Out-Null
Copy-Item -LiteralPath $script:RunDxPath -Destination 'tools/Run-DX.ps1'
Copy-Item -LiteralPath $script:StageScriptPath -Destination 'tools/Stage-CompareInputs.ps1'
+ $runDxContent = Get-Content -LiteralPath (Join-Path $work 'tools/Run-DX.ps1') -Raw
+ $runDxContent = $runDxContent -replace '(?m)^exit \$exit$', 'return $exit'
+ Set-Content -LiteralPath (Join-Path $work 'tools/Run-DX.ps1') -Value $runDxContent -Encoding UTF8
$harnessStub = @'
param(
[string]$BaseVi,
[string]$HeadVi,
[string]$OutputRoot,
[string]$StagingRoot,
+ [string]$AgentId,
+ [string]$AgentClass,
+ [string]$ExecutionCellLeasePath,
+ [string]$ExecutionCellId,
+ [string]$ExecutionCellLeaseId,
+ [string]$HarnessInstanceId,
[switch]$SameNameHint,
[switch]$AllowSameLeaf,
[string]$NoiseProfile,
@@ -132,6 +211,12 @@ $log = [ordered]@{
base = $BaseVi
head = $HeadVi
stagingRoot = $StagingRoot
+ agentId = $AgentId
+ agentClass = $AgentClass
+ executionCellLeasePath = $ExecutionCellLeasePath
+ executionCellId = $ExecutionCellId
+ executionCellLeaseId = $ExecutionCellLeaseId
+ harnessInstanceId = $HarnessInstanceId
sameNameHint = $SameNameHint.IsPresent
allowSameLeaf = $AllowSameLeaf.IsPresent
noiseProfile = $NoiseProfile
@@ -140,6 +225,8 @@ $log = [ordered]@{
$log | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $OutputRoot 'harness-log.json') -Encoding utf8
$session = [ordered]@{
schema = 'teststand-compare-session/v1'
+ suiteClass = 'single-compare'
+ requestedSimultaneous = $false
warmup = @{
mode = $Warmup
events = $null
@@ -158,6 +245,30 @@ $session = [ordered]@{
}
outcome = $null
error = $null
+ executionCell = @{
+ cellId = $ExecutionCellId
+ leaseId = $ExecutionCellLeaseId
+ leasePath = $ExecutionCellLeasePath
+ agentId = $AgentId
+ agentClass = $AgentClass
+ cellClass = 'worker'
+ suiteClass = 'single-compare'
+ operatorAuthorizationRef = $null
+ premiumSaganMode = $false
+ }
+ harnessInstance = @{
+ harnessKind = 'teststand-compare-harness'
+ instanceId = $HarnessInstanceId
+ role = 'single-plane'
+ processModelClass = 'sequential-process-model'
+ }
+ processModel = @{
+ runtimeSurface = 'windows-native-teststand'
+ processModelClass = 'sequential-process-model'
+ windowsOnly = $true
+ rootHarnessInstanceId = $HarnessInstanceId
+ planeCount = 1
+ }
}
$session | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputRoot 'session-index.json') -Encoding utf8
exit 0
@@ -174,15 +285,16 @@ exit 0
$outputRoot = Join-Path $work 'results'
$runDx = Join-Path $work 'tools/Run-DX.ps1'
- & pwsh -NoLogo -NoProfile -File $runDx `
+ $result = & $runDx `
-Suite TestStand `
-BaseVi $baseVi `
-HeadVi $headVi `
-OutputRoot $outputRoot `
+ -ResultsPath $outputRoot `
-Warmup detect `
-UseRawPaths `
- -NoiseProfile legacy *> $null
- $LASTEXITCODE | Should -Be 0
+ -NoiseProfile legacy
+ $result | Should -Be 0
$logPath = Join-Path $outputRoot 'harness-log.json'
Test-Path -LiteralPath $logPath | Should -BeTrue
@@ -202,5 +314,38 @@ exit 0
}
finally { Pop-Location }
}
-}
+ It 'declares dual-plane parity forwarding and status projection in the wrapper contract' {
+ $content = Get-Content -LiteralPath $script:RunDxPath -Raw
+
+ $content | Should -Match '\[string\]\$LabVIEW64ExePath'
+ $content | Should -Match '\[string\]\$LabVIEW32ExePath'
+ $content | Should -Match '\[string\]\$AgentId'
+ $content | Should -Match '\[string\]\$AgentClass'
+ $content | Should -Match '\[string\]\$ExecutionCellLeasePath'
+ $content | Should -Match '\[string\]\$ExecutionCellId'
+ $content | Should -Match '\[string\]\$ExecutionCellLeaseId'
+ $content | Should -Match '\[string\]\$HarnessInstanceId'
+ $content | Should -Match "\[ValidateSet\('single-compare','dual-plane-parity'\)\]\s*\[string\]\`$TestStandSuiteClass"
+ $content | Should -Match '\$hParams\.LabVIEW64ExePath\s*=\s*\$LabVIEW64ExePath'
+ $content | Should -Match '\$hParams\.LabVIEW32ExePath\s*=\s*\$LabVIEW32ExePath'
+ $content | Should -Match '\$hParams\.SuiteClass\s*=\s*\$TestStandSuiteClass'
+ $content | Should -Match '\$hParams\.AgentId\s*=\s*\$AgentId'
+ $content | Should -Match '\$hParams\.AgentClass\s*=\s*\$AgentClass'
+ $content | Should -Match '\$hParams\.ExecutionCellLeasePath\s*=\s*\$ExecutionCellLeasePath'
+ $content | Should -Match '\$hParams\.ExecutionCellId\s*=\s*\$ExecutionCellId'
+ $content | Should -Match '\$hParams\.ExecutionCellLeaseId\s*=\s*\$ExecutionCellLeaseId'
+ $content | Should -Match '\$hParams\.HarnessInstanceId\s*=\s*\$HarnessInstanceId'
+ $content | Should -Match 'suiteClass\s*=\s*if\s*\(\$session\.PSObject\.Properties\.Name\s*-contains\s*''suiteClass''\)'
+ $content | Should -Match 'primaryPlane\s*=\s*Get-SessionValue\s+\$session\s+''primaryPlane'''
+ $content | Should -Match 'Get-SessionBoolValue'
+ $content | Should -Match '\$requestedSimultaneous\s*=\s*\$false'
+ $content | Should -Match 'requestedSimultaneous\s*=\s*\$requestedSimultaneous'
+ $content | Should -Match 'executionTopology\s*=\s*@\{'
+ $content | Should -Match 'executionCell\s*=\s*Get-SessionValue\s+\$session\s+''executionCell'''
+ $content | Should -Match 'harnessInstance\s*=\s*Get-SessionValue\s+\$session\s+''harnessInstance'''
+ $content | Should -Match 'processModel\s*=\s*Get-SessionValue\s+\$session\s+''processModel'''
+ $content | Should -Match 'parity\s*=\s*Get-SessionValue\s+\$session\s+''parity'''
+ $content | Should -Match 'planes\s*=\s*Get-SessionValue\s+\$session\s+''planes'''
+ }
+}
diff --git a/tests/TestHelpers.Schema.ps1 b/tests/TestHelpers.Schema.ps1
index 19132d61f..a7d4fc5ab 100644
--- a/tests/TestHelpers.Schema.ps1
+++ b/tests/TestHelpers.Schema.ps1
@@ -26,7 +26,7 @@ if (-not (Get-Variable -Name JsonShapeSpecs -Scope Script -ErrorAction SilentlyC
$script:JsonShapeSpecs['FinalStatus'] = [pscustomobject]@{
Required = @('schema','timestamp','iterations','diffs','errors','succeeded')
- Optional = @('averageSeconds','totalSeconds','percentiles','histogram','diffSummaryEmitted','basePath','headPath')
+ Optional = @('averageSeconds','totalSeconds','percentiles','histogram','diffSummaryEmitted','basePath','headPath','harness')
Types = @{
schema = { param($v) $v -is [string] -and $v -eq 'loop-final-status-v1' }
timestamp = { param($v) ($v -is [string] -or $v -is [datetime]) }
@@ -41,6 +41,7 @@ $script:JsonShapeSpecs['FinalStatus'] = [pscustomobject]@{
diffSummaryEmitted= { param($v) -not $v -or $v -is [bool] }
basePath = { param($v) -not $v -or $v -is [string] }
headPath = { param($v) -not $v -or $v -is [string] }
+ harness = { param($v) -not $v -or ($v -is [hashtable] -or $v -is [pscustomobject]) }
}
}
diff --git a/tests/TestStand-CompareHarness.Tests.ps1 b/tests/TestStand-CompareHarness.Tests.ps1
index cfe70b198..c37c3a203 100644
--- a/tests/TestStand-CompareHarness.Tests.ps1
+++ b/tests/TestStand-CompareHarness.Tests.ps1
@@ -67,11 +67,34 @@ exit 0
$outputRoot = Join-Path $work 'results'
$harness = Join-Path $work 'tools\TestStand-CompareHarness.ps1'
$stageDir = Join-Path $work 'stage'
+ $leasePath = Join-Path $work 'execution-cell.json'
New-Item -ItemType Directory -Path $stageDir | Out-Null
$stagedBase = Join-Path $stageDir 'Base.vi'
$stagedHead = Join-Path $stageDir 'Head.vi'
Copy-Item -LiteralPath $baseReal -Destination $stagedBase -Force
Copy-Item -LiteralPath $headReal -Destination $stagedHead -Force
+ @{
+ schema = 'priority/execution-cell-lease@v1'
+ cellId = 'exec-cell-hooke-01'
+ host = @{
+ isolatedLaneGroupId = 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+ fingerprintSha256 = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+ }
+ request = @{
+ agentId = 'hooke'
+ agentClass = 'subagent'
+ cellClass = 'worker'
+ suiteClass = 'single-compare'
+ planeBinding = 'native-labview-2025-64'
+ harnessKind = 'teststand-compare-harness'
+ workingRoot = $outputRoot
+ artifactRoot = $outputRoot
+ }
+ grant = @{
+ leaseId = 'lease-hooke-01'
+ premiumSaganMode = $false
+ }
+ } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $leasePath -Encoding UTF8
& pwsh -NoLogo -NoProfile -File $harness `
-BaseVi $stagedBase `
@@ -83,7 +106,9 @@ exit 0
-CloseLabVIEW `
-CloseLVCompare `
-StagingRoot $stageDir `
- -SameNameHint *> $null
+ -SameNameHint `
+ -ExecutionCellLeasePath $leasePath `
+ -HarnessInstanceId 'ts-harness-hooke-01' *> $null
$invokeLogPath = Get-ChildItem -Path $outputRoot -Recurse -Filter 'invoke-args.json' | Select-Object -First 1
$invokeLogPath | Should -Not -BeNullOrEmpty
@@ -100,6 +125,22 @@ exit 0
$indexData.compare.sameName | Should -BeTrue
$indexData.compare.staging.enabled | Should -BeTrue
$indexData.compare.staging.root | Should -Be $stageDir
+ $indexData.executionCell.cellId | Should -Be 'exec-cell-hooke-01'
+ $indexData.executionCell.leaseId | Should -Be 'lease-hooke-01'
+ $indexData.executionCell.agentId | Should -Be 'hooke'
+ $indexData.executionCell.agentClass | Should -Be 'subagent'
+ $indexData.executionCell.cellClass | Should -Be 'worker'
+ $indexData.executionCell.runtimeSurface | Should -Be 'windows-native-teststand'
+ $indexData.executionCell.premiumSaganMode | Should -BeFalse
+ $indexData.executionCell.operatorAuthorizationRef | Should -BeNullOrEmpty
+ $indexData.harnessInstance.instanceId | Should -Be 'ts-harness-hooke-01'
+ $indexData.harnessInstance.role | Should -Be 'single-plane'
+ $indexData.harnessInstance.processModelClass | Should -Be 'sequential-process-model'
+ $indexData.processModel.runtimeSurface | Should -Be 'windows-native-teststand'
+ $indexData.processModel.processModelClass | Should -Be 'sequential-process-model'
+ $indexData.processModel.windowsOnly | Should -BeTrue
+ $indexData.processModel.rootHarnessInstanceId | Should -Be 'ts-harness-hooke-01'
+ $indexData.processModel.planeCount | Should -Be 1
}
finally { Pop-Location }
}
@@ -194,3 +235,202 @@ exit 0
}
}
+Describe 'TestStand-CompareHarness.ps1 (dual-plane parity)' -Tag 'Unit' {
+ It 'runs LabVIEW 2026 x64 and x32 sessions simultaneously and emits a parity session index' {
+ $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
+ $baseDir = Join-Path $TestDrive 'dual-base'
+ $headDir = Join-Path $TestDrive 'dual-head'
+ New-Item -ItemType Directory -Path $baseDir, $headDir | Out-Null
+ $baseVi = Join-Path $baseDir 'Base.vi'
+ $headVi = Join-Path $headDir 'Head.vi'
+ Set-Content -LiteralPath $baseVi -Value 'base' -Encoding UTF8
+ Set-Content -LiteralPath $headVi -Value 'head' -Encoding UTF8
+
+ $work = Join-Path $TestDrive 'harness-dual-plane'
+ New-Item -ItemType Directory -Path $work | Out-Null
+ Push-Location $work
+ try {
+ New-Item -ItemType Directory -Path 'tools' | Out-Null
+ Copy-Item -LiteralPath (Join-Path $repoRoot 'tools\TestStand-CompareHarness.ps1') -Destination 'tools\TestStand-CompareHarness.ps1'
+
+ Set-Content -LiteralPath 'tools/Warmup-LabVIEWRuntime.ps1' -Encoding UTF8 -Value @'
+param(
+ [string]$LabVIEWPath,
+ [string]$JsonLogPath,
+ [string]$SupportedBitness
+)
+if ($JsonLogPath) {
+ $dir = Split-Path -Parent $JsonLogPath
+ if ($dir -and -not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
+ (@{ type = 'warmup'; bitness = $SupportedBitness; labview = $LabVIEWPath } | ConvertTo-Json -Compress) | Set-Content -LiteralPath $JsonLogPath -Encoding utf8
+}
+exit 0
+'@
+
+ $invokeStub = @'
+param(
+ [string]$BaseVi,
+ [string]$HeadVi,
+ [Alias('LabVIEWPath')]
+ [string]$LabVIEWExePath,
+ [Alias('LVCompareExePath')]
+ [string]$LVComparePath,
+ [string]$OutputDir,
+ [switch]$RenderReport,
+ [string]$JsonLogPath,
+ [object]$Flags,
+ [string]$NoiseProfile,
+ [string]$LabVIEWBitness
+)
+if (-not (Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null }
+if ($JsonLogPath) {
+ '{}' | Set-Content -LiteralPath $JsonLogPath -Encoding utf8
+}
+$capture = [ordered]@{
+ exitCode = 0
+ seconds = if ($LabVIEWBitness -eq '32') { 1.32 } else { 1.64 }
+ command = "stub-$LabVIEWBitness"
+ cliPath = "C:\Program Files\National Instruments\Shared\LabVIEW CLI\$LabVIEWBitness\LabVIEWCLI.exe"
+ environment = @{
+ cli = @{
+ path = "C:\Program Files\National Instruments\Shared\LabVIEW CLI\$LabVIEWBitness\LabVIEWCLI.exe"
+ version = '26.0.0f0'
+ reportType = 'html'
+ reportPath = 'compare-report.html'
+ status = 'ok'
+ message = "compare completed for $LabVIEWBitness"
+ }
+ }
+}
+$capture | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $OutputDir 'lvcompare-capture.json') -Encoding utf8
+if ($RenderReport) {
+ Set-Content -LiteralPath (Join-Path $OutputDir 'compare-report.html') -Value "" -Encoding utf8
+}
+exit 0
+'@
+ Set-Content -LiteralPath 'tools/Invoke-LVCompare.ps1' -Value $invokeStub -Encoding UTF8
+ Set-Content -LiteralPath 'tools/Close-LVCompare.ps1' -Value "param() exit 0" -Encoding UTF8
+ Set-Content -LiteralPath 'tools/Close-LabVIEW.ps1' -Value "param() exit 0" -Encoding UTF8
+
+ $outputRoot = Join-Path $work 'results'
+ $harness = Join-Path $work 'tools\TestStand-CompareHarness.ps1'
+ $leasePath = Join-Path $work 'execution-cell.json'
+ @{
+ schema = 'priority/execution-cell-lease@v1'
+ cellId = 'exec-cell-sagan-01'
+ host = @{
+ isolatedLaneGroupId = 'host-os-fingerprint:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210'
+ fingerprintSha256 = 'fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210'
+ }
+ request = @{
+ agentId = 'sagan'
+ agentClass = 'sagan'
+ cellClass = 'kernel-coordinator'
+ suiteClass = 'dual-plane-parity'
+ planeBinding = 'dual-plane-parity'
+ harnessKind = 'teststand-compare-harness'
+ workingRoot = $outputRoot
+ artifactRoot = $outputRoot
+ }
+ grant = @{
+ leaseId = 'lease-sagan-01'
+ premiumSaganMode = $false
+ }
+ } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $leasePath -Encoding UTF8
+ & pwsh -NoLogo -NoProfile -File $harness `
+ -BaseVi $baseVi `
+ -HeadVi $headVi `
+ -OutputRoot $outputRoot `
+ -SuiteClass dual-plane-parity `
+ -LabVIEW64ExePath 'C:\Program Files\National Instruments\LabVIEW 2026\LabVIEW.exe' `
+ -LabVIEW32ExePath 'C:\Program Files (x86)\National Instruments\LabVIEW 2026\LabVIEW.exe' `
+ -Warmup detect `
+ -RenderReport `
+ -ExecutionCellLeasePath $leasePath `
+ -HarnessInstanceId 'ts-harness-sagan-01' *> $null
+
+ $LASTEXITCODE | Should -Be 0
+
+ $sessionIndex = Join-Path $outputRoot 'session-index.json'
+ Test-Path -LiteralPath $sessionIndex | Should -BeTrue
+ $indexData = Get-Content -LiteralPath $sessionIndex -Raw | ConvertFrom-Json -Depth 12
+ $indexData.schema | Should -Be 'teststand-compare-session/v2'
+ $indexData.suiteClass | Should -Be 'dual-plane-parity'
+ $indexData.primaryPlane | Should -Be 'native-labview-2026-64'
+ $indexData.requestedSimultaneous | Should -BeTrue
+ $indexData.executionCell.cellId | Should -Be 'exec-cell-sagan-01'
+ $indexData.executionCell.leaseId | Should -Be 'lease-sagan-01'
+ $indexData.executionCell.agentId | Should -Be 'sagan'
+ $indexData.executionCell.agentClass | Should -Be 'sagan'
+ $indexData.executionCell.cellClass | Should -Be 'kernel-coordinator'
+ $indexData.executionCell.runtimeSurface | Should -Be 'windows-native-teststand'
+ $indexData.executionCell.premiumSaganMode | Should -BeFalse
+ $indexData.executionCell.operatorAuthorizationRef | Should -BeNullOrEmpty
+ $indexData.harnessInstance.instanceId | Should -Be 'ts-harness-sagan-01'
+ $indexData.harnessInstance.role | Should -Be 'coordinator'
+ $indexData.harnessInstance.processModelClass | Should -Be 'parallel-process-model'
+ $indexData.processModel.runtimeSurface | Should -Be 'windows-native-teststand'
+ $indexData.processModel.processModelClass | Should -Be 'parallel-process-model'
+ $indexData.processModel.windowsOnly | Should -BeTrue
+ $indexData.processModel.rootHarnessInstanceId | Should -Be 'ts-harness-sagan-01'
+ $indexData.processModel.planeCount | Should -Be 2
+ $indexData.parity.status | Should -Be 'match'
+ $indexData.parity.mismatchCount | Should -Be 0
+ $indexData.planes.x64.plane | Should -Be 'native-labview-2026-64'
+ $indexData.planes.x32.plane | Should -Be 'native-labview-2026-32'
+ $indexData.planes.x64.architecture | Should -Be '64-bit'
+ $indexData.planes.x32.architecture | Should -Be '32-bit'
+ $indexData.planes.x64.labviewExePath | Should -Be 'C:\Program Files\National Instruments\LabVIEW 2026\LabVIEW.exe'
+ $indexData.planes.x32.labviewExePath | Should -Be 'C:\Program Files (x86)\National Instruments\LabVIEW 2026\LabVIEW.exe'
+ $indexData.planes.x64.outcome.exitCode | Should -Be 0
+ $indexData.planes.x32.outcome.exitCode | Should -Be 0
+ $indexData.planes.x64.compare.report | Should -BeTrue
+ $indexData.planes.x32.compare.report | Should -BeTrue
+ $indexData.planes.x64.compare.policy | Should -Be 'cli-only'
+ $indexData.planes.x32.compare.policy | Should -Be 'cli-only'
+ $indexData.planes.x64.compare.mode | Should -Be 'labview-cli'
+ $indexData.planes.x32.compare.mode | Should -Be 'labview-cli'
+ $indexData.planes.x64.executionCell.cellId | Should -Be 'exec-cell-sagan-01'
+ $indexData.planes.x32.executionCell.cellId | Should -Be 'exec-cell-sagan-01'
+ $indexData.planes.x64.executionCell.cellClass | Should -Be 'kernel-coordinator'
+ $indexData.planes.x32.executionCell.cellClass | Should -Be 'kernel-coordinator'
+ $indexData.planes.x64.executionCell.runtimeSurface | Should -Be 'windows-native-teststand'
+ $indexData.planes.x32.executionCell.runtimeSurface | Should -Be 'windows-native-teststand'
+ $indexData.planes.x64.executionCell.premiumSaganMode | Should -BeFalse
+ $indexData.planes.x32.executionCell.premiumSaganMode | Should -BeFalse
+ $indexData.planes.x64.harnessInstance.role | Should -Be 'plane-child'
+ $indexData.planes.x32.harnessInstance.role | Should -Be 'plane-child'
+ $indexData.planes.x64.harnessInstance.processModelClass | Should -Be 'parallel-process-model'
+ $indexData.planes.x32.harnessInstance.processModelClass | Should -Be 'parallel-process-model'
+ $indexData.planes.x64.harnessInstance.parentInstanceId | Should -Be 'ts-harness-sagan-01'
+ $indexData.planes.x32.harnessInstance.parentInstanceId | Should -Be 'ts-harness-sagan-01'
+ $indexData.planes.x64.harnessInstance.instanceId | Should -Be 'ts-harness-sagan-01-x64'
+ $indexData.planes.x32.harnessInstance.instanceId | Should -Be 'ts-harness-sagan-01-x32'
+ $indexData.planes.x64.processModel.runtimeSurface | Should -Be 'windows-native-teststand'
+ $indexData.planes.x32.processModel.runtimeSurface | Should -Be 'windows-native-teststand'
+ $indexData.planes.x64.processModel.processModelClass | Should -Be 'parallel-process-model'
+ $indexData.planes.x32.processModel.processModelClass | Should -Be 'parallel-process-model'
+ $indexData.planes.x64.processModel.rootHarnessInstanceId | Should -Be 'ts-harness-sagan-01'
+ $indexData.planes.x32.processModel.rootHarnessInstanceId | Should -Be 'ts-harness-sagan-01'
+ $indexData.planes.x64.processModel.planeCount | Should -Be 2
+ $indexData.planes.x32.processModel.planeCount | Should -Be 2
+ Test-Path -LiteralPath (Join-Path $outputRoot 'planes\x64\session-index.json') | Should -BeTrue
+ Test-Path -LiteralPath (Join-Path $outputRoot 'planes\x32\session-index.json') | Should -BeTrue
+ $x64Child = Get-Content -LiteralPath (Join-Path $outputRoot 'planes\x64\session-index.json') -Raw | ConvertFrom-Json -Depth 12
+ $x32Child = Get-Content -LiteralPath (Join-Path $outputRoot 'planes\x32\session-index.json') -Raw | ConvertFrom-Json -Depth 12
+ $x64Child.executionCell.cellId | Should -Be 'exec-cell-sagan-01'
+ $x32Child.executionCell.cellId | Should -Be 'exec-cell-sagan-01'
+ $x64Child.executionCell.cellClass | Should -Be 'kernel-coordinator'
+ $x32Child.executionCell.cellClass | Should -Be 'kernel-coordinator'
+ $x64Child.executionCell.runtimeSurface | Should -Be 'windows-native-teststand'
+ $x32Child.executionCell.runtimeSurface | Should -Be 'windows-native-teststand'
+ $x64Child.harnessInstance.instanceId | Should -Be 'ts-harness-sagan-01-x64'
+ $x32Child.harnessInstance.instanceId | Should -Be 'ts-harness-sagan-01-x32'
+ $x64Child.harnessInstance.processModelClass | Should -Be 'parallel-process-model'
+ $x32Child.harnessInstance.processModelClass | Should -Be 'parallel-process-model'
+ $x64Child.processModel.rootHarnessInstanceId | Should -Be 'ts-harness-sagan-01'
+ $x32Child.processModel.rootHarnessInstanceId | Should -Be 'ts-harness-sagan-01'
+ }
+ finally { Pop-Location }
+ }
+}
diff --git a/tests/Write-LabVIEW2026HostPlaneDiagnostics.Tests.ps1 b/tests/Write-LabVIEW2026HostPlaneDiagnostics.Tests.ps1
index 775781468..f84fc2640 100644
--- a/tests/Write-LabVIEW2026HostPlaneDiagnostics.Tests.ps1
+++ b/tests/Write-LabVIEW2026HostPlaneDiagnostics.Tests.ps1
@@ -48,6 +48,13 @@ Describe 'Write-LabVIEW2026HostPlaneDiagnostics.ps1' -Tag 'Unit' {
$report.schema | Should -Be 'labview-2026-host-plane-report@v1'
$report.runner.hostIsRunner | Should -BeTrue
$report.runner.runnerName | Should -Not -BeNullOrEmpty
+ $report.host.osFingerprint.role | Should -Be 'canonical-host-baseline'
+ $report.host.osFingerprint.comparisonScope | Should -Be 'isolated-lane-group'
+ $report.host.osFingerprint.fingerprintSha256 | Should -Match '^[a-f0-9]{64}$'
+ $report.host.osFingerprint.isolatedLaneGroupId | Should -Match '^host-os-fingerprint:[a-f0-9]{64}$'
+ $report.host.osFingerprint.canonical.version | Should -Not -BeNullOrEmpty
+ $report.host.osFingerprint.canonical.buildNumber | Should -Not -BeNullOrEmpty
+ $report.host.osFingerprint.canonical.architecture | Should -Not -BeNullOrEmpty
$report.policy.authoritativePlanes | Should -Contain 'docker-desktop/linux-container-2026'
$report.policy.authoritativePlanes | Should -Contain 'docker-desktop/windows-container-2026'
$report.policy.hostNativeShadowPlane.plane | Should -Be 'native-labview-2026-32'
@@ -68,6 +75,10 @@ Describe 'Write-LabVIEW2026HostPlaneDiagnostics.ps1' -Tag 'Unit' {
Test-Path -LiteralPath $summaryPath | Should -BeTrue
$summary = Get-Content -LiteralPath $summaryPath -Raw
$summary | Should -Match '# LabVIEW 2026 Host Plane Summary'
+ $summary | Should -Match '- Canonical host OS:'
+ $summary | Should -Match '- Host OS fingerprint SHA-256:'
+ $summary | Should -Match '- Isolated lane group ID:'
+ $summary | Should -Match '- Host OS branding:'
$summary | Should -Match '- Native 64-bit: `ready`'
$summary | Should -Match '- Native 32-bit: `ready`'
$summary | Should -Match 'Host-native 32-bit shadow: `acceleration-surface`'
@@ -141,5 +152,9 @@ Describe 'Write-LabVIEW2026HostPlaneDiagnostics.ps1' -Tag 'Unit' {
$outputText | Should -Match 'labview-2026-native-64-status=ready'
$outputText | Should -Match 'labview-2026-native-32-status=ready'
$outputText | Should -Match 'labview-2026-native-parallel-supported=True'
+ $outputText | Should -Match 'labview-2026-host-os-fingerprint-sha256='
+ $outputText | Should -Match 'labview-2026-host-isolated-lane-group-id='
+ $outputText | Should -Match 'labview-2026-host-os-version='
+ $outputText | Should -Match 'labview-2026-host-os-build='
}
}
diff --git a/tests/Write-SessionIndexV2CutoverReadiness.Tests.ps1 b/tests/Write-SessionIndexV2CutoverReadiness.Tests.ps1
index f8398126a..7c882a86e 100644
--- a/tests/Write-SessionIndexV2CutoverReadiness.Tests.ps1
+++ b/tests/Write-SessionIndexV2CutoverReadiness.Tests.ps1
@@ -136,11 +136,13 @@ $($consumerMatrixLines -join "`n")
## Burn-in tracking
"@
- $checklistLines = foreach ($item in $RemainingChecklistItems) {
- "- [ ] $item"
- }
- if ($checklistLines.Count -eq 0) {
- $checklistLines = '- [x] Remove v1 generation from producer paths/workflows.'
+ $checklistLines = @(
+ foreach ($item in $RemainingChecklistItems) {
+ "- [ ] $item"
+ }
+ )
+ if ($checklistLines.Length -eq 0) {
+ $checklistLines = @('- [x] Remove v1 generation from producer paths/workflows.')
}
Write-TextFile -Path $deprecationPath -Content (@"
diff --git a/tools/CompareVI.Tools/CompareVI.Tools.psd1 b/tools/CompareVI.Tools/CompareVI.Tools.psd1
index 3a55566f1..fe08f4ad9 100644
--- a/tools/CompareVI.Tools/CompareVI.Tools.psd1
+++ b/tools/CompareVI.Tools/CompareVI.Tools.psd1
@@ -21,7 +21,7 @@
PSData = @{
Tags = @('CompareVI','LabVIEW','VIHistory')
ProjectUri = 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action'
- Prerelease = 'rc.1'
+ Prerelease = 'rc.2'
}
}
}
diff --git a/tools/LabVIEW2026HostPlaneDiagnostics.psm1 b/tools/LabVIEW2026HostPlaneDiagnostics.psm1
index c8f573afb..9895fb872 100644
--- a/tools/LabVIEW2026HostPlaneDiagnostics.psm1
+++ b/tools/LabVIEW2026HostPlaneDiagnostics.psm1
@@ -25,6 +25,147 @@ function Convert-ToPathString {
return $Value.Trim()
}
+function Get-OptionalMemberValue {
+ param(
+ [AllowNull()]$Object,
+ [Parameter(Mandatory)][string]$Name
+ )
+
+ if ($null -eq $Object) {
+ return $null
+ }
+
+ $property = $Object.PSObject.Properties[$Name]
+ if ($property) {
+ return $property.Value
+ }
+
+ return $null
+}
+
+function Convert-ToCanonicalString {
+ param([AllowNull()]$Value)
+
+ if ($null -eq $Value) {
+ return ''
+ }
+
+ return ([string]$Value).Trim()
+}
+
+function Get-Sha256Hex {
+ param([Parameter(Mandatory)][string]$Value)
+
+ $bytes = [System.Text.Encoding]::UTF8.GetBytes($Value)
+ $hash = [System.Security.Cryptography.SHA256]::HashData($bytes)
+ return ([System.BitConverter]::ToString($hash)).Replace('-', '').ToLowerInvariant()
+}
+
+function Get-HostOperatingSystemFingerprint {
+ $registryPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
+ $currentVersion = $null
+ $osInfo = $null
+ $computerSystem = $null
+
+ if ($IsWindows) {
+ try {
+ $currentVersion = Get-ItemProperty -Path $registryPath
+ } catch {}
+
+ try {
+ $osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
+ } catch {}
+
+ try {
+ $computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem
+ } catch {}
+ }
+
+ $platform = if ($IsWindows) { 'windows' } else { 'non-windows' }
+ $version = if ($IsWindows) {
+ Convert-ToCanonicalString (Get-OptionalMemberValue -Object $osInfo -Name 'Version')
+ } else {
+ Convert-ToCanonicalString ([System.Runtime.InteropServices.RuntimeInformation]::OSDescription)
+ }
+ $buildNumber = if ($IsWindows) {
+ $value = Convert-ToCanonicalString (Get-OptionalMemberValue -Object $osInfo -Name 'BuildNumber')
+ if ([string]::IsNullOrWhiteSpace($value)) {
+ $value = Convert-ToCanonicalString (Get-OptionalMemberValue -Object $currentVersion -Name 'CurrentBuildNumber')
+ }
+ $value
+ } else {
+ ''
+ }
+ $ubrRaw = if ($IsWindows) { Get-OptionalMemberValue -Object $currentVersion -Name 'UBR' } else { $null }
+ $ubr = 0
+ if ($null -ne $ubrRaw -and [int]::TryParse(([string]$ubrRaw), [ref]$ubr)) {
+ $ubr = [int]$ubr
+ }
+
+ $canonical = [ordered]@{
+ version = $version
+ buildNumber = $buildNumber
+ ubr = $ubr
+ displayVersion = if ($IsWindows) { Convert-ToCanonicalString (Get-OptionalMemberValue -Object $currentVersion -Name 'DisplayVersion') } else { '' }
+ editionId = if ($IsWindows) { Convert-ToCanonicalString (Get-OptionalMemberValue -Object $currentVersion -Name 'EditionID') } else { '' }
+ installationType = if ($IsWindows) { Convert-ToCanonicalString (Get-OptionalMemberValue -Object $currentVersion -Name 'InstallationType') } else { '' }
+ architecture = if ($IsWindows) {
+ Convert-ToCanonicalString (Get-OptionalMemberValue -Object $osInfo -Name 'OSArchitecture')
+ } else {
+ Convert-ToCanonicalString ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)
+ }
+ systemType = if ($IsWindows) { Convert-ToCanonicalString (Get-OptionalMemberValue -Object $computerSystem -Name 'SystemType') } else { '' }
+ buildLabEx = if ($IsWindows) { Convert-ToCanonicalString (Get-OptionalMemberValue -Object $currentVersion -Name 'BuildLabEx') } else { '' }
+ }
+
+ $fingerprintPayload = [ordered]@{
+ platform = $platform
+ comparisonScope = 'isolated-lane-group'
+ canonical = $canonical
+ }
+ $fingerprintSha256 = Get-Sha256Hex -Value (($fingerprintPayload | ConvertTo-Json -Depth 8 -Compress))
+
+ $caption = if ($IsWindows) { Convert-ToCanonicalString (Get-OptionalMemberValue -Object $osInfo -Name 'Caption') } else { Convert-ToCanonicalString ([System.Runtime.InteropServices.RuntimeInformation]::OSDescription) }
+ $productName = if ($IsWindows) { Convert-ToCanonicalString (Get-OptionalMemberValue -Object $currentVersion -Name 'ProductName') } else { '' }
+ $brandingMismatch = $false
+ if (-not [string]::IsNullOrWhiteSpace($caption) -and -not [string]::IsNullOrWhiteSpace($productName)) {
+ $brandingMismatch = -not [string]::Equals($caption, $productName, [System.StringComparison]::OrdinalIgnoreCase)
+ }
+
+ return [pscustomobject][ordered]@{
+ role = 'canonical-host-baseline'
+ comparisonScope = 'isolated-lane-group'
+ platform = $platform
+ fingerprintSha256 = $fingerprintSha256
+ isolatedLaneGroupId = "host-os-fingerprint:$fingerprintSha256"
+ canonical = [pscustomobject]$canonical
+ advisory = [pscustomobject][ordered]@{
+ caption = $caption
+ productName = $productName
+ currentVersionCompatibility = if ($IsWindows) { Convert-ToCanonicalString (Get-OptionalMemberValue -Object $currentVersion -Name 'CurrentVersion') } else { '' }
+ brandingMismatch = $brandingMismatch
+ installDate = if ($IsWindows -and (Get-OptionalMemberValue -Object $osInfo -Name 'InstallDate')) { ([datetime](Get-OptionalMemberValue -Object $osInfo -Name 'InstallDate')).ToString('o') } else { '' }
+ lastBootUpTime = if ($IsWindows -and (Get-OptionalMemberValue -Object $osInfo -Name 'LastBootUpTime')) { ([datetime](Get-OptionalMemberValue -Object $osInfo -Name 'LastBootUpTime')).ToString('o') } else { '' }
+ }
+ sources = [pscustomobject][ordered]@{
+ registryPath = if ($IsWindows) { $registryPath } else { '' }
+ cimClass = if ($IsWindows) { 'Win32_OperatingSystem' } else { '' }
+ systemClass = if ($IsWindows) { 'Win32_ComputerSystem' } else { '' }
+ comparisonFields = @(
+ 'version',
+ 'buildNumber',
+ 'ubr',
+ 'displayVersion',
+ 'editionId',
+ 'installationType',
+ 'architecture',
+ 'systemType',
+ 'buildLabEx'
+ )
+ }
+ }
+}
+
function Get-HostPlaneIssues {
param(
[bool]$HasLabVIEW,
@@ -161,6 +302,7 @@ function Get-LabVIEW2026HostPlaneReport {
host = [ordered]@{
os = if ($IsWindows) { 'windows' } else { 'non-windows' }
computerName = [Environment]::MachineName
+ osFingerprint = Get-HostOperatingSystemFingerprint
}
runner = [ordered]@{
hostIsRunner = $true
diff --git a/tools/Post-IssueComment.ps1 b/tools/Post-IssueComment.ps1
index 3000f2b67..11888b950 100644
--- a/tools/Post-IssueComment.ps1
+++ b/tools/Post-IssueComment.ps1
@@ -11,6 +11,8 @@ param(
[string]$Body,
[switch]$EditLast,
+ [switch]$SkipBudgetHook,
+ [string]$BudgetHookMarkdownFile,
[switch]$Quiet
)
@@ -25,6 +27,123 @@ function Ensure-Gh {
Ensure-Gh
+$script:CommentBudgetHookStartMarker = ''
+$script:CommentBudgetHookEndMarker = ''
+$script:RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
+
+function Remove-CommentBudgetHook {
+ param(
+ [AllowNull()]
+ [string]$BodyText
+ )
+
+ if ([string]::IsNullOrWhiteSpace($BodyText)) {
+ return ''
+ }
+
+ $startIndex = $BodyText.IndexOf($script:CommentBudgetHookStartMarker, [System.StringComparison]::Ordinal)
+ if ($startIndex -lt 0) {
+ return $BodyText.TrimEnd("`r", "`n")
+ }
+
+ $endIndex = $BodyText.IndexOf($script:CommentBudgetHookEndMarker, $startIndex, [System.StringComparison]::Ordinal)
+ if ($endIndex -lt 0) {
+ return $BodyText.TrimEnd("`r", "`n")
+ }
+
+ $prefix = $BodyText.Substring(0, $startIndex).TrimEnd("`r", "`n")
+ $suffix = $BodyText.Substring($endIndex + $script:CommentBudgetHookEndMarker.Length).TrimStart("`r", "`n")
+
+ if (-not [string]::IsNullOrWhiteSpace($prefix) -and -not [string]::IsNullOrWhiteSpace($suffix)) {
+ return ($prefix + "`n`n" + $suffix).TrimEnd("`r", "`n")
+ }
+
+ return ($prefix + $suffix).TrimEnd("`r", "`n")
+}
+
+function New-CommentBudgetHookFailureMarkdown {
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]$Message
+ )
+
+ $sanitizedMessage = ($Message -replace '\s+', ' ').Trim()
+ return @(
+ $script:CommentBudgetHookStartMarker
+ "_Budget hook_: unavailable (`comment-budget-hook-generation-failed`): $sanitizedMessage."
+ $script:CommentBudgetHookEndMarker
+ ) -join "`n"
+}
+
+function Get-CommentBudgetHookMarkdown {
+ param(
+ [Parameter(Mandatory=$true)]
+ [ValidateSet('issue', 'pr')]
+ [string]$TargetKind,
+
+ [Parameter(Mandatory=$true)]
+ [int]$TargetNumber,
+
+ [string]$Repo,
+
+ [string]$MarkdownFile,
+
+ [switch]$SkipHook
+ )
+
+ if ($SkipHook) {
+ return ''
+ }
+
+ if (-not [string]::IsNullOrWhiteSpace($MarkdownFile)) {
+ return (Get-Content -LiteralPath (Resolve-Path -LiteralPath $MarkdownFile -ErrorAction Stop).Path -Raw)
+ }
+
+ $hookScriptPath = Join-Path $script:RepoRoot 'tools' 'priority' 'github-comment-budget-hook.mjs'
+ $hookMarkdownPath = Join-Path $script:RepoRoot 'tests' 'results' '_agent' 'cost' 'github-comment-budget-hook.md'
+ $hookArgs = @(
+ $hookScriptPath,
+ '--repo-root', $script:RepoRoot,
+ '--target-kind', $TargetKind,
+ '--target-number', $TargetNumber.ToString(),
+ '--markdown-output', $hookMarkdownPath
+ )
+ if (-not [string]::IsNullOrWhiteSpace($Repo)) {
+ $hookArgs += @('--repo', $Repo.Trim())
+ }
+
+ try {
+ & node @hookArgs | Out-Null
+ if (-not $?) {
+ $exitCode = if (Test-Path variable:LASTEXITCODE) { $LASTEXITCODE } else { $null }
+ throw "github-comment-budget-hook exited with code $exitCode."
+ }
+ return (Get-Content -LiteralPath $hookMarkdownPath -Raw)
+ } catch {
+ return New-CommentBudgetHookFailureMarkdown -Message $_.Exception.Message
+ }
+}
+
+function Merge-CommentBudgetHook {
+ param(
+ [AllowNull()]
+ [string]$BodyText,
+
+ [AllowNull()]
+ [string]$HookMarkdown
+ )
+
+ $cleanBody = Remove-CommentBudgetHook -BodyText $BodyText
+ if ([string]::IsNullOrWhiteSpace($HookMarkdown)) {
+ return $cleanBody
+ }
+ $normalizedHook = $HookMarkdown.TrimEnd("`r", "`n")
+ if ([string]::IsNullOrWhiteSpace($cleanBody)) {
+ return $normalizedHook
+ }
+ return ($cleanBody.TrimEnd("`r", "`n") + "`n`n" + $normalizedHook).TrimEnd("`r", "`n")
+}
+
function Invoke-GhIssueComment {
param(
[Parameter(Mandatory=$true)]
@@ -49,16 +168,27 @@ if ($EditLast) {
switch ($PSCmdlet.ParameterSetName) {
'BodyFile' {
$resolved = Resolve-Path -LiteralPath $BodyFile -ErrorAction Stop
- $args = $issueArg + @('--body-file', $resolved.Path)
+ $bodyText = Get-Content -LiteralPath $resolved.Path -Raw
+ $hookMarkdown = Get-CommentBudgetHookMarkdown -TargetKind issue -TargetNumber $Issue -MarkdownFile $BudgetHookMarkdownFile -SkipHook:$SkipBudgetHook
+ $mergedBody = Merge-CommentBudgetHook -BodyText $bodyText -HookMarkdown $hookMarkdown
+ $temp = [System.IO.Path]::GetTempFileName()
+ Set-Content -LiteralPath $temp -Value $mergedBody -Encoding utf8
+ $args = $issueArg + @('--body-file', $temp)
if (-not $Quiet) {
Write-Host ("Posting comment from file '{0}' to issue #{1}..." -f $resolved.Path, $Issue)
}
- Invoke-GhIssueComment -Arguments $args
+ try {
+ Invoke-GhIssueComment -Arguments $args
+ } finally {
+ Remove-Item -LiteralPath $temp -ErrorAction SilentlyContinue
+ }
}
'Body' {
$temp = [System.IO.Path]::GetTempFileName()
try {
- Set-Content -LiteralPath $temp -Value $Body -Encoding utf8
+ $hookMarkdown = Get-CommentBudgetHookMarkdown -TargetKind issue -TargetNumber $Issue -MarkdownFile $BudgetHookMarkdownFile -SkipHook:$SkipBudgetHook
+ $mergedBody = Merge-CommentBudgetHook -BodyText $Body -HookMarkdown $hookMarkdown
+ Set-Content -LiteralPath $temp -Value $mergedBody -Encoding utf8
$args = $issueArg + @('--body-file', $temp)
if (-not $Quiet) {
Write-Host ("Posting comment to issue #{0} using temporary body file..." -f $Issue)
diff --git a/tools/Post-PullRequestComment.ps1 b/tools/Post-PullRequestComment.ps1
index ed8acfdb0..6b663b776 100644
--- a/tools/Post-PullRequestComment.ps1
+++ b/tools/Post-PullRequestComment.ps1
@@ -14,6 +14,8 @@ param(
[string]$Body,
[switch]$EditLast,
+ [switch]$SkipBudgetHook,
+ [string]$BudgetHookMarkdownFile,
[switch]$Quiet
)
@@ -44,6 +46,123 @@ function Invoke-GhPullRequestComment {
Ensure-Gh
+$script:CommentBudgetHookStartMarker = ''
+$script:CommentBudgetHookEndMarker = ''
+$script:RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
+
+function Remove-CommentBudgetHook {
+ param(
+ [AllowNull()]
+ [string]$BodyText
+ )
+
+ if ([string]::IsNullOrWhiteSpace($BodyText)) {
+ return ''
+ }
+
+ $startIndex = $BodyText.IndexOf($script:CommentBudgetHookStartMarker, [System.StringComparison]::Ordinal)
+ if ($startIndex -lt 0) {
+ return $BodyText.TrimEnd("`r", "`n")
+ }
+
+ $endIndex = $BodyText.IndexOf($script:CommentBudgetHookEndMarker, $startIndex, [System.StringComparison]::Ordinal)
+ if ($endIndex -lt 0) {
+ return $BodyText.TrimEnd("`r", "`n")
+ }
+
+ $prefix = $BodyText.Substring(0, $startIndex).TrimEnd("`r", "`n")
+ $suffix = $BodyText.Substring($endIndex + $script:CommentBudgetHookEndMarker.Length).TrimStart("`r", "`n")
+
+ if (-not [string]::IsNullOrWhiteSpace($prefix) -and -not [string]::IsNullOrWhiteSpace($suffix)) {
+ return ($prefix + "`n`n" + $suffix).TrimEnd("`r", "`n")
+ }
+
+ return ($prefix + $suffix).TrimEnd("`r", "`n")
+}
+
+function New-CommentBudgetHookFailureMarkdown {
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]$Message
+ )
+
+ $sanitizedMessage = ($Message -replace '\s+', ' ').Trim()
+ return @(
+ $script:CommentBudgetHookStartMarker
+ "_Budget hook_: unavailable (`comment-budget-hook-generation-failed`): $sanitizedMessage."
+ $script:CommentBudgetHookEndMarker
+ ) -join "`n"
+}
+
+function Get-CommentBudgetHookMarkdown {
+ param(
+ [Parameter(Mandatory=$true)]
+ [ValidateSet('issue', 'pr')]
+ [string]$TargetKind,
+
+ [Parameter(Mandatory=$true)]
+ [int]$TargetNumber,
+
+ [string]$Repo,
+
+ [string]$MarkdownFile,
+
+ [switch]$SkipHook
+ )
+
+ if ($SkipHook) {
+ return ''
+ }
+
+ if (-not [string]::IsNullOrWhiteSpace($MarkdownFile)) {
+ return (Get-Content -LiteralPath (Resolve-Path -LiteralPath $MarkdownFile -ErrorAction Stop).Path -Raw)
+ }
+
+ $hookScriptPath = Join-Path $script:RepoRoot 'tools' 'priority' 'github-comment-budget-hook.mjs'
+ $hookMarkdownPath = Join-Path $script:RepoRoot 'tests' 'results' '_agent' 'cost' 'github-comment-budget-hook.md'
+ $hookArgs = @(
+ $hookScriptPath,
+ '--repo-root', $script:RepoRoot,
+ '--target-kind', $TargetKind,
+ '--target-number', $TargetNumber.ToString(),
+ '--markdown-output', $hookMarkdownPath
+ )
+ if (-not [string]::IsNullOrWhiteSpace($Repo)) {
+ $hookArgs += @('--repo', $Repo.Trim())
+ }
+
+ try {
+ & node @hookArgs | Out-Null
+ if (-not $?) {
+ $exitCode = if (Test-Path variable:LASTEXITCODE) { $LASTEXITCODE } else { $null }
+ throw "github-comment-budget-hook exited with code $exitCode."
+ }
+ return (Get-Content -LiteralPath $hookMarkdownPath -Raw)
+ } catch {
+ return New-CommentBudgetHookFailureMarkdown -Message $_.Exception.Message
+ }
+}
+
+function Merge-CommentBudgetHook {
+ param(
+ [AllowNull()]
+ [string]$BodyText,
+
+ [AllowNull()]
+ [string]$HookMarkdown
+ )
+
+ $cleanBody = Remove-CommentBudgetHook -BodyText $BodyText
+ if ([string]::IsNullOrWhiteSpace($HookMarkdown)) {
+ return $cleanBody
+ }
+ $normalizedHook = $HookMarkdown.TrimEnd("`r", "`n")
+ if ([string]::IsNullOrWhiteSpace($cleanBody)) {
+ return $normalizedHook
+ }
+ return ($cleanBody.TrimEnd("`r", "`n") + "`n`n" + $normalizedHook).TrimEnd("`r", "`n")
+}
+
$commentArgs = @('pr', 'comment', $PullRequest.ToString())
if (-not [string]::IsNullOrWhiteSpace($Repo)) {
$commentArgs += @('--repo', $Repo.Trim())
@@ -55,16 +174,27 @@ if ($EditLast) {
switch ($PSCmdlet.ParameterSetName) {
'BodyFile' {
$resolved = Resolve-Path -LiteralPath $BodyFile -ErrorAction Stop
- $args = $commentArgs + @('--body-file', $resolved.Path)
+ $bodyText = Get-Content -LiteralPath $resolved.Path -Raw
+ $hookMarkdown = Get-CommentBudgetHookMarkdown -TargetKind pr -TargetNumber $PullRequest -Repo $Repo -MarkdownFile $BudgetHookMarkdownFile -SkipHook:$SkipBudgetHook
+ $mergedBody = Merge-CommentBudgetHook -BodyText $bodyText -HookMarkdown $hookMarkdown
+ $temp = [System.IO.Path]::GetTempFileName()
+ Set-Content -LiteralPath $temp -Value $mergedBody -Encoding utf8
+ $args = $commentArgs + @('--body-file', $temp)
if (-not $Quiet) {
Write-Host ("Posting comment from file '{0}' to PR #{1}..." -f $resolved.Path, $PullRequest)
}
- Invoke-GhPullRequestComment -Arguments $args
+ try {
+ Invoke-GhPullRequestComment -Arguments $args
+ } finally {
+ Remove-Item -LiteralPath $temp -ErrorAction SilentlyContinue
+ }
}
'Body' {
$temp = [System.IO.Path]::GetTempFileName()
try {
- Set-Content -LiteralPath $temp -Value $Body -Encoding utf8
+ $hookMarkdown = Get-CommentBudgetHookMarkdown -TargetKind pr -TargetNumber $PullRequest -Repo $Repo -MarkdownFile $BudgetHookMarkdownFile -SkipHook:$SkipBudgetHook
+ $mergedBody = Merge-CommentBudgetHook -BodyText $Body -HookMarkdown $hookMarkdown
+ Set-Content -LiteralPath $temp -Value $mergedBody -Encoding utf8
$args = $commentArgs + @('--body-file', $temp)
if (-not $Quiet) {
Write-Host ("Posting comment to PR #{0} using temporary body file..." -f $PullRequest)
diff --git a/tools/Print-AgentHandoff.ps1 b/tools/Print-AgentHandoff.ps1
index 823b322a1..37e559b83 100644
--- a/tools/Print-AgentHandoff.ps1
+++ b/tools/Print-AgentHandoff.ps1
@@ -1293,19 +1293,27 @@ try {
$templateVerificationSyncScript = Join-Path $repoRoot 'tools' 'priority' 'sync-template-agent-verification-report.mjs'
$templatePivotGateScript = Join-Path $repoRoot 'tools' 'priority' 'template-pivot-gate.mjs'
$monitoringModeScript = Join-Path $repoRoot 'tools' 'priority' 'handoff-monitoring-mode.mjs'
+ $releasePublishedBundleObserverScript = Join-Path $repoRoot 'tools' 'priority' 'release-published-bundle-observer.mjs'
+ $releaseSigningReadinessScript = Join-Path $repoRoot 'tools' 'priority' 'release-signing-readiness.mjs'
$governorSummaryScript = Join-Path $repoRoot 'tools' 'priority' 'autonomous-governor-summary.mjs'
$governorPortfolioSummaryScript = Join-Path $repoRoot 'tools' 'priority' 'autonomous-governor-portfolio-summary.mjs'
+ $contextConcentratorScript = Join-Path $repoRoot 'tools' 'priority' 'sagan-context-concentrator.mjs'
$nodeCmd = Get-Command node -ErrorAction SilentlyContinue
if ($nodeCmd) {
$promotionDir = Join-Path $ResultsRoot '_agent/promotion'
+ $releaseDir = Join-Path $ResultsRoot '_agent/release'
$handoffDir = Join-Path $ResultsRoot '_agent/handoff'
New-Item -ItemType Directory -Force -Path $promotionDir | Out-Null
+ New-Item -ItemType Directory -Force -Path $releaseDir | Out-Null
New-Item -ItemType Directory -Force -Path $handoffDir | Out-Null
$templateVerificationSeedPath = Join-Path $promotionDir 'template-agent-verification-report.json'
$templateVerificationOverlayPath = Join-Path $promotionDir 'template-agent-verification-report.local.json'
$templateVerificationSyncPath = Join-Path $promotionDir 'template-agent-verification-sync.json'
$templatePivotGatePath = Join-Path $promotionDir 'template-pivot-gate-report.json'
+ $releaseConductorReportPath = Join-Path $releaseDir 'release-conductor-report.json'
+ $releasePublishedBundleObserverPath = Join-Path $releaseDir 'release-published-bundle-observer.json'
+ $releaseSigningReadinessPath = Join-Path $releaseDir 'release-signing-readiness.json'
$queueEmptyReportPath = Join-Path $repoRoot 'tests/results/_agent/issue/no-standing-priority.json'
$entrypointStatusPath = Join-Path $ResultsRoot '_agent/handoff/entrypoint-status.json'
$continuitySummaryPath = Join-Path $ResultsRoot '_agent/handoff/continuity-summary.json'
@@ -1313,6 +1321,7 @@ try {
$monitoringModePath = Join-Path $handoffDir 'monitoring-mode.json'
$governorSummaryPath = Join-Path $handoffDir 'autonomous-governor-summary.json'
$governorPortfolioSummaryPath = Join-Path $handoffDir 'autonomous-governor-portfolio-summary.json'
+ $contextConcentratorPath = Join-Path $handoffDir 'sagan-context-concentrator.json'
if (Test-Path -LiteralPath $repoGraphTruthScript -PathType Leaf) {
& $nodeCmd.Source $repoGraphTruthScript `
@@ -1346,12 +1355,27 @@ try {
--output $monitoringModePath | Out-Host
}
+ if (Test-Path -LiteralPath $releasePublishedBundleObserverScript -PathType Leaf) {
+ & $nodeCmd.Source $releasePublishedBundleObserverScript `
+ --repo-root $repoRoot `
+ --output $releasePublishedBundleObserverPath | Out-Host
+ }
+
+ if (Test-Path -LiteralPath $releaseSigningReadinessScript -PathType Leaf) {
+ & $nodeCmd.Source $releaseSigningReadinessScript `
+ --repo-root $repoRoot `
+ --release-conductor-report $releaseConductorReportPath `
+ --release-published-bundle-observer $releasePublishedBundleObserverPath `
+ --output $releaseSigningReadinessPath | Out-Host
+ }
+
if (Test-Path -LiteralPath $governorSummaryScript -PathType Leaf) {
& $nodeCmd.Source $governorSummaryScript `
--repo-root $repoRoot `
--queue-empty-report $queueEmptyReportPath `
--continuity-summary $continuitySummaryPath `
--monitoring-mode $monitoringModePath `
+ --release-signing-readiness $releaseSigningReadinessPath `
--output $governorSummaryPath | Out-Host
}
@@ -1363,6 +1387,18 @@ try {
--repo-graph-truth $repoGraphTruthPath `
--output $governorPortfolioSummaryPath | Out-Host
}
+
+ if (Test-Path -LiteralPath $contextConcentratorScript -PathType Leaf) {
+ & $nodeCmd.Source $contextConcentratorScript `
+ --repo-root $repoRoot `
+ --priority-cache (Join-Path $repoRoot '.agent_priority_cache.json') `
+ --governor-summary $governorSummaryPath `
+ --governor-portfolio-summary $governorPortfolioSummaryPath `
+ --monitoring-mode $monitoringModePath `
+ --operator-steering-event (Join-Path $handoffDir 'operator-steering-event.json') `
+ --episode-directory (Join-Path $ResultsRoot '_agent/memory/subagent-episodes') `
+ --output $contextConcentratorPath | Out-Host
+ }
}
} catch {
Write-Warning ("Failed to refresh monitoring-mode handoff state: {0}" -f $_.Exception.Message)
@@ -1517,6 +1553,21 @@ try {
Write-Host (" next : {0}" -f (Format-NullableValue $governor.summary.nextAction))
Write-Host (" signal : {0}" -f (Format-NullableValue $governor.summary.signalQuality))
Write-Host (" queue : {0}" -f (Format-NullableValue $governor.summary.queueState))
+ if ($governor.summary.PSObject.Properties['releaseSigningStatus']) {
+ Write-Host (" signing : {0}" -f (Format-NullableValue $governor.summary.releaseSigningStatus))
+ if ($governor.summary.PSObject.Properties['releaseSigningExternalBlocker'] -and $governor.summary.releaseSigningExternalBlocker) {
+ Write-Host (" blocker : {0}" -f (Format-NullableValue $governor.summary.releaseSigningExternalBlocker))
+ }
+ if ($governor.summary.PSObject.Properties['releasePublicationState'] -and $governor.summary.releasePublicationState) {
+ Write-Host (" publish : {0}" -f (Format-NullableValue $governor.summary.releasePublicationState))
+ }
+ if ($governor.summary.PSObject.Properties['releasePublishedBundleState'] -and $governor.summary.releasePublishedBundleState) {
+ Write-Host (" bundle : {0}" -f (Format-NullableValue $governor.summary.releasePublishedBundleState))
+ }
+ if ($governor.summary.PSObject.Properties['releasePublishedBundleReleaseTag'] -and $governor.summary.releasePublishedBundleReleaseTag) {
+ Write-Host (" bundleTag: {0}" -f (Format-NullableValue $governor.summary.releasePublishedBundleReleaseTag))
+ }
+ }
if ($governor.summary.nextOwnerRepository) {
Write-Host (" nextRepo : {0}" -f (Format-NullableValue $governor.summary.nextOwnerRepository))
}
@@ -1532,6 +1583,39 @@ try {
Write-Host (" pr : {0}" -f (Format-NullableValue $governor.summary.queueHandoffPrUrl))
}
}
+ if ($governor.summary.PSObject.Properties['executionTopologyStatus'] -and $governor.summary.executionTopologyStatus) {
+ Write-Host (" execTopo : {0}" -f (Format-NullableValue $governor.summary.executionTopologyStatus))
+ Write-Host (" execProv : {0}" -f (Format-NullableValue $governor.summary.executionTopologyProviderId))
+ Write-Host (" execSlot : {0}" -f (Format-NullableValue $governor.summary.executionTopologyWorkerSlotId))
+ Write-Host (" execLanes: {0}/{1}" -f
+ (Format-NullableValue $governor.summary.executionTopologyActiveLogicalLaneCount),
+ (Format-NullableValue $governor.summary.executionTopologySeededLogicalLaneCount))
+ if ($governor.summary.PSObject.Properties['executionTopologyRuntimeSurface'] -and $governor.summary.executionTopologyRuntimeSurface) {
+ Write-Host (" execSurf : {0}" -f (Format-NullableValue $governor.summary.executionTopologyRuntimeSurface))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologyProcessModelClass'] -and $governor.summary.executionTopologyProcessModelClass) {
+ Write-Host (" execProc : {0}" -f (Format-NullableValue $governor.summary.executionTopologyProcessModelClass))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologyRequestedSimultaneous'] -and $governor.summary.executionTopologyRequestedSimultaneous) {
+ Write-Host (" execSim : {0}" -f (Format-NullableValue $governor.summary.executionTopologyRequestedSimultaneous))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologyCellClass'] -and $governor.summary.executionTopologyCellClass) {
+ Write-Host (" execCell : {0}" -f (Format-NullableValue $governor.summary.executionTopologyCellClass))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologySuiteClass'] -and $governor.summary.executionTopologySuiteClass) {
+ Write-Host (" execSuite: {0}" -f (Format-NullableValue $governor.summary.executionTopologySuiteClass))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologyOperatorAuthorizationRef'] -and $governor.summary.executionTopologyOperatorAuthorizationRef) {
+ Write-Host (" execAuth : {0}" -f (Format-NullableValue $governor.summary.executionTopologyOperatorAuthorizationRef))
+ }
+ }
+ if ($governor.summary.PSObject.Properties['executionBundleStatus'] -and $governor.summary.executionBundleStatus) {
+ Write-Host (" exec : {0}" -f (Format-NullableValue $governor.summary.executionBundleStatus))
+ Write-Host (" execPlan : {0}" -f (Format-NullableValue $governor.summary.executionBundlePlaneBinding))
+ Write-Host (" execPrem : {0}" -f (Format-NullableValue $governor.summary.executionBundlePremiumSaganMode))
+ Write-Host (" execLink : {0}" -f (Format-NullableValue $governor.summary.executionBundleReciprocalLinkReady))
+ Write-Host (" execRate : {0}" -f (Format-NullableValue $governor.summary.executionBundleEffectiveBillableRateUsdPerHour))
+ }
if ($env:GITHUB_STEP_SUMMARY) {
$governorLines = @(
'### Autonomous Governor',
@@ -1542,6 +1626,21 @@ try {
('- Signal quality: {0}' -f (Format-NullableValue $governor.summary.signalQuality)),
('- Queue state: {0}' -f (Format-NullableValue $governor.summary.queueState))
)
+ if ($governor.summary.PSObject.Properties['releaseSigningStatus']) {
+ $governorLines += ('- Release signing: {0}' -f (Format-NullableValue $governor.summary.releaseSigningStatus))
+ if ($governor.summary.PSObject.Properties['releaseSigningExternalBlocker'] -and $governor.summary.releaseSigningExternalBlocker) {
+ $governorLines += ('- Release blocker: {0}' -f (Format-NullableValue $governor.summary.releaseSigningExternalBlocker))
+ }
+ if ($governor.summary.PSObject.Properties['releasePublicationState'] -and $governor.summary.releasePublicationState) {
+ $governorLines += ('- Release publication: {0}' -f (Format-NullableValue $governor.summary.releasePublicationState))
+ }
+ if ($governor.summary.PSObject.Properties['releasePublishedBundleState'] -and $governor.summary.releasePublishedBundleState) {
+ $governorLines += ('- Published bundle: {0}' -f (Format-NullableValue $governor.summary.releasePublishedBundleState))
+ }
+ if ($governor.summary.PSObject.Properties['releasePublishedBundleReleaseTag'] -and $governor.summary.releasePublishedBundleReleaseTag) {
+ $governorLines += ('- Published bundle tag: {0}' -f (Format-NullableValue $governor.summary.releasePublishedBundleReleaseTag))
+ }
+ }
if ($governor.summary.nextOwnerRepository) {
$governorLines += ('- Next owner: {0}' -f (Format-NullableValue $governor.summary.nextOwnerRepository))
}
@@ -1557,6 +1656,39 @@ try {
$governorLines += ('- Queue PR: {0}' -f (Format-NullableValue $governor.summary.queueHandoffPrUrl))
}
}
+ if ($governor.summary.PSObject.Properties['executionTopologyStatus'] -and $governor.summary.executionTopologyStatus) {
+ $governorLines += ('- Execution topology: {0}' -f (Format-NullableValue $governor.summary.executionTopologyStatus))
+ $governorLines += ('- Execution provider: {0}' -f (Format-NullableValue $governor.summary.executionTopologyProviderId))
+ $governorLines += ('- Execution worker slot: {0}' -f (Format-NullableValue $governor.summary.executionTopologyWorkerSlotId))
+ $governorLines += ('- Execution logical lanes active/seeded: {0}/{1}' -f
+ (Format-NullableValue $governor.summary.executionTopologyActiveLogicalLaneCount),
+ (Format-NullableValue $governor.summary.executionTopologySeededLogicalLaneCount))
+ if ($governor.summary.PSObject.Properties['executionTopologyRuntimeSurface'] -and $governor.summary.executionTopologyRuntimeSurface) {
+ $governorLines += ('- Execution runtime surface: {0}' -f (Format-NullableValue $governor.summary.executionTopologyRuntimeSurface))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologyProcessModelClass'] -and $governor.summary.executionTopologyProcessModelClass) {
+ $governorLines += ('- Execution process model: {0}' -f (Format-NullableValue $governor.summary.executionTopologyProcessModelClass))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologyRequestedSimultaneous'] -and $governor.summary.executionTopologyRequestedSimultaneous) {
+ $governorLines += ('- Execution simultaneous: {0}' -f (Format-NullableValue $governor.summary.executionTopologyRequestedSimultaneous))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologyCellClass'] -and $governor.summary.executionTopologyCellClass) {
+ $governorLines += ('- Execution cell class: {0}' -f (Format-NullableValue $governor.summary.executionTopologyCellClass))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologySuiteClass'] -and $governor.summary.executionTopologySuiteClass) {
+ $governorLines += ('- Execution suite class: {0}' -f (Format-NullableValue $governor.summary.executionTopologySuiteClass))
+ }
+ if ($governor.summary.PSObject.Properties['executionTopologyOperatorAuthorizationRef'] -and $governor.summary.executionTopologyOperatorAuthorizationRef) {
+ $governorLines += ('- Execution operator authorization: {0}' -f (Format-NullableValue $governor.summary.executionTopologyOperatorAuthorizationRef))
+ }
+ }
+ if ($governor.summary.PSObject.Properties['executionBundleStatus'] -and $governor.summary.executionBundleStatus) {
+ $governorLines += ('- Execution bundle: {0}' -f (Format-NullableValue $governor.summary.executionBundleStatus))
+ $governorLines += ('- Execution plane: {0}' -f (Format-NullableValue $governor.summary.executionBundlePlaneBinding))
+ $governorLines += ('- Premium Sagan mode: {0}' -f (Format-NullableValue $governor.summary.executionBundlePremiumSaganMode))
+ $governorLines += ('- Execution reciprocal link: {0}' -f (Format-NullableValue $governor.summary.executionBundleReciprocalLinkReady))
+ $governorLines += ('- Execution effective rate USD/hr: {0}' -f (Format-NullableValue $governor.summary.executionBundleEffectiveBillableRateUsdPerHour))
+ }
($governorLines -join "`n") | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
}
}
@@ -1575,6 +1707,21 @@ try {
Write-Host (" next : {0}" -f (Format-NullableValue $portfolio.summary.nextAction))
Write-Host (" template : {0}" -f (Format-NullableValue $portfolio.summary.templateMonitoringStatus))
Write-Host (" proof : {0}" -f (Format-NullableValue $portfolio.summary.supportedProofStatus))
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyStatus']) {
+ Write-Host (" vhist : {0}" -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyStatus))
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyTargetRepository'] -and $portfolio.summary.viHistoryDistributorDependencyTargetRepository) {
+ Write-Host (" vhistRepo: {0}" -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyTargetRepository))
+ }
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyExternalBlocker'] -and $portfolio.summary.viHistoryDistributorDependencyExternalBlocker) {
+ Write-Host (" vhistBlk : {0}" -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyExternalBlocker))
+ }
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyPublishedBundleState'] -and $portfolio.summary.viHistoryDistributorDependencyPublishedBundleState) {
+ Write-Host (" vhistPub : {0}" -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyPublishedBundleState))
+ }
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyPublishedBundleReleaseTag'] -and $portfolio.summary.viHistoryDistributorDependencyPublishedBundleReleaseTag) {
+ Write-Host (" vhistTag : {0}" -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyPublishedBundleReleaseTag))
+ }
+ }
if ($portfolio.summary.nextOwnerRepository) {
Write-Host (" nextRepo : {0}" -f (Format-NullableValue $portfolio.summary.nextOwnerRepository))
}
@@ -1586,6 +1733,39 @@ try {
Write-Host (" queueSrc : {0}" -f (Format-NullableValue $portfolio.summary.queueAuthoritySource))
}
}
+ if ($portfolio.summary.PSObject.Properties['executionTopologyStatus'] -and $portfolio.summary.executionTopologyStatus) {
+ Write-Host (" execTopo : {0}" -f (Format-NullableValue $portfolio.summary.executionTopologyStatus))
+ Write-Host (" execProv : {0}" -f (Format-NullableValue $portfolio.summary.executionTopologyProviderId))
+ Write-Host (" execSlot : {0}" -f (Format-NullableValue $portfolio.summary.executionTopologyWorkerSlotId))
+ Write-Host (" execLanes: {0}/{1}" -f
+ (Format-NullableValue $portfolio.summary.executionTopologyActiveLogicalLaneCount),
+ (Format-NullableValue $portfolio.summary.executionTopologySeededLogicalLaneCount))
+ if ($portfolio.summary.PSObject.Properties['executionTopologyRuntimeSurface'] -and $portfolio.summary.executionTopologyRuntimeSurface) {
+ Write-Host (" execSurf : {0}" -f (Format-NullableValue $portfolio.summary.executionTopologyRuntimeSurface))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologyProcessModelClass'] -and $portfolio.summary.executionTopologyProcessModelClass) {
+ Write-Host (" execProc : {0}" -f (Format-NullableValue $portfolio.summary.executionTopologyProcessModelClass))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologyRequestedSimultaneous'] -and $portfolio.summary.executionTopologyRequestedSimultaneous) {
+ Write-Host (" execSim : {0}" -f (Format-NullableValue $portfolio.summary.executionTopologyRequestedSimultaneous))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologyCellClass'] -and $portfolio.summary.executionTopologyCellClass) {
+ Write-Host (" execCell : {0}" -f (Format-NullableValue $portfolio.summary.executionTopologyCellClass))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologySuiteClass'] -and $portfolio.summary.executionTopologySuiteClass) {
+ Write-Host (" execSuite: {0}" -f (Format-NullableValue $portfolio.summary.executionTopologySuiteClass))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologyOperatorAuthorizationRef'] -and $portfolio.summary.executionTopologyOperatorAuthorizationRef) {
+ Write-Host (" execAuth : {0}" -f (Format-NullableValue $portfolio.summary.executionTopologyOperatorAuthorizationRef))
+ }
+ }
+ if ($portfolio.summary.PSObject.Properties['executionBundleStatus'] -and $portfolio.summary.executionBundleStatus) {
+ Write-Host (" exec : {0}" -f (Format-NullableValue $portfolio.summary.executionBundleStatus))
+ Write-Host (" execPlan : {0}" -f (Format-NullableValue $portfolio.summary.executionBundlePlaneBinding))
+ Write-Host (" execPrem : {0}" -f (Format-NullableValue $portfolio.summary.executionBundlePremiumSaganMode))
+ Write-Host (" execLink : {0}" -f (Format-NullableValue $portfolio.summary.executionBundleReciprocalLinkReady))
+ Write-Host (" execRate : {0}" -f (Format-NullableValue $portfolio.summary.executionBundleEffectiveBillableRateUsdPerHour))
+ }
if ($env:GITHUB_STEP_SUMMARY) {
$portfolioLines = @(
'### Governor Portfolio',
@@ -1596,6 +1776,21 @@ try {
('- Template monitoring: {0}' -f (Format-NullableValue $portfolio.summary.templateMonitoringStatus)),
('- Supported proof: {0}' -f (Format-NullableValue $portfolio.summary.supportedProofStatus))
)
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyStatus']) {
+ $portfolioLines += ('- VI-history dependency: {0}' -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyStatus))
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyTargetRepository'] -and $portfolio.summary.viHistoryDistributorDependencyTargetRepository) {
+ $portfolioLines += ('- VI-history target: {0}' -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyTargetRepository))
+ }
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyExternalBlocker'] -and $portfolio.summary.viHistoryDistributorDependencyExternalBlocker) {
+ $portfolioLines += ('- VI-history blocker: {0}' -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyExternalBlocker))
+ }
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyPublishedBundleState'] -and $portfolio.summary.viHistoryDistributorDependencyPublishedBundleState) {
+ $portfolioLines += ('- VI-history published bundle: {0}' -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyPublishedBundleState))
+ }
+ if ($portfolio.summary.PSObject.Properties['viHistoryDistributorDependencyPublishedBundleReleaseTag'] -and $portfolio.summary.viHistoryDistributorDependencyPublishedBundleReleaseTag) {
+ $portfolioLines += ('- VI-history published bundle tag: {0}' -f (Format-NullableValue $portfolio.summary.viHistoryDistributorDependencyPublishedBundleReleaseTag))
+ }
+ }
if ($portfolio.summary.nextOwnerRepository) {
$portfolioLines += ('- Next owner: {0}' -f (Format-NullableValue $portfolio.summary.nextOwnerRepository))
}
@@ -1607,6 +1802,39 @@ try {
$portfolioLines += ('- Queue source: {0}' -f (Format-NullableValue $portfolio.summary.queueAuthoritySource))
}
}
+ if ($portfolio.summary.PSObject.Properties['executionTopologyStatus'] -and $portfolio.summary.executionTopologyStatus) {
+ $portfolioLines += ('- Execution topology: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologyStatus))
+ $portfolioLines += ('- Execution provider: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologyProviderId))
+ $portfolioLines += ('- Execution worker slot: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologyWorkerSlotId))
+ $portfolioLines += ('- Execution logical lanes active/seeded: {0}/{1}' -f
+ (Format-NullableValue $portfolio.summary.executionTopologyActiveLogicalLaneCount),
+ (Format-NullableValue $portfolio.summary.executionTopologySeededLogicalLaneCount))
+ if ($portfolio.summary.PSObject.Properties['executionTopologyRuntimeSurface'] -and $portfolio.summary.executionTopologyRuntimeSurface) {
+ $portfolioLines += ('- Execution runtime surface: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologyRuntimeSurface))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologyProcessModelClass'] -and $portfolio.summary.executionTopologyProcessModelClass) {
+ $portfolioLines += ('- Execution process model: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologyProcessModelClass))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologyRequestedSimultaneous'] -and $portfolio.summary.executionTopologyRequestedSimultaneous) {
+ $portfolioLines += ('- Execution simultaneous: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologyRequestedSimultaneous))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologyCellClass'] -and $portfolio.summary.executionTopologyCellClass) {
+ $portfolioLines += ('- Execution cell class: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologyCellClass))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologySuiteClass'] -and $portfolio.summary.executionTopologySuiteClass) {
+ $portfolioLines += ('- Execution suite class: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologySuiteClass))
+ }
+ if ($portfolio.summary.PSObject.Properties['executionTopologyOperatorAuthorizationRef'] -and $portfolio.summary.executionTopologyOperatorAuthorizationRef) {
+ $portfolioLines += ('- Execution operator authorization: {0}' -f (Format-NullableValue $portfolio.summary.executionTopologyOperatorAuthorizationRef))
+ }
+ }
+ if ($portfolio.summary.PSObject.Properties['executionBundleStatus'] -and $portfolio.summary.executionBundleStatus) {
+ $portfolioLines += ('- Execution bundle: {0}' -f (Format-NullableValue $portfolio.summary.executionBundleStatus))
+ $portfolioLines += ('- Execution plane: {0}' -f (Format-NullableValue $portfolio.summary.executionBundlePlaneBinding))
+ $portfolioLines += ('- Premium Sagan mode: {0}' -f (Format-NullableValue $portfolio.summary.executionBundlePremiumSaganMode))
+ $portfolioLines += ('- Execution reciprocal link: {0}' -f (Format-NullableValue $portfolio.summary.executionBundleReciprocalLinkReady))
+ $portfolioLines += ('- Execution effective rate USD/hr: {0}' -f (Format-NullableValue $portfolio.summary.executionBundleEffectiveBillableRateUsdPerHour))
+ }
($portfolioLines -join "`n") | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
}
}
@@ -1614,6 +1842,49 @@ try {
Write-Warning ("Failed to display governor portfolio summary: {0}" -f $_.Exception.Message)
}
+try {
+ $contextConcentratorPath = Join-Path $ResultsRoot '_agent/handoff/sagan-context-concentrator.json'
+ if (Test-Path -LiteralPath $contextConcentratorPath -PathType Leaf) {
+ $concentrator = Get-Content -LiteralPath $contextConcentratorPath -Raw | ConvertFrom-Json -ErrorAction Stop
+ Write-Host ''
+ Write-Host '[Context Concentrator]' -ForegroundColor Cyan
+ Write-Host (" status : {0}" -f (Format-NullableValue $concentrator.summary.concentrationStatus))
+ if ($concentrator.summary.activeIssueNumber) {
+ Write-Host (" issue : #{0}" -f (Format-NullableValue $concentrator.summary.activeIssueNumber))
+ }
+ Write-Host (" owner : {0}" -f (Format-NullableValue $concentrator.summary.currentOwnerRepository))
+ Write-Host (" next : {0}" -f (Format-NullableValue $concentrator.summary.nextAction))
+ Write-Host (" hot/warm : {0}/{1}" -f (Format-NullableValue $concentrator.summary.hotWorkingSetCount), (Format-NullableValue $concentrator.summary.warmMemoryCount))
+ Write-Host (" archive : {0}" -f (Format-NullableValue $concentrator.summary.archiveCount))
+ Write-Host (" blockers : {0}" -f (Format-NullableValue $concentrator.summary.blockerCount))
+ Write-Host (' spend : ${0}' -f (Format-NullableValue $concentrator.summary.blendedLowerBoundUsd))
+ foreach ($entry in @($concentrator.memory.hotWorkingSet | Select-Object -First 3)) {
+ Write-Host (" - {0} [{1}]" -f (Format-NullableValue $entry.label), (Format-NullableValue $entry.status))
+ }
+ if ($env:GITHUB_STEP_SUMMARY) {
+ $activeIssueLabel = if ($concentrator.summary.activeIssueNumber) {
+ "#$($concentrator.summary.activeIssueNumber)"
+ } else {
+ 'n/a'
+ }
+ $contextLines = @(
+ '### Context Concentrator',
+ '',
+ ('- Status: {0}' -f (Format-NullableValue $concentrator.summary.concentrationStatus)),
+ ('- Active issue: {0}' -f $activeIssueLabel),
+ ('- Current owner: {0}' -f (Format-NullableValue $concentrator.summary.currentOwnerRepository)),
+ ('- Next action: {0}' -f (Format-NullableValue $concentrator.summary.nextAction)),
+ ('- Hot/warm/archive: {0}/{1}/{2}' -f (Format-NullableValue $concentrator.summary.hotWorkingSetCount), (Format-NullableValue $concentrator.summary.warmMemoryCount), (Format-NullableValue $concentrator.summary.archiveCount)),
+ ('- Blockers: {0}' -f (Format-NullableValue $concentrator.summary.blockerCount)),
+ ('- Blended lower-bound spend: ${0}' -f (Format-NullableValue $concentrator.summary.blendedLowerBoundUsd))
+ )
+ ($contextLines -join "`n") | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
+ }
+ }
+} catch {
+ Write-Warning ("Failed to display context concentrator summary: {0}" -f $_.Exception.Message)
+}
+
try {
$steeringPath = Join-Path $ResultsRoot '_agent/handoff/operator-steering-event.json'
if (Test-Path -LiteralPath $steeringPath -PathType Leaf) {
diff --git a/tools/Publish-CompareVIToolsArtifact.ps1 b/tools/Publish-CompareVIToolsArtifact.ps1
index 0e10c05f7..8cfba1556 100644
--- a/tools/Publish-CompareVIToolsArtifact.ps1
+++ b/tools/Publish-CompareVIToolsArtifact.ps1
@@ -336,6 +336,8 @@ try {
)
}
+ $hostedNiLinuxDefaultImage = 'nationalinstruments/labview:2026q1-linux'
+
$consumerContractMetadata = [ordered]@{
capabilities = [ordered]@{
viHistory = [ordered]@{
@@ -362,6 +364,24 @@ try {
'The capability contract declares compare-vi-cli-action as the upstream producer; downstream repositories should distribute or consume the capability, not vendor the full backend control plane.'
)
}
+ dockerProfile = [ordered]@{
+ schema = 'comparevi-tools/docker-profile-capability@v1'
+ capabilityId = 'docker-profile'
+ displayName = 'Docker Profile'
+ distributionRole = 'upstream-producer'
+ distributionModel = 'release-bundle'
+ bundleMetadataPath = 'comparevi-tools-release.json'
+ bundleImportPath = 'tools/CompareVI.Tools/CompareVI.Tools.psd1'
+ releaseAssetPattern = 'CompareVI.Tools-v.zip'
+ authoritativeConsumerPinFieldPath = 'versionContract.authoritativeConsumerPin'
+ authoritativeConsumerPinKindFieldPath = 'versionContract.authoritativeConsumerPinKind'
+ authoritativeImageContractSource = 'consumerContract.dockerImageContract'
+ notes = @(
+ 'Use this capability record when a downstream distributor needs a Producer-published Docker image contract without inventing template-local image conventions.',
+ 'Resolve the immutable downstream pin from versionContract.authoritativeConsumerPin and then read the docker image contract from the authoritativeImageContractSource path in the same comparevi-tools-release.json payload.',
+ 'The docker-profile capability publishes contract metadata only; downstream repositories should consume Producer-owned image contract surfaces instead of vendoring compare runtime orchestration.'
+ )
+ }
}
historyFacade = [ordered]@{
schema = 'comparevi-tools/history-facade@v1'
@@ -481,7 +501,7 @@ try {
'tools/Compare-ExitCodeClassifier.ps1'
)
captureFileName = 'ni-linux-container-capture.json'
- defaultImage = 'nationalinstruments/labview:2026q1-linux'
+ defaultImage = $hostedNiLinuxDefaultImage
notes = @(
'Hosted Linux consumers can resolve the runner from COMPAREVI_SCRIPTS_ROOT without a full backend checkout.',
'Keep the entry script and support scripts adjacent inside the extracted bundle so runtime guard and exit-code classification remain available.',
@@ -489,6 +509,23 @@ try {
'The first Windows mirror proof slice also ships `Test-WindowsNI2026q1HostPreflight.ps1` and `Run-NIWindowsContainerCompare.ps1` so Windows-host consumers can validate the pinned headless NI image without a full backend checkout.'
)
}
+ dockerImageContract = [ordered]@{
+ schema = 'comparevi-tools/docker-image-contract@v1'
+ schemaUrl = 'https://labview-community-ci-cd.github.io/compare-vi-cli-action/schemas/comparevi-tools-docker-image-contract-v1.schema.json'
+ images = [ordered]@{
+ hostedNiLinuxRunner = [ordered]@{
+ imageRef = $hostedNiLinuxDefaultImage
+ consumerRole = 'hosted-ni-linux-runner'
+ notes = @(
+ 'Use this image reference when a downstream Docker-profile consumer needs the authoritative Producer-published Linux container image for hosted NI compare execution.'
+ )
+ }
+ }
+ notes = @(
+ 'Treat this object as the authoritative Producer-published image contract for downstream Docker-profile consumers.',
+ 'Resolve it from consumerContract.capabilities.dockerProfile.authoritativeImageContractSource under the same immutable comparevi-tools-release.json payload.'
+ )
+ }
}
$bundleMetadata = [ordered]@{
diff --git a/tools/Run-DX.ps1 b/tools/Run-DX.ps1
index 82d1eaae6..c9c2fc780 100644
--- a/tools/Run-DX.ps1
+++ b/tools/Run-DX.ps1
@@ -15,6 +15,8 @@ param(
[string]$BaseVi,
[string]$HeadVi,
[string]$LabVIEWExePath,
+ [string]$LabVIEW64ExePath,
+ [string]$LabVIEW32ExePath,
[string]$LVComparePath,
[string]$OutputRoot = 'tests/results/teststand-session',
[string[]]$Flags,
@@ -23,6 +25,14 @@ param(
[string]$NoiseProfile = 'full',
[ValidateSet('detect','spawn','skip')]
[string]$Warmup = 'detect',
+ [ValidateSet('single-compare','dual-plane-parity')]
+ [string]$TestStandSuiteClass = 'single-compare',
+ [string]$AgentId,
+ [string]$AgentClass,
+ [string]$ExecutionCellLeasePath,
+ [string]$ExecutionCellId,
+ [string]$ExecutionCellLeaseId,
+ [string]$HarnessInstanceId,
[switch]$RenderReport,
[switch]$CloseLabVIEW,
[switch]$CloseLVCompare,
@@ -52,6 +62,24 @@ function Write-DxLine([string]$msg,[string]$kind='info'){
Write-Host ("[dx] {0} {1}" -f $kind,$msg)
}
+function Get-SessionBoolValue($Source, [string]$PropertyName, [bool]$Default = $false) {
+ try {
+ if ($Source -and $Source.PSObject.Properties.Name -contains $PropertyName) {
+ return [bool]$Source.$PropertyName
+ }
+ } catch {}
+ return $Default
+}
+
+function Get-SessionValue($Source, [string]$PropertyName, $Default = $null) {
+ try {
+ if ($Source -and $Source.PSObject.Properties.Name -contains $PropertyName) {
+ return $Source.$PropertyName
+ }
+ } catch {}
+ return $Default
+}
+
# Apply DX toggles
if (-not $env:DX_CONSOLE_LEVEL) { $env:DX_CONSOLE_LEVEL = 'concise' }
if (-not $env:DX_CONSOLE_PREFERRED) { $env:DX_CONSOLE_PREFERRED = '1' }
@@ -144,7 +172,16 @@ $harness = Join-Path $repoRoot 'tools/TestStand-CompareHarness.ps1'
if ($sameNameCollision) { $hParams.SameNameHint = $true }
if ($LabVIEWExePath) { $hParams.LabVIEWExePath = $LabVIEWExePath }
+ if ($LabVIEW64ExePath) { $hParams.LabVIEW64ExePath = $LabVIEW64ExePath }
+ if ($LabVIEW32ExePath) { $hParams.LabVIEW32ExePath = $LabVIEW32ExePath }
if ($LVComparePath) { $hParams.LVComparePath = $LVComparePath }
+ $hParams.SuiteClass = $TestStandSuiteClass
+ if ($AgentId) { $hParams.AgentId = $AgentId }
+ if ($AgentClass) { $hParams.AgentClass = $AgentClass }
+ if ($ExecutionCellLeasePath) { $hParams.ExecutionCellLeasePath = $ExecutionCellLeasePath }
+ if ($ExecutionCellId) { $hParams.ExecutionCellId = $ExecutionCellId }
+ if ($ExecutionCellLeaseId) { $hParams.ExecutionCellLeaseId = $ExecutionCellLeaseId }
+ if ($HarnessInstanceId) { $hParams.HarnessInstanceId = $HarnessInstanceId }
if ($PSBoundParameters.ContainsKey('Flags')) { $hParams.Flags = $Flags }
if ($ReplaceFlags) { $hParams.ReplaceFlags = $true }
if ($RenderReport) { $hParams.RenderReport = $true }
@@ -201,11 +238,37 @@ $harness = Join-Path $repoRoot 'tools/TestStand-CompareHarness.ps1'
}
if ($session) {
try {
+ $requestedSimultaneous = $false
+ if ($session.PSObject.Properties.Name -contains 'requestedSimultaneous') {
+ $requestedSimultaneous = [bool]$session.requestedSimultaneous
+ } elseif ($session.processModel -and $session.processModel.PSObject.Properties.Name -contains 'processModelClass') {
+ $requestedSimultaneous = ($session.processModel.processModelClass -eq 'parallel-process-model')
+ }
$statusEnvelope.session = @{
- outcome = $session.outcome
- error = $session.error
- compare = $session.compare
- content = $session.content
+ suiteClass = Get-SessionValue $session 'suiteClass'
+ primaryPlane = Get-SessionValue $session 'primaryPlane'
+ requestedSimultaneous = $requestedSimultaneous
+ outcome = Get-SessionValue $session 'outcome'
+ error = Get-SessionValue $session 'error'
+ executionCell = Get-SessionValue $session 'executionCell'
+ harnessInstance = Get-SessionValue $session 'harnessInstance'
+ processModel = Get-SessionValue $session 'processModel'
+ compare = Get-SessionValue $session 'compare'
+ content = Get-SessionValue $session 'content'
+ parity = Get-SessionValue $session 'parity'
+ planes = Get-SessionValue $session 'planes'
+ }
+ $statusEnvelope.executionTopology = @{
+ suiteClass = if ($session.PSObject.Properties.Name -contains 'suiteClass') { $session.suiteClass } elseif (Get-SessionValue $session 'executionCell') { (Get-SessionValue (Get-SessionValue $session 'executionCell') 'suiteClass') } else { $null }
+ runtimeSurface = Get-SessionValue (Get-SessionValue $session 'processModel') 'runtimeSurface'
+ processModelClass = Get-SessionValue (Get-SessionValue $session 'processModel') 'processModelClass'
+ requestedSimultaneous = $requestedSimultaneous
+ cellClass = Get-SessionValue (Get-SessionValue $session 'executionCell') 'cellClass'
+ operatorAuthorizationRef = Get-SessionValue (Get-SessionValue $session 'executionCell') 'operatorAuthorizationRef'
+ premiumSaganMode = if (Get-SessionValue $session 'executionCell') { Get-SessionBoolValue (Get-SessionValue $session 'executionCell') 'premiumSaganMode' } else { $false }
+ harnessKind = Get-SessionValue (Get-SessionValue $session 'harnessInstance') 'harnessKind'
+ executionCellId = Get-SessionValue (Get-SessionValue $session 'executionCell') 'cellId'
+ executionCellLeaseId = Get-SessionValue (Get-SessionValue $session 'executionCell') 'leaseId'
}
} catch {}
}
diff --git a/tools/Test-AgentHandoffEntryPoint.ps1 b/tools/Test-AgentHandoffEntryPoint.ps1
index 92cca6b9a..78e772c6f 100644
--- a/tools/Test-AgentHandoffEntryPoint.ps1
+++ b/tools/Test-AgentHandoffEntryPoint.ps1
@@ -37,6 +37,7 @@ $requiredArtifacts = @(
'tests/results/_agent/handoff/continuity-summary.json',
'tests/results/_agent/handoff/entrypoint-status.json',
'tests/results/_agent/handoff/monitoring-mode.json',
+ 'tests/results/_agent/handoff/sagan-context-concentrator.json',
'tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json',
'tests/results/_agent/handoff/*.json',
'tests/results/_agent/sessions/*.json'
@@ -51,6 +52,7 @@ $commandCatalog = [ordered]@{
monitoringMode = 'node tools/npm/run-script.mjs priority:monitoring:mode'
governorSummary = 'node tools/npm/run-script.mjs priority:governor:summary'
governorPortfolio = 'node tools/npm/run-script.mjs priority:governor:portfolio'
+ contextConcentrator = 'node tools/npm/run-script.mjs priority:context:concentrate'
}
$artifactCatalog = [ordered]@{
@@ -62,6 +64,7 @@ $artifactCatalog = [ordered]@{
entrypointStatus = 'tests/results/_agent/handoff/entrypoint-status.json'
monitoringMode = 'tests/results/_agent/handoff/monitoring-mode.json'
autonomousGovernorSummary = 'tests/results/_agent/handoff/autonomous-governor-summary.json'
+ saganContextConcentrator = 'tests/results/_agent/handoff/sagan-context-concentrator.json'
autonomousGovernorPortfolioSummary = 'tests/results/_agent/handoff/autonomous-governor-portfolio-summary.json'
handoffGlob = 'tests/results/_agent/handoff/*.json'
sessionGlob = 'tests/results/_agent/sessions/*.json'
diff --git a/tools/TestStand-CompareHarness.ps1 b/tools/TestStand-CompareHarness.ps1
index a7d6e6102..f889668ca 100644
--- a/tools/TestStand-CompareHarness.ps1
+++ b/tools/TestStand-CompareHarness.ps1
@@ -7,44 +7,8 @@
Invoke-LVCompare.ps1 to perform a deterministic compare, and finally optional close helpers.
Writes a session-index.json with pointers to emitted crumbs and artifacts.
-.PARAMETER BaseVi
- Base VI path.
-
-.PARAMETER HeadVi
- Head VI path.
-
-.PARAMETER LabVIEWExePath
- Path to LabVIEW.exe (pinned version/bitness recommended).
-
-.PARAMETER LVCompareExePath
- Path to LVCompare.exe (defaults to canonical install when omitted).
-
-.PARAMETER OutputRoot
- Root folder for all outputs (default tests/results/teststand-session).
-
-.PARAMETER Warmup
- Controls LabVIEW warmup behaviour. `detect` (default) warms up when the helper
- script is available, `spawn` forces a fresh warmup cycle (StopAfterWarmup),
- and `skip` bypasses warmup entirely.
-
-.PARAMETER RenderReport
- Generate compare-report.html during compare.
-
-.PARAMETER Flags
- Additional LVCompare flags forwarded to Invoke-LVCompare.ps1.
-
-.PARAMETER ReplaceFlags
- Replace the default LVCompare flags with the provided -Flags values.
-
-.PARAMETER NoiseProfile
- Selects which LVCompare ignore bundle to apply when -ReplaceFlags is omitted.
- Defaults to 'full' for complete compare detail; pass 'legacy' to restore the historical suppression bundle.
-
-.PARAMETER CloseLabVIEW
- Attempt graceful LabVIEW close via tools/Close-LabVIEW.ps1 at the end.
-
-.PARAMETER CloseLVCompare
- Attempt LVCompare cleanup via tools/Close-LVCompare.ps1 at the end.
+ Revision 2 adds an opt-in dual-plane native parity suite for LabVIEW 2026 x64/x32.
+ The legacy single-plane session contract remains the default.
#>
[CmdletBinding()]
param(
@@ -52,6 +16,8 @@ param(
[Parameter(Mandatory)][string]$HeadVi,
[Alias('LabVIEWPath')]
[string]$LabVIEWExePath,
+[ValidateSet('32','64')]
+[string]$LabVIEWBitness = '64',
[Alias('LVCompareExePath')]
[string]$LVComparePath,
[string]$OutputRoot = 'tests/results/teststand-session',
@@ -68,7 +34,22 @@ param(
[switch]$DisableTimeout,
[string]$StagingRoot,
[switch]$SameNameHint,
-[switch]$AllowSameLeaf
+[switch]$AllowSameLeaf,
+[ValidateSet('single-compare','dual-plane-parity')]
+[string]$SuiteClass = 'single-compare',
+[string]$LabVIEW64ExePath,
+[string]$LabVIEW32ExePath,
+[switch]$InternalSinglePlane,
+[ValidateSet('x64','x32')]
+[string]$InternalPlaneKey,
+[string]$AgentId = $env:CODEX_AGENT_ID,
+[string]$AgentClass = $env:CODEX_AGENT_CLASS,
+[string]$ExecutionCellLeasePath = $env:TESTSTAND_EXECUTION_CELL_LEASE_PATH,
+[string]$ExecutionCellId = $env:TESTSTAND_EXECUTION_CELL_ID,
+[string]$ExecutionCellLeaseId = $env:TESTSTAND_EXECUTION_CELL_LEASE_ID,
+[string]$ExecutionCellSuiteClass = $env:TESTSTAND_EXECUTION_CELL_SUITE_CLASS,
+[string]$HarnessInstanceId = $env:TESTSTAND_HARNESS_INSTANCE_ID,
+[string]$ParentHarnessInstanceId = $env:TESTSTAND_PARENT_HARNESS_INSTANCE_ID
)
Set-StrictMode -Version Latest
@@ -78,6 +59,35 @@ try { Import-Module ThreadJob -ErrorAction SilentlyContinue } catch {}
function New-Dir([string]$p){ if (-not (Test-Path $p)) { New-Item -ItemType Directory -Path $p -Force | Out-Null } }
+function Resolve-AbsolutePath {
+ param(
+ [Parameter(Mandatory)][string]$RepoRoot,
+ [Parameter(Mandatory)][string]$Candidate
+ )
+
+ if ([System.IO.Path]::IsPathRooted($Candidate)) {
+ return $Candidate
+ }
+
+ return (Join-Path $RepoRoot $Candidate)
+}
+
+function Resolve-LabVIEW2026Path {
+ param([ValidateSet('32','64')][string]$Bitness)
+
+ $root = if ($Bitness -eq '32') { ${env:ProgramFiles(x86)} } else { ${env:ProgramFiles} }
+ if ([string]::IsNullOrWhiteSpace($root)) {
+ return $null
+ }
+ return (Join-Path $root 'National Instruments\LabVIEW 2026\LabVIEW.exe')
+}
+
+function Convert-ToArchitectureLabel {
+ param([ValidateSet('32','64')][string]$Bitness)
+ if ($Bitness -eq '32') { return '32-bit' }
+ return '64-bit'
+}
+
function Invoke-WithTimeout {
param(
[scriptblock]$Block,
@@ -110,172 +120,776 @@ function Invoke-WithTimeout {
}
}
-$repo = (Resolve-Path '.').Path
+function New-SessionOutcome {
+ param([AllowNull()]$Capture)
-# Resolve OutputRoot to absolute path for deterministic writes
-if (-not ([System.IO.Path]::IsPathRooted($OutputRoot))) {
- $OutputRoot = Join-Path $repo $OutputRoot
-}
+ if ($null -eq $Capture) {
+ return $null
+ }
-$paths = [ordered]@{
- warmupDir = Join-Path $OutputRoot '_warmup'
- compareDir = Join-Path $OutputRoot 'compare'
+ return [ordered]@{
+ exitCode = [int]$Capture.exitCode
+ seconds = [double]$Capture.seconds
+ command = $Capture.command
+ diff = [bool]($Capture.exitCode -eq 1)
+ }
}
-New-Dir $paths.warmupDir
-New-Dir $paths.compareDir
-
-$baseLeaf = Split-Path -Path $BaseVi -Leaf
-$headLeaf = Split-Path -Path $HeadVi -Leaf
-$sameName = [string]::Equals($baseLeaf, $headLeaf, [System.StringComparison]::OrdinalIgnoreCase)
-$baseResolved = (Resolve-Path -LiteralPath $BaseVi -ErrorAction Stop).Path
-$headResolved = (Resolve-Path -LiteralPath $HeadVi -ErrorAction Stop).Path
-if ($baseResolved -ne $headResolved) {
- $baseResolvedLeaf = Split-Path -Path $baseResolved -Leaf
- $headResolvedLeaf = Split-Path -Path $headResolved -Leaf
- if ([string]::Equals($baseResolvedLeaf, $headResolvedLeaf, [System.StringComparison]::OrdinalIgnoreCase) -and -not $AllowSameLeaf.IsPresent) {
- throw ("LVCompare limitation: staged inputs must have distinct filenames. Received '{0}' and '{1}'." -f $BaseVi, $HeadVi)
+
+function Read-JsonFileIfPresent {
+ param([AllowNull()][string]$Path)
+
+ if ([string]::IsNullOrWhiteSpace($Path)) {
+ return $null
+ }
+ if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
+ return $null
+ }
+
+ try {
+ return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json -Depth 20
+ } catch {
+ return $null
}
}
-if ($SameNameHint.IsPresent) {
- $sameName = $true
+
+function Get-FirstNonEmptyText {
+ param([AllowNull()][object[]]$Values)
+
+ foreach ($value in @($Values)) {
+ if ($null -eq $value) {
+ continue
+ }
+ $text = [string]$value
+ if (-not [string]::IsNullOrWhiteSpace($text)) {
+ return $text
+ }
+ }
+
+ return $null
}
-$rawPolicy = $env:LVCI_COMPARE_POLICY
-$policy = if ([string]::IsNullOrWhiteSpace($rawPolicy)) { 'cli-only' } else { $rawPolicy }
-$rawMode = $env:LVCI_COMPARE_MODE
-$mode = if ([string]::IsNullOrWhiteSpace($rawMode)) { 'labview-cli' } else { $rawMode }
-$autoCli = $false
-if ($sameName -and $policy -ne 'lv-only') {
- $autoCli = $true
- if ($Warmup -ne 'skip') {
- Write-Host "Harness: skipping warmup for same-name VIs (CLI path auto-selected)." -ForegroundColor Gray
- $Warmup = 'skip'
+
+function Resolve-TestStandExecutionCellContext {
+ param(
+ [AllowNull()][string]$ExecutionCellLeasePath,
+ [AllowNull()][string]$ExecutionCellId,
+ [AllowNull()][string]$ExecutionCellLeaseId,
+ [AllowNull()][string]$ExecutionCellSuiteClass,
+ [AllowNull()][string]$HarnessInstanceId,
+ [AllowNull()][string]$ParentHarnessInstanceId,
+ [AllowNull()][string]$AgentId,
+ [AllowNull()][string]$AgentClass,
+ [AllowNull()][string]$SuiteClass,
+ [AllowNull()][string]$PlaneName,
+ [AllowNull()][string]$Role,
+ [Parameter(Mandatory)][string]$OutputRoot
+ )
+
+ $resolvedLeasePath = if ([string]::IsNullOrWhiteSpace($ExecutionCellLeasePath)) {
+ $null
+ } else {
+ $resolvedLease = Resolve-Path -LiteralPath $ExecutionCellLeasePath -ErrorAction SilentlyContinue
+ if ($resolvedLease) { $resolvedLease.Path } else { $ExecutionCellLeasePath }
+ }
+ $lease = Read-JsonFileIfPresent -Path $resolvedLeasePath
+ $leaseRequest = if ($lease -and $lease.PSObject.Properties['request']) { $lease.request } else { $null }
+ $leaseGrant = if ($lease -and $lease.PSObject.Properties['grant']) { $lease.grant } else { $null }
+ $leaseCommit = if ($lease -and $lease.PSObject.Properties['commit']) { $lease.commit } else { $null }
+ $leaseHost = if ($lease -and $lease.PSObject.Properties['host']) { $lease.host } else { $null }
+ $leaseCellId = if ($lease -and $lease.PSObject.Properties['cellId']) { $lease.cellId } else { $null }
+ $leaseGrantLeaseId = if ($leaseGrant -and $leaseGrant.PSObject.Properties['leaseId']) { $leaseGrant.leaseId } else { $null }
+ $leaseRequestAgentId = if ($leaseRequest -and $leaseRequest.PSObject.Properties['agentId']) { $leaseRequest.agentId } else { $null }
+ $leaseRequestAgentClass = if ($leaseRequest -and $leaseRequest.PSObject.Properties['agentClass']) { $leaseRequest.agentClass } else { $null }
+ $leaseRequestCellClass = if ($leaseRequest -and $leaseRequest.PSObject.Properties['cellClass']) { $leaseRequest.cellClass } else { $null }
+ $leaseRequestSuiteClass = if ($leaseRequest -and $leaseRequest.PSObject.Properties['suiteClass']) { $leaseRequest.suiteClass } else { $null }
+ $leaseRequestPlaneBinding = if ($leaseRequest -and $leaseRequest.PSObject.Properties['planeBinding']) { $leaseRequest.planeBinding } else { $null }
+ $leaseRequestWorkingRoot = if ($leaseRequest -and $leaseRequest.PSObject.Properties['workingRoot']) { $leaseRequest.workingRoot } else { $null }
+ $leaseRequestArtifactRoot = if ($leaseRequest -and $leaseRequest.PSObject.Properties['artifactRoot']) { $leaseRequest.artifactRoot } else { $null }
+ $leaseRequestHarnessKind = if ($leaseRequest -and $leaseRequest.PSObject.Properties['harnessKind']) { $leaseRequest.harnessKind } else { $null }
+ $leaseRequestOperatorAuthorizationRef = if ($leaseRequest -and $leaseRequest.PSObject.Properties['operatorAuthorizationRef']) { $leaseRequest.operatorAuthorizationRef } else { $null }
+ $leaseCommitWorkingRoot = if ($leaseCommit -and $leaseCommit.PSObject.Properties['workingRoot']) { $leaseCommit.workingRoot } else { $null }
+ $leaseCommitArtifactRoot = if ($leaseCommit -and $leaseCommit.PSObject.Properties['artifactRoot']) { $leaseCommit.artifactRoot } else { $null }
+ $leaseHostIsolatedLaneGroupId = if ($leaseHost -and $leaseHost.PSObject.Properties['isolatedLaneGroupId']) { $leaseHost.isolatedLaneGroupId } else { $null }
+ $leaseHostFingerprintSha256 = if ($leaseHost -and $leaseHost.PSObject.Properties['fingerprintSha256']) { $leaseHost.fingerprintSha256 } else { $null }
+ $leaseGrantPremiumSaganMode = if ($leaseGrant -and $leaseGrant.PSObject.Properties['premiumSaganMode']) { $leaseGrant.premiumSaganMode } else { $null }
+
+ $resolvedCellId = Get-FirstNonEmptyText @($ExecutionCellId, $leaseCellId)
+ $resolvedLeaseId = Get-FirstNonEmptyText @($ExecutionCellLeaseId, $leaseGrantLeaseId)
+ $resolvedAgentId = Get-FirstNonEmptyText @($AgentId, $leaseRequestAgentId)
+ $resolvedAgentClass = (Get-FirstNonEmptyText @($AgentClass, $leaseRequestAgentClass))
+ if ([string]::IsNullOrWhiteSpace($resolvedAgentClass)) {
+ $resolvedAgentClass = 'subagent'
+ }
+ $resolvedSuiteClass = Get-FirstNonEmptyText @($ExecutionCellSuiteClass, $leaseRequestSuiteClass, $SuiteClass)
+ $resolvedPlaneBinding = if ([string]::IsNullOrWhiteSpace($PlaneName)) {
+ Get-FirstNonEmptyText @($leaseRequestPlaneBinding, $(if ($resolvedSuiteClass -eq 'dual-plane-parity') { 'dual-plane-parity' } else { $null }))
+ } else {
+ $PlaneName
+ }
+ $resolvedWorkingRoot = Get-FirstNonEmptyText @($leaseCommitWorkingRoot, $leaseRequestWorkingRoot, $OutputRoot)
+ $resolvedArtifactRoot = Get-FirstNonEmptyText @($leaseCommitArtifactRoot, $leaseRequestArtifactRoot, $OutputRoot)
+ $resolvedHarnessKind = Get-FirstNonEmptyText @($leaseRequestHarnessKind, 'teststand-compare-harness')
+ $resolvedRole = Get-FirstNonEmptyText @($Role, $(if (-not [string]::IsNullOrWhiteSpace($ParentHarnessInstanceId)) { 'plane-child' } elseif ($resolvedSuiteClass -eq 'dual-plane-parity' -and [string]::IsNullOrWhiteSpace($PlaneName)) { 'coordinator' } else { 'single-plane' }))
+ $resolvedProcessModelClass = if ($resolvedSuiteClass -eq 'dual-plane-parity') {
+ 'parallel-process-model'
+ } else {
+ 'sequential-process-model'
+ }
+
+ $planeSuffix = if ($PlaneName -match '2026-64$') {
+ 'x64'
+ } elseif ($PlaneName -match '2026-32$') {
+ 'x32'
+ } else {
+ 'plane'
+ }
+ $resolvedHarnessInstanceId = Get-FirstNonEmptyText @(
+ $HarnessInstanceId,
+ $(if (-not [string]::IsNullOrWhiteSpace($ParentHarnessInstanceId)) { '{0}-{1}' -f $ParentHarnessInstanceId, $planeSuffix } else { $null }),
+ $(if (-not [string]::IsNullOrWhiteSpace($resolvedCellId)) { '{0}-{1}' -f $resolvedHarnessKind, $resolvedCellId } else { $null }),
+ $(if (-not [string]::IsNullOrWhiteSpace($PlaneName)) { '{0}-{1}' -f $resolvedHarnessKind, $planeSuffix } else { $resolvedHarnessKind })
+ )
+
+ $executionCell = $null
+ if (-not [string]::IsNullOrWhiteSpace($resolvedCellId) -or -not [string]::IsNullOrWhiteSpace($resolvedLeaseId) -or -not [string]::IsNullOrWhiteSpace($resolvedAgentId) -or -not [string]::IsNullOrWhiteSpace($resolvedLeasePath)) {
+ $executionCell = [ordered]@{
+ cellId = $resolvedCellId
+ leaseId = $resolvedLeaseId
+ leasePath = $resolvedLeasePath
+ agentId = $resolvedAgentId
+ agentClass = $resolvedAgentClass
+ cellClass = Get-FirstNonEmptyText @($leaseRequestCellClass)
+ suiteClass = $resolvedSuiteClass
+ planeBinding = $resolvedPlaneBinding
+ runtimeSurface = 'windows-native-teststand'
+ premiumSaganMode = if ($null -eq $leaseGrantPremiumSaganMode) { $false } else { [bool]$leaseGrantPremiumSaganMode }
+ operatorAuthorizationRef = Get-FirstNonEmptyText @($leaseRequestOperatorAuthorizationRef)
+ workingRoot = $resolvedWorkingRoot
+ artifactRoot = $resolvedArtifactRoot
+ isolatedLaneGroupId = Get-FirstNonEmptyText @($leaseHostIsolatedLaneGroupId)
+ hostOsFingerprintSha256 = Get-FirstNonEmptyText @($leaseHostFingerprintSha256)
+ }
+ }
+
+ $harnessInstance = [ordered]@{
+ harnessKind = $resolvedHarnessKind
+ instanceId = $resolvedHarnessInstanceId
+ role = $resolvedRole
+ processModelClass = $resolvedProcessModelClass
+ planeBinding = $resolvedPlaneBinding
+ parentInstanceId = Get-FirstNonEmptyText @($ParentHarnessInstanceId)
+ }
+
+ $processModel = [ordered]@{
+ runtimeSurface = 'windows-native-teststand'
+ processModelClass = $resolvedProcessModelClass
+ windowsOnly = $true
+ rootHarnessInstanceId = Get-FirstNonEmptyText @($ParentHarnessInstanceId, $resolvedHarnessInstanceId)
+ planeCount = if ($resolvedSuiteClass -eq 'dual-plane-parity') { 2 } else { 1 }
+ }
+
+ return [pscustomobject]@{
+ executionCell = $executionCell
+ harnessInstance = $harnessInstance
+ processModel = $processModel
}
}
-if ($policy -eq 'cli-only') {
- if ($Warmup -ne 'skip') {
- Write-Host "Harness: skipping warmup (headless CLI default policy)." -ForegroundColor Gray
- $Warmup = 'skip'
+
+function Invoke-TestStandSinglePlaneSession {
+ param(
+ [Parameter(Mandatory)][string]$RepoRoot,
+ [Parameter(Mandatory)][string]$BaseVi,
+ [Parameter(Mandatory)][string]$HeadVi,
+ [AllowNull()][string]$LabVIEWExePath,
+ [ValidateSet('32','64')][string]$LabVIEWBitness = '64',
+ [AllowNull()][string]$LVComparePath,
+ [Parameter(Mandatory)][string]$OutputRoot,
+ [ValidateSet('detect','spawn','skip')][string]$Warmup,
+ [AllowNull()][string]$SuiteClass,
+ [AllowNull()][string[]]$Flags,
+ [bool]$ReplaceFlags,
+ [ValidateSet('full','legacy')][string]$NoiseProfile,
+ [bool]$RenderReport,
+ [bool]$CloseLabVIEW,
+ [bool]$CloseLVCompare,
+ [int]$TimeoutSeconds,
+ [bool]$DisableTimeout,
+ [AllowNull()][string]$StagingRoot,
+ [bool]$SameNameHint,
+ [bool]$AllowSameLeaf,
+ [AllowNull()][string]$PlaneName,
+ [AllowNull()][string]$AgentId,
+ [AllowNull()][string]$AgentClass,
+ [AllowNull()][string]$ExecutionCellLeasePath,
+ [AllowNull()][string]$ExecutionCellId,
+ [AllowNull()][string]$ExecutionCellLeaseId,
+ [AllowNull()][string]$ExecutionCellSuiteClass,
+ [AllowNull()][string]$HarnessInstanceId,
+ [AllowNull()][string]$ParentHarnessInstanceId,
+ [AllowNull()][string]$HarnessRole
+ )
+
+ $resolvedOutputRoot = Resolve-AbsolutePath -RepoRoot $RepoRoot -Candidate $OutputRoot
+ $cellLeaseContext = Resolve-TestStandExecutionCellContext -ExecutionCellLeasePath $ExecutionCellLeasePath -ExecutionCellId $ExecutionCellId -ExecutionCellLeaseId $ExecutionCellLeaseId -ExecutionCellSuiteClass $ExecutionCellSuiteClass -HarnessInstanceId $HarnessInstanceId -ParentHarnessInstanceId $ParentHarnessInstanceId -AgentId $AgentId -AgentClass $AgentClass -SuiteClass $SuiteClass -PlaneName $PlaneName -Role $HarnessRole -OutputRoot $resolvedOutputRoot
+ $paths = [ordered]@{
+ warmupDir = Join-Path $resolvedOutputRoot '_warmup'
+ compareDir = Join-Path $resolvedOutputRoot 'compare'
+ }
+ New-Dir $paths.warmupDir
+ New-Dir $paths.compareDir
+
+ $baseLeaf = Split-Path -Path $BaseVi -Leaf
+ $headLeaf = Split-Path -Path $HeadVi -Leaf
+ $sameName = [string]::Equals($baseLeaf, $headLeaf, [System.StringComparison]::OrdinalIgnoreCase)
+ $baseResolved = (Resolve-Path -LiteralPath $BaseVi -ErrorAction Stop).Path
+ $headResolved = (Resolve-Path -LiteralPath $HeadVi -ErrorAction Stop).Path
+ if ($baseResolved -ne $headResolved) {
+ $baseResolvedLeaf = Split-Path -Path $baseResolved -Leaf
+ $headResolvedLeaf = Split-Path -Path $headResolved -Leaf
+ if ([string]::Equals($baseResolvedLeaf, $headResolvedLeaf, [System.StringComparison]::OrdinalIgnoreCase) -and -not $AllowSameLeaf) {
+ throw ("LVCompare limitation: staged inputs must have distinct filenames. Received '{0}' and '{1}'." -f $BaseVi, $HeadVi)
+ }
+ }
+ if ($SameNameHint) {
+ $sameName = $true
+ }
+
+ $rawPolicy = $env:LVCI_COMPARE_POLICY
+ $policy = if ([string]::IsNullOrWhiteSpace($rawPolicy)) { 'cli-only' } else { $rawPolicy }
+ $rawMode = $env:LVCI_COMPARE_MODE
+ $mode = if ([string]::IsNullOrWhiteSpace($rawMode)) { 'labview-cli' } else { $rawMode }
+ $autoCli = $false
+ $effectiveWarmup = $Warmup
+ if ($sameName -and $policy -ne 'lv-only') {
+ $autoCli = $true
+ if ($effectiveWarmup -ne 'skip') {
+ Write-Host "Harness: skipping warmup for same-name VIs (CLI path auto-selected)." -ForegroundColor Gray
+ $effectiveWarmup = 'skip'
+ }
+ }
+ if ($policy -eq 'cli-only') {
+ if ($effectiveWarmup -ne 'skip') {
+ Write-Host "Harness: skipping warmup (headless CLI default policy)." -ForegroundColor Gray
+ $effectiveWarmup = 'skip'
+ }
+ }
+ if ([string]::IsNullOrWhiteSpace($rawPolicy)) {
+ try { [System.Environment]::SetEnvironmentVariable('LVCI_COMPARE_POLICY', $policy, 'Process') } catch {}
+ }
+ if ([string]::IsNullOrWhiteSpace($rawMode)) {
+ try { [System.Environment]::SetEnvironmentVariable('LVCI_COMPARE_MODE', $mode, 'Process') } catch {}
+ }
+
+ $warmupLog = Join-Path $paths.warmupDir 'labview-runtime.ndjson'
+ $compareLog = Join-Path $paths.compareDir 'compare-events.ndjson'
+ $capPath = Join-Path $paths.compareDir 'lvcompare-capture.json'
+ $reportPath = Join-Path $paths.compareDir 'compare-report.html'
+ $cap = $null
+ $warmupRan = $false
+ $err = $null
+ $closeLVCompareScript = Join-Path $RepoRoot 'tools' 'Close-LVCompare.ps1'
+ $closeLabVIEWScript = Join-Path $RepoRoot 'tools' 'Close-LabVIEW.ps1'
+ $effectiveTimeout = if ($DisableTimeout) { 0 } else { [Math]::Max(0, [int]$TimeoutSeconds) }
+
+ try {
+ if ($effectiveWarmup -ne 'skip') {
+ $warmupScript = Join-Path $RepoRoot 'tools' 'Warmup-LabVIEWRuntime.ps1'
+ if (-not (Test-Path -LiteralPath $warmupScript)) { throw "Warmup-LabVIEWRuntime.ps1 not found at $warmupScript" }
+ $warmParams = @{ JsonLogPath = $warmupLog; SupportedBitness = $LabVIEWBitness }
+ if ($LabVIEWExePath) { $warmParams.LabVIEWPath = $LabVIEWExePath }
+ $warmupRunner = {
+ param($warmupScriptPath, $warmupParameters)
+ & $warmupScriptPath @warmupParameters | Out-Null
+ }
+ try {
+ Invoke-WithTimeout -Block $warmupRunner -TimeoutSeconds $effectiveTimeout -Stage 'warmup' -DisableTimeout:$DisableTimeout -ArgumentList @($warmupScript, $warmParams) | Out-Null
+ $warmupRan = $true
+ } catch {
+ $err = $_.Exception.Message
+ throw
+ }
+ }
+
+ $invoke = Join-Path $RepoRoot 'tools' 'Invoke-LVCompare.ps1'
+ if (-not (Test-Path -LiteralPath $invoke)) { throw "Invoke-LVCompare.ps1 not found at $invoke" }
+ $invokeParams = @{
+ BaseVi = $BaseVi
+ HeadVi = $HeadVi
+ OutputDir = $paths.compareDir
+ JsonLogPath = $compareLog
+ RenderReport = $RenderReport
+ NoiseProfile = $NoiseProfile
+ LabVIEWBitness = $LabVIEWBitness
+ }
+ if ($LabVIEWExePath) { $invokeParams.LabVIEWExePath = $LabVIEWExePath }
+ if ($LVComparePath) { $invokeParams.LVComparePath = $LVComparePath }
+ if ($Flags) { $invokeParams.Flags = $Flags }
+ if ($ReplaceFlags) { $invokeParams.ReplaceFlags = $true }
+ if ($AllowSameLeaf) { $invokeParams.AllowSameLeaf = $true }
+ $compareRunner = {
+ param($invokePath, $invokeParameters)
+ & $invokePath @invokeParameters | Out-Null
+ }
+ Invoke-WithTimeout -Block $compareRunner -TimeoutSeconds $effectiveTimeout -Stage 'compare' -DisableTimeout:$DisableTimeout -ArgumentList @($invoke, $invokeParams) | Out-Null
+ if (Test-Path -LiteralPath $capPath) { $cap = Get-Content -LiteralPath $capPath -Raw | ConvertFrom-Json }
+ } catch {
+ $err = $_.Exception.Message
+ } finally {
+ if ($CloseLVCompare -and (Test-Path -LiteralPath $closeLVCompareScript)) {
+ try { & $closeLVCompareScript | Out-Null } catch {}
+ }
+ if ($CloseLabVIEW -and (Test-Path -LiteralPath $closeLabVIEWScript)) {
+ try {
+ $closeParams = @{ SupportedBitness = $LabVIEWBitness }
+ if ($LabVIEWExePath) { $closeParams.LabVIEWExePath = $LabVIEWExePath }
+ & $closeLabVIEWScript @closeParams | Out-Null
+ } catch {}
+ }
+ }
+
+ $reportExists = Test-Path -LiteralPath $reportPath -PathType Leaf
+ $warmupNode = [ordered]@{
+ mode = $effectiveWarmup
+ events = if ($warmupRan) { $warmupLog } else { $null }
}
+ $compareNode = [ordered]@{
+ events = $compareLog
+ capture = $capPath
+ report = $reportExists
+ }
+ $compareNode.staging = [ordered]@{
+ enabled = [bool]([string]::IsNullOrWhiteSpace($StagingRoot) -eq $false)
+ root = if ([string]::IsNullOrWhiteSpace($StagingRoot)) { $null } else { $StagingRoot }
+ }
+ $compareNode.allowSameLeaf = $AllowSameLeaf
+ if ($cap) {
+ if ($cap.PSObject.Properties['command']) { $compareNode.command = $cap.command }
+ if ($cap.PSObject.Properties['cliPath']) { $compareNode.cliPath = $cap.cliPath }
+ if ($cap.PSObject.Properties['environment']) {
+ $envNode = $cap.environment
+ if ($envNode -and $envNode.PSObject.Properties['cli']) {
+ $compareNode.cli = $envNode.cli
+ }
+ }
+ }
+ $compareNode.autoCli = $autoCli
+ $compareNode.sameName = $sameName
+ $compareNode.timeoutSeconds = $effectiveTimeout
+ if ($env:LVCI_COMPARE_POLICY) { $compareNode.policy = $env:LVCI_COMPARE_POLICY }
+ if ($env:LVCI_COMPARE_MODE) { $compareNode.mode = $env:LVCI_COMPARE_MODE }
+
+ $planeRecord = [ordered]@{
+ plane = if ([string]::IsNullOrWhiteSpace($PlaneName)) { $null } else { $PlaneName }
+ architecture = Convert-ToArchitectureLabel -Bitness $LabVIEWBitness
+ labviewExePath = if ([string]::IsNullOrWhiteSpace($LabVIEWExePath)) { $null } else { $LabVIEWExePath }
+ outputRoot = $resolvedOutputRoot
+ warmup = $warmupNode
+ compare = $compareNode
+ outcome = New-SessionOutcome -Capture $cap
+ error = $err
+ exitCode = if ($cap) { [int]$cap.exitCode } else { 1 }
+ executionCell = $cellLeaseContext.executionCell
+ harnessInstance = $cellLeaseContext.harnessInstance
+ processModel = $cellLeaseContext.processModel
+ }
+
+ return [pscustomobject]$planeRecord
}
-if ([string]::IsNullOrWhiteSpace($rawPolicy)) {
- try { [System.Environment]::SetEnvironmentVariable('LVCI_COMPARE_POLICY', $policy, 'Process') } catch {}
+
+function Write-TestStandV1SessionIndex {
+ param(
+ [Parameter(Mandatory)][string]$OutputRoot,
+ [Parameter(Mandatory)][object]$PlaneSession
+ )
+
+ $index = [ordered]@{
+ schema = 'teststand-compare-session/v1'
+ at = (Get-Date).ToString('o')
+ warmup = $PlaneSession.warmup
+ compare = $PlaneSession.compare
+ outcome = $PlaneSession.outcome
+ error = $PlaneSession.error
+ executionCell = $PlaneSession.executionCell
+ harnessInstance = $PlaneSession.harnessInstance
+ processModel = $PlaneSession.processModel
+ }
+
+ $indexPath = Join-Path $OutputRoot 'session-index.json'
+ New-Dir $OutputRoot
+ $index | ConvertTo-Json -Depth 8 | Out-File -LiteralPath $indexPath -Encoding utf8
}
-if ([string]::IsNullOrWhiteSpace($rawMode)) {
- try { [System.Environment]::SetEnvironmentVariable('LVCI_COMPARE_MODE', $mode, 'Process') } catch {}
+
+function Convert-ToParityComparableValue {
+ param($Value)
+ if ($null -eq $Value) { return $null }
+ return $Value
}
-$warmupLog = Join-Path $paths.warmupDir 'labview-runtime.ndjson'
-$compareLog = Join-Path $paths.compareDir 'compare-events.ndjson'
-$capPath = Join-Path $paths.compareDir 'lvcompare-capture.json'
-$reportPath = Join-Path $paths.compareDir 'compare-report.html'
-$cap = $null
-$warmupRan = $false
-$err = $null
-$closeLVCompareScript = Join-Path $repo 'tools' 'Close-LVCompare.ps1'
-$closeLabVIEWScript = Join-Path $repo 'tools' 'Close-LabVIEW.ps1'
-$effectiveTimeout = if ($DisableTimeout) { 0 } else { [Math]::Max(0, [int]$TimeoutSeconds) }
-
-try {
- # 1) Warmup LabVIEW runtime (optional)
- if ($Warmup -ne 'skip') {
- $warmupScript = Join-Path $repo 'tools' 'Warmup-LabVIEWRuntime.ps1'
- if (-not (Test-Path -LiteralPath $warmupScript)) { throw "Warmup-LabVIEWRuntime.ps1 not found at $warmupScript" }
- $warmParams = @{ JsonLogPath = $warmupLog }
- if ($LabVIEWExePath) { $warmParams.LabVIEWPath = $LabVIEWExePath }
- $warmupRunner = {
- param($warmupScriptPath, $warmupParameters)
- & $warmupScriptPath @warmupParameters | Out-Null
+function New-DualPlaneParitySummary {
+ param(
+ [Parameter(Mandatory)][object]$X64Session,
+ [Parameter(Mandatory)][object]$X32Session
+ )
+
+ $mismatches = New-Object System.Collections.Generic.List[object]
+ $comparedFields = @('outcome.exitCode', 'outcome.diff', 'compare.report', 'compare.mode', 'compare.policy')
+
+ foreach ($field in $comparedFields) {
+ $x64Value = switch ($field) {
+ 'outcome.exitCode' { Convert-ToParityComparableValue $X64Session.outcome.exitCode }
+ 'outcome.diff' { Convert-ToParityComparableValue $X64Session.outcome.diff }
+ 'compare.report' { Convert-ToParityComparableValue $X64Session.compare.report }
+ 'compare.mode' { Convert-ToParityComparableValue $X64Session.compare.mode }
+ 'compare.policy' { Convert-ToParityComparableValue $X64Session.compare.policy }
+ default { $null }
}
- try {
- Invoke-WithTimeout -Block $warmupRunner -TimeoutSeconds $effectiveTimeout -Stage 'warmup' -DisableTimeout:$DisableTimeout -ArgumentList @($warmupScript, $warmParams) | Out-Null
- $warmupRan = $true
- } catch {
- $err = $_.Exception.Message
- throw
+ $x32Value = switch ($field) {
+ 'outcome.exitCode' { Convert-ToParityComparableValue $X32Session.outcome.exitCode }
+ 'outcome.diff' { Convert-ToParityComparableValue $X32Session.outcome.diff }
+ 'compare.report' { Convert-ToParityComparableValue $X32Session.compare.report }
+ 'compare.mode' { Convert-ToParityComparableValue $X32Session.compare.mode }
+ 'compare.policy' { Convert-ToParityComparableValue $X32Session.compare.policy }
+ default { $null }
+ }
+
+ if ($x64Value -ne $x32Value) {
+ $mismatches.Add([ordered]@{ field = $field; x64 = $x64Value; x32 = $x32Value }) | Out-Null
}
}
- # 2) Invoke LVCompare (deterministic)
- $invoke = Join-Path $repo 'tools' 'Invoke-LVCompare.ps1'
- if (-not (Test-Path -LiteralPath $invoke)) { throw "Invoke-LVCompare.ps1 not found at $invoke" }
- $invokeParams = @{
- BaseVi = $BaseVi
- HeadVi = $HeadVi
- OutputDir = $paths.compareDir
- JsonLogPath = $compareLog
- RenderReport = $RenderReport.IsPresent
- NoiseProfile = $NoiseProfile
- }
- if ($LabVIEWExePath) { $invokeParams.LabVIEWExePath = $LabVIEWExePath }
- if ($LVComparePath) { $invokeParams.LVComparePath = $LVComparePath }
- if ($Flags) { $invokeParams.Flags = $Flags }
- if ($ReplaceFlags) { $invokeParams.ReplaceFlags = $true }
- if ($AllowSameLeaf.IsPresent) { $invokeParams.AllowSameLeaf = $true }
- $compareRunner = {
- param($invokePath, $invokeParameters)
- & $invokePath @invokeParameters | Out-Null
- }
- Invoke-WithTimeout -Block $compareRunner -TimeoutSeconds $effectiveTimeout -Stage 'compare' -DisableTimeout:$DisableTimeout -ArgumentList @($invoke, $invokeParams) | Out-Null
- if (Test-Path -LiteralPath $capPath) { $cap = Get-Content -LiteralPath $capPath -Raw | ConvertFrom-Json }
-} catch { $err = $_.Exception.Message }
-finally {
- if ($CloseLVCompare -and (Test-Path -LiteralPath $closeLVCompareScript)) {
- try { & $closeLVCompareScript | Out-Null } catch {}
- }
- if ($CloseLabVIEW -and (Test-Path -LiteralPath $closeLabVIEWScript)) {
- try { & $closeLabVIEWScript -MinimumSupportedLVVersion '2025' -SupportedBitness '64' | Out-Null } catch {}
+ $incomplete = (
+ ($null -eq $X64Session.outcome) -or
+ ($null -eq $X32Session.outcome) -or
+ (-not [string]::IsNullOrWhiteSpace([string]$X64Session.error)) -or
+ (-not [string]::IsNullOrWhiteSpace([string]$X32Session.error))
+ )
+
+ $status = if ($incomplete) {
+ 'incomplete'
+ } elseif ($mismatches.Count -gt 0) {
+ 'mismatch'
+ } else {
+ 'match'
}
-}
-# 4) Session index (always write)
-$reportExists = Test-Path -LiteralPath $reportPath -PathType Leaf
-$warmupNode = [ordered]@{
- mode = $Warmup
- events = if ($warmupRan) { $warmupLog } else { $null }
+ return [ordered]@{
+ status = $status
+ comparedFields = $comparedFields
+ exitCodeParity = if ($null -eq $X64Session.outcome -or $null -eq $X32Session.outcome) { $null } else { [bool]($X64Session.outcome.exitCode -eq $X32Session.outcome.exitCode) }
+ diffParity = if ($null -eq $X64Session.outcome -or $null -eq $X32Session.outcome) { $null } else { [bool]($X64Session.outcome.diff -eq $X32Session.outcome.diff) }
+ mismatchCount = $mismatches.Count
+ mismatches = @($mismatches.ToArray())
+ }
}
-$compareNode = [ordered]@{
- events = $compareLog
- capture = $capPath
- report = $reportExists
+
+function Wait-ForChildProcesses {
+ param(
+ [Parameter(Mandatory)][System.Diagnostics.Process[]]$Processes,
+ [int]$TimeoutSeconds = 0
+ )
+
+ $deadline = if ($TimeoutSeconds -gt 0) { (Get-Date).AddSeconds($TimeoutSeconds) } else { $null }
+ while ($true) {
+ $active = @($Processes | Where-Object { -not $_.HasExited })
+ if ($active.Count -eq 0) {
+ break
+ }
+ if ($deadline -and (Get-Date) -gt $deadline) {
+ foreach ($proc in $active) {
+ try { Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue } catch {}
+ }
+ throw (New-Object System.TimeoutException("Dual-plane parity suite exceeded ${TimeoutSeconds}s"))
+ }
+ Start-Sleep -Milliseconds 250
+ foreach ($proc in $Processes) {
+ try { $null = $proc.Refresh() } catch {}
+ }
+ }
}
-$compareNode.staging = [ordered]@{
- enabled = [bool]([string]::IsNullOrWhiteSpace($StagingRoot) -eq $false)
- root = if ([string]::IsNullOrWhiteSpace($StagingRoot)) { $null } else { $StagingRoot }
+
+function Start-DualPlaneChildProcess {
+ param(
+ [Parameter(Mandatory)][string]$ScriptPath,
+ [Parameter(Mandatory)][string]$PlaneKey,
+ [Parameter(Mandatory)][string]$BaseVi,
+ [Parameter(Mandatory)][string]$HeadVi,
+ [Parameter(Mandatory)][string]$OutputRoot,
+ [Parameter(Mandatory)][string]$LabVIEWExePath,
+ [Parameter(Mandatory)][ValidateSet('32','64')][string]$LabVIEWBitness,
+ [AllowNull()][string]$LVComparePath,
+ [ValidateSet('detect','spawn','skip')][string]$Warmup,
+ [AllowNull()][string[]]$Flags,
+ [bool]$ReplaceFlags,
+ [ValidateSet('full','legacy')][string]$NoiseProfile,
+ [bool]$RenderReport,
+ [bool]$CloseLabVIEW,
+ [bool]$CloseLVCompare,
+ [int]$TimeoutSeconds,
+ [bool]$DisableTimeout,
+ [AllowNull()][string]$StagingRoot,
+ [bool]$SameNameHint,
+ [bool]$AllowSameLeaf,
+ [AllowNull()][string]$AgentId,
+ [AllowNull()][string]$AgentClass,
+ [AllowNull()][string]$ExecutionCellLeasePath,
+ [AllowNull()][string]$ExecutionCellId,
+ [AllowNull()][string]$ExecutionCellLeaseId,
+ [AllowNull()][string]$ExecutionCellSuiteClass,
+ [AllowNull()][string]$ParentHarnessInstanceId
+ )
+
+ $pwsh = (Get-Command pwsh -ErrorAction Stop).Source
+ $args = New-Object System.Collections.Generic.List[string]
+ $args.Add('-NoLogo') | Out-Null
+ $args.Add('-NoProfile') | Out-Null
+ $args.Add('-File') | Out-Null
+ $args.Add($ScriptPath) | Out-Null
+ $args.Add('-BaseVi') | Out-Null
+ $args.Add($BaseVi) | Out-Null
+ $args.Add('-HeadVi') | Out-Null
+ $args.Add($HeadVi) | Out-Null
+ $args.Add('-OutputRoot') | Out-Null
+ $args.Add($OutputRoot) | Out-Null
+ $args.Add('-LabVIEWExePath') | Out-Null
+ $args.Add($LabVIEWExePath) | Out-Null
+ $args.Add('-LabVIEWBitness') | Out-Null
+ $args.Add($LabVIEWBitness) | Out-Null
+ $args.Add('-Warmup') | Out-Null
+ $args.Add($Warmup) | Out-Null
+ $args.Add('-NoiseProfile') | Out-Null
+ $args.Add($NoiseProfile) | Out-Null
+ $args.Add('-SuiteClass') | Out-Null
+ $args.Add('single-compare') | Out-Null
+ $args.Add('-InternalSinglePlane') | Out-Null
+ $args.Add('-InternalPlaneKey') | Out-Null
+ $args.Add($PlaneKey) | Out-Null
+
+ if ($LVComparePath) {
+ $args.Add('-LVComparePath') | Out-Null
+ $args.Add($LVComparePath) | Out-Null
+ }
+ if ($Flags) {
+ foreach ($flag in $Flags) {
+ $args.Add('-Flags') | Out-Null
+ $args.Add($flag) | Out-Null
+ }
+ }
+ if ($ReplaceFlags) { $args.Add('-ReplaceFlags') | Out-Null }
+ if ($RenderReport) { $args.Add('-RenderReport') | Out-Null }
+ if ($CloseLabVIEW) { $args.Add('-CloseLabVIEW') | Out-Null }
+ if ($CloseLVCompare) { $args.Add('-CloseLVCompare') | Out-Null }
+ if ($DisableTimeout) { $args.Add('-DisableTimeout') | Out-Null } else {
+ $args.Add('-TimeoutSeconds') | Out-Null
+ $args.Add([string]$TimeoutSeconds) | Out-Null
+ }
+ if ($StagingRoot) {
+ $args.Add('-StagingRoot') | Out-Null
+ $args.Add($StagingRoot) | Out-Null
+ }
+ if ($AgentId) {
+ $args.Add('-AgentId') | Out-Null
+ $args.Add($AgentId) | Out-Null
+ }
+ if ($AgentClass) {
+ $args.Add('-AgentClass') | Out-Null
+ $args.Add($AgentClass) | Out-Null
+ }
+ if ($ExecutionCellLeasePath) {
+ $args.Add('-ExecutionCellLeasePath') | Out-Null
+ $args.Add($ExecutionCellLeasePath) | Out-Null
+ }
+ if ($ExecutionCellId) {
+ $args.Add('-ExecutionCellId') | Out-Null
+ $args.Add($ExecutionCellId) | Out-Null
+ }
+ if ($ExecutionCellLeaseId) {
+ $args.Add('-ExecutionCellLeaseId') | Out-Null
+ $args.Add($ExecutionCellLeaseId) | Out-Null
+ }
+ if ($ExecutionCellSuiteClass) {
+ $args.Add('-ExecutionCellSuiteClass') | Out-Null
+ $args.Add($ExecutionCellSuiteClass) | Out-Null
+ }
+ if ($ParentHarnessInstanceId) {
+ $args.Add('-ParentHarnessInstanceId') | Out-Null
+ $args.Add($ParentHarnessInstanceId) | Out-Null
+ }
+ if ($SameNameHint) { $args.Add('-SameNameHint') | Out-Null }
+ if ($AllowSameLeaf) { $args.Add('-AllowSameLeaf') | Out-Null }
+
+ return Start-Process -FilePath $pwsh -ArgumentList @($args.ToArray()) -PassThru -WindowStyle Hidden
}
-$compareNode.allowSameLeaf = $AllowSameLeaf.IsPresent
-if ($cap) {
- if ($cap.PSObject.Properties['command']) { $compareNode.command = $cap.command }
- if ($cap.PSObject.Properties['cliPath']) { $compareNode.cliPath = $cap.cliPath }
- if ($cap.PSObject.Properties['environment']) {
- $envNode = $cap.environment
- if ($envNode -and $envNode.PSObject.Properties['cli']) {
- $compareNode.cli = $envNode.cli
+
+function Invoke-DualPlaneParitySuite {
+ param(
+ [Parameter(Mandatory)][string]$RepoRoot,
+ [Parameter(Mandatory)][string]$ScriptPath,
+ [Parameter(Mandatory)][string]$BaseVi,
+ [Parameter(Mandatory)][string]$HeadVi,
+ [Parameter(Mandatory)][string]$OutputRoot,
+ [AllowNull()][string]$DefaultLabVIEWExePath,
+ [AllowNull()][string]$LabVIEW64ExePath,
+ [AllowNull()][string]$LabVIEW32ExePath,
+ [AllowNull()][string]$LVComparePath,
+ [ValidateSet('detect','spawn','skip')][string]$Warmup,
+ [AllowNull()][string[]]$Flags,
+ [bool]$ReplaceFlags,
+ [ValidateSet('full','legacy')][string]$NoiseProfile,
+ [bool]$RenderReport,
+ [bool]$CloseLabVIEW,
+ [bool]$CloseLVCompare,
+ [int]$TimeoutSeconds,
+ [bool]$DisableTimeout,
+ [AllowNull()][string]$StagingRoot,
+ [bool]$SameNameHint,
+ [bool]$AllowSameLeaf,
+ [AllowNull()][string]$AgentId,
+ [AllowNull()][string]$AgentClass,
+ [AllowNull()][string]$ExecutionCellLeasePath,
+ [AllowNull()][string]$ExecutionCellId,
+ [AllowNull()][string]$ExecutionCellLeaseId,
+ [AllowNull()][string]$HarnessInstanceId
+ )
+
+ $resolvedOutputRoot = Resolve-AbsolutePath -RepoRoot $RepoRoot -Candidate $OutputRoot
+ New-Dir $resolvedOutputRoot
+ $dualPlaneContext = Resolve-TestStandExecutionCellContext -ExecutionCellLeasePath $ExecutionCellLeasePath -ExecutionCellId $ExecutionCellId -ExecutionCellLeaseId $ExecutionCellLeaseId -ExecutionCellSuiteClass 'dual-plane-parity' -HarnessInstanceId $HarnessInstanceId -AgentId $AgentId -AgentClass $AgentClass -SuiteClass 'dual-plane-parity' -PlaneName $null -Role 'coordinator' -OutputRoot $resolvedOutputRoot
+
+ $x64LabVIEW = if ([string]::IsNullOrWhiteSpace($LabVIEW64ExePath)) {
+ if ([string]::IsNullOrWhiteSpace($DefaultLabVIEWExePath)) { Resolve-LabVIEW2026Path -Bitness '64' } else { $DefaultLabVIEWExePath }
+ } else {
+ $LabVIEW64ExePath
+ }
+ $x32LabVIEW = if ([string]::IsNullOrWhiteSpace($LabVIEW32ExePath)) { Resolve-LabVIEW2026Path -Bitness '32' } else { $LabVIEW32ExePath }
+
+ $planesRoot = Join-Path $resolvedOutputRoot 'planes'
+ $x64Root = Join-Path $planesRoot 'x64'
+ $x32Root = Join-Path $planesRoot 'x32'
+ New-Dir $x64Root
+ New-Dir $x32Root
+
+ $suiteTimeout = if ($DisableTimeout -or $TimeoutSeconds -le 0) { 0 } else { [Math]::Max(30, $TimeoutSeconds + 30) }
+
+ $x64Process = Start-DualPlaneChildProcess -ScriptPath $ScriptPath -PlaneKey 'x64' -BaseVi $BaseVi -HeadVi $HeadVi -OutputRoot $x64Root -LabVIEWExePath $x64LabVIEW -LabVIEWBitness '64' -LVComparePath $LVComparePath -Warmup $Warmup -Flags $Flags -ReplaceFlags:$ReplaceFlags -NoiseProfile $NoiseProfile -RenderReport:$RenderReport -CloseLabVIEW:$CloseLabVIEW -CloseLVCompare:$CloseLVCompare -TimeoutSeconds $TimeoutSeconds -DisableTimeout:$DisableTimeout -StagingRoot $StagingRoot -SameNameHint:$SameNameHint -AllowSameLeaf:$AllowSameLeaf -AgentId $AgentId -AgentClass $AgentClass -ExecutionCellLeasePath $ExecutionCellLeasePath -ExecutionCellId $ExecutionCellId -ExecutionCellLeaseId $ExecutionCellLeaseId -ExecutionCellSuiteClass 'dual-plane-parity' -ParentHarnessInstanceId $dualPlaneContext.harnessInstance.instanceId
+ $x32Process = Start-DualPlaneChildProcess -ScriptPath $ScriptPath -PlaneKey 'x32' -BaseVi $BaseVi -HeadVi $HeadVi -OutputRoot $x32Root -LabVIEWExePath $x32LabVIEW -LabVIEWBitness '32' -LVComparePath $LVComparePath -Warmup $Warmup -Flags $Flags -ReplaceFlags:$ReplaceFlags -NoiseProfile $NoiseProfile -RenderReport:$RenderReport -CloseLabVIEW:$CloseLabVIEW -CloseLVCompare:$CloseLVCompare -TimeoutSeconds $TimeoutSeconds -DisableTimeout:$DisableTimeout -StagingRoot $StagingRoot -SameNameHint:$SameNameHint -AllowSameLeaf:$AllowSameLeaf -AgentId $AgentId -AgentClass $AgentClass -ExecutionCellLeasePath $ExecutionCellLeasePath -ExecutionCellId $ExecutionCellId -ExecutionCellLeaseId $ExecutionCellLeaseId -ExecutionCellSuiteClass 'dual-plane-parity' -ParentHarnessInstanceId $dualPlaneContext.harnessInstance.instanceId
+
+ Wait-ForChildProcesses -Processes @($x64Process, $x32Process) -TimeoutSeconds $suiteTimeout
+
+ $x64IndexPath = Join-Path $x64Root 'session-index.json'
+ $x32IndexPath = Join-Path $x32Root 'session-index.json'
+ if (-not (Test-Path -LiteralPath $x64IndexPath -PathType Leaf)) {
+ throw "Dual-plane parity suite missing x64 session index at $x64IndexPath"
+ }
+ if (-not (Test-Path -LiteralPath $x32IndexPath -PathType Leaf)) {
+ throw "Dual-plane parity suite missing x32 session index at $x32IndexPath"
+ }
+
+ $x64Index = Get-Content -LiteralPath $x64IndexPath -Raw | ConvertFrom-Json -Depth 12
+ $x32Index = Get-Content -LiteralPath $x32IndexPath -Raw | ConvertFrom-Json -Depth 12
+
+ $x64Session = [pscustomobject][ordered]@{
+ plane = 'native-labview-2026-64'
+ architecture = '64-bit'
+ labviewExePath = $x64LabVIEW
+ outputRoot = $x64Root
+ warmup = $x64Index.warmup
+ compare = $x64Index.compare
+ outcome = $x64Index.outcome
+ error = $x64Index.error
+ exitCode = if ($null -ne $x64Index.outcome) { [int]$x64Index.outcome.exitCode } else { if ($x64Process.ExitCode -is [int]) { [int]$x64Process.ExitCode } else { 1 } }
+ executionCell = $x64Index.executionCell
+ harnessInstance = $x64Index.harnessInstance
+ processModel = $x64Index.processModel
+ }
+ $x32Session = [pscustomobject][ordered]@{
+ plane = 'native-labview-2026-32'
+ architecture = '32-bit'
+ labviewExePath = $x32LabVIEW
+ outputRoot = $x32Root
+ warmup = $x32Index.warmup
+ compare = $x32Index.compare
+ outcome = $x32Index.outcome
+ error = $x32Index.error
+ exitCode = if ($null -ne $x32Index.outcome) { [int]$x32Index.outcome.exitCode } else { if ($x32Process.ExitCode -is [int]) { [int]$x32Process.ExitCode } else { 1 } }
+ executionCell = $x32Index.executionCell
+ harnessInstance = $x32Index.harnessInstance
+ processModel = $x32Index.processModel
+ }
+
+ $parity = New-DualPlaneParitySummary -X64Session $x64Session -X32Session $x32Session
+
+ $topError = if ($parity.status -eq 'incomplete') {
+ @($x64Session.error, $x32Session.error | Where-Object { -not [string]::IsNullOrWhiteSpace([string]$_) }) -join '; '
+ } else {
+ $null
+ }
+
+ $topIndex = [ordered]@{
+ schema = 'teststand-compare-session/v2'
+ at = (Get-Date).ToString('o')
+ suiteClass = 'dual-plane-parity'
+ primaryPlane = 'native-labview-2026-64'
+ requestedSimultaneous = $true
+ warmup = $x64Session.warmup
+ compare = $x64Session.compare
+ outcome = $x64Session.outcome
+ error = $topError
+ executionCell = $dualPlaneContext.executionCell
+ harnessInstance = $dualPlaneContext.harnessInstance
+ processModel = $dualPlaneContext.processModel
+ planes = [ordered]@{
+ x64 = $x64Session
+ x32 = $x32Session
}
+ parity = $parity
+ }
+
+ $indexPath = Join-Path $resolvedOutputRoot 'session-index.json'
+ $topIndex | ConvertTo-Json -Depth 12 | Out-File -LiteralPath $indexPath -Encoding utf8
+
+ $exitCode = switch ($parity.status) {
+ 'match' { if ($null -ne $x64Session.outcome) { [int]$x64Session.outcome.exitCode } else { 1 } }
+ 'mismatch' { 2 }
+ default { 1 }
}
+
+ Write-Host ("TestStand Dual-Plane Parity result: status={0} x64={1} x32={2} index={3}" -f $parity.status, $x64Session.exitCode, $x32Session.exitCode, $indexPath) -ForegroundColor Yellow
+ exit $exitCode
}
-$compareNode.autoCli = $autoCli
-$compareNode.sameName = $sameName
-$compareNode.timeoutSeconds = $effectiveTimeout
-if ($env:LVCI_COMPARE_POLICY) { $compareNode.policy = $env:LVCI_COMPARE_POLICY }
-if ($env:LVCI_COMPARE_MODE) { $compareNode.mode = $env:LVCI_COMPARE_MODE }
-
-$index = [ordered]@{
- schema = 'teststand-compare-session/v1'
- at = (Get-Date).ToString('o')
- warmup = $warmupNode
- compare = $compareNode
- outcome = if ($cap) {
- @{ exitCode=[int]$cap.exitCode; seconds=[double]$cap.seconds; command=$cap.command; diff=([bool]($cap.exitCode -eq 1)) }
- } else { $null }
- error = $err
+
+$repo = (Resolve-Path '.').Path
+
+if ($InternalSinglePlane -and [string]::IsNullOrWhiteSpace($InternalPlaneKey) -eq $false) {
+ if ($InternalPlaneKey -eq 'x32' -and -not $PSBoundParameters.ContainsKey('LabVIEWBitness')) {
+ $LabVIEWBitness = '32'
+ }
+ if ($InternalPlaneKey -eq 'x64' -and -not $PSBoundParameters.ContainsKey('LabVIEWBitness')) {
+ $LabVIEWBitness = '64'
+ }
+}
+
+if (-not [System.IO.Path]::IsPathRooted($OutputRoot)) {
+ $OutputRoot = Join-Path $repo $OutputRoot
}
-$indexPath = Join-Path $OutputRoot 'session-index.json'
-New-Dir $OutputRoot
-$index | ConvertTo-Json -Depth 6 | Out-File -LiteralPath $indexPath -Encoding utf8
-$exitCode = if ($cap) { [int]$cap.exitCode } else { 1 }
-$diffDisplay = if ($index.outcome) { $index.outcome.diff } else { 'unknown' }
-$exitDisplay = if ($index.outcome) { $index.outcome.exitCode } else { 'n/a' }
+if ($SuiteClass -eq 'dual-plane-parity' -and -not $InternalSinglePlane) {
+ Invoke-DualPlaneParitySuite -RepoRoot $repo -ScriptPath $PSCommandPath -BaseVi $BaseVi -HeadVi $HeadVi -OutputRoot $OutputRoot -DefaultLabVIEWExePath $LabVIEWExePath -LabVIEW64ExePath $LabVIEW64ExePath -LabVIEW32ExePath $LabVIEW32ExePath -LVComparePath $LVComparePath -Warmup $Warmup -Flags $Flags -ReplaceFlags:$ReplaceFlags -NoiseProfile $NoiseProfile -RenderReport:$RenderReport -CloseLabVIEW:$CloseLabVIEW -CloseLVCompare:$CloseLVCompare -TimeoutSeconds $TimeoutSeconds -DisableTimeout:$DisableTimeout -StagingRoot $StagingRoot -SameNameHint:$SameNameHint -AllowSameLeaf:$AllowSameLeaf -AgentId $AgentId -AgentClass $AgentClass -ExecutionCellLeasePath $ExecutionCellLeasePath -ExecutionCellId $ExecutionCellId -ExecutionCellLeaseId $ExecutionCellLeaseId -HarnessInstanceId $HarnessInstanceId
+ return
+}
+
+$planeName = switch ($InternalPlaneKey) {
+ 'x64' { 'native-labview-2026-64' }
+ 'x32' { 'native-labview-2026-32' }
+ default { $null }
+}
+$harnessRole = if ($InternalSinglePlane -and -not [string]::IsNullOrWhiteSpace($InternalPlaneKey)) { 'plane-child' } else { 'single-plane' }
+
+$singlePlaneSession = Invoke-TestStandSinglePlaneSession -RepoRoot $repo -BaseVi $BaseVi -HeadVi $HeadVi -LabVIEWExePath $LabVIEWExePath -LabVIEWBitness $LabVIEWBitness -LVComparePath $LVComparePath -OutputRoot $OutputRoot -Warmup $Warmup -Flags $Flags -ReplaceFlags:$ReplaceFlags -NoiseProfile $NoiseProfile -RenderReport:$RenderReport -CloseLabVIEW:$CloseLabVIEW -CloseLVCompare:$CloseLVCompare -TimeoutSeconds $TimeoutSeconds -DisableTimeout:$DisableTimeout -StagingRoot $StagingRoot -SameNameHint:$SameNameHint -AllowSameLeaf:$AllowSameLeaf -PlaneName $planeName -AgentId $AgentId -AgentClass $AgentClass -ExecutionCellLeasePath $ExecutionCellLeasePath -ExecutionCellId $ExecutionCellId -ExecutionCellLeaseId $ExecutionCellLeaseId -ExecutionCellSuiteClass $ExecutionCellSuiteClass -HarnessInstanceId $HarnessInstanceId -ParentHarnessInstanceId $ParentHarnessInstanceId -HarnessRole $harnessRole -SuiteClass $SuiteClass
+
+Write-TestStandV1SessionIndex -OutputRoot $OutputRoot -PlaneSession $singlePlaneSession
+
+$capPath = if ($singlePlaneSession.compare) { $singlePlaneSession.compare.capture } else { $null }
+$diffDisplay = if ($singlePlaneSession.outcome) { $singlePlaneSession.outcome.diff } else { 'unknown' }
+$exitDisplay = if ($singlePlaneSession.outcome) { $singlePlaneSession.outcome.exitCode } else { 'n/a' }
Write-Host ("TestStand Compare Harness result: exit={0} diff={1} capture={2}" -f $exitDisplay, $diffDisplay, $capPath) -ForegroundColor Yellow
-exit $exitCode
+exit $singlePlaneSession.exitCode
diff --git a/tools/Write-LabVIEW2026HostPlaneDiagnostics.ps1 b/tools/Write-LabVIEW2026HostPlaneDiagnostics.ps1
index 51cc89434..9e6e8ced8 100644
--- a/tools/Write-LabVIEW2026HostPlaneDiagnostics.ps1
+++ b/tools/Write-LabVIEW2026HostPlaneDiagnostics.ps1
@@ -109,6 +109,10 @@ function New-HostPlaneSummaryMarkdown {
)
$runner = Get-ObjectValue -Object $Report -Name 'runner'
+ $hostInfo = Get-ObjectValue -Object $Report -Name 'host'
+ $osFingerprint = Get-ObjectValue -Object $hostInfo -Name 'osFingerprint'
+ $osCanonical = Get-ObjectValue -Object $osFingerprint -Name 'canonical'
+ $osAdvisory = Get-ObjectValue -Object $osFingerprint -Name 'advisory'
$native = Get-ObjectValue -Object $Report -Name 'native'
$executionPolicy = Get-ObjectValue -Object $Report -Name 'executionPolicy'
$policy = Get-ObjectValue -Object $Report -Name 'policy'
@@ -135,6 +139,20 @@ function New-HostPlaneSummaryMarkdown {
'',
('- Report: `{0}`' -f $ReportPath),
('- Runner: `{0}` (hostIsRunner={1})' -f ([string](Get-ObjectValue -Object $runner -Name 'runnerName')), ([string][bool](Get-ObjectValue -Object $runner -Name 'hostIsRunner'))),
+ ('- Canonical host OS: `{0}` version=`{1}` build=`{2}` ubr=`{3}` displayVersion=`{4}` edition=`{5}` architecture=`{6}`' -f `
+ ([string](Get-ObjectValue -Object $osFingerprint -Name 'platform')), `
+ ([string](Get-ObjectValue -Object $osCanonical -Name 'version')), `
+ ([string](Get-ObjectValue -Object $osCanonical -Name 'buildNumber')), `
+ ([string](Get-ObjectValue -Object $osCanonical -Name 'ubr')), `
+ ([string](Get-ObjectValue -Object $osCanonical -Name 'displayVersion')), `
+ ([string](Get-ObjectValue -Object $osCanonical -Name 'editionId')), `
+ ([string](Get-ObjectValue -Object $osCanonical -Name 'architecture'))),
+ ('- Host OS fingerprint SHA-256: `{0}`' -f ([string](Get-ObjectValue -Object $osFingerprint -Name 'fingerprintSha256'))),
+ ('- Isolated lane group ID: `{0}`' -f ([string](Get-ObjectValue -Object $osFingerprint -Name 'isolatedLaneGroupId'))),
+ ('- Host OS branding: caption=`{0}` registryProduct=`{1}` mismatch={2}' -f `
+ ([string](Get-ObjectValue -Object $osAdvisory -Name 'caption')), `
+ ([string](Get-ObjectValue -Object $osAdvisory -Name 'productName')), `
+ ([string][bool](Get-ObjectValue -Object $osAdvisory -Name 'brandingMismatch'))),
('- Native 64-bit: `{0}`' -f ([string](Get-ObjectValue -Object $x64Plane -Name 'status'))),
('- Native 32-bit: `{0}`' -f ([string](Get-ObjectValue -Object $x32Plane -Name 'status'))),
('- Parallel native support: `{0}`' -f ([string][bool](Get-ObjectValue -Object $native -Name 'parallelLabVIEWSupported'))),
@@ -203,6 +221,10 @@ Write-GitHubOutput -Key 'labview-2026-host-plane-summary-path' -Value $summaryRe
Write-GitHubOutput -Key 'labview-2026-native-64-status' -Value ([string]$report.native.planes.x64.status) -Path $GitHubOutputPath
Write-GitHubOutput -Key 'labview-2026-native-32-status' -Value ([string]$report.native.planes.x32.status) -Path $GitHubOutputPath
Write-GitHubOutput -Key 'labview-2026-native-parallel-supported' -Value ([string][bool]$report.native.parallelLabVIEWSupported) -Path $GitHubOutputPath
+Write-GitHubOutput -Key 'labview-2026-host-os-fingerprint-sha256' -Value ([string]$report.host.osFingerprint.fingerprintSha256) -Path $GitHubOutputPath
+Write-GitHubOutput -Key 'labview-2026-host-isolated-lane-group-id' -Value ([string]$report.host.osFingerprint.isolatedLaneGroupId) -Path $GitHubOutputPath
+Write-GitHubOutput -Key 'labview-2026-host-os-version' -Value ([string]$report.host.osFingerprint.canonical.version) -Path $GitHubOutputPath
+Write-GitHubOutput -Key 'labview-2026-host-os-build' -Value ([string]$report.host.osFingerprint.canonical.buildNumber) -Path $GitHubOutputPath
if ($PassThru) {
Write-Output $report
diff --git a/tools/policy/github-comment-budget-hook.json b/tools/policy/github-comment-budget-hook.json
new file mode 100644
index 000000000..8fe08f642
--- /dev/null
+++ b/tools/policy/github-comment-budget-hook.json
@@ -0,0 +1,16 @@
+{
+ "schema": "priority/github-comment-budget-hook-policy@v1",
+ "costRollupPath": "tests/results/_agent/cost/agent-cost-rollup.json",
+ "materializationPolicyPath": "tools/policy/agent-cost-rollup-materialization.json",
+ "materializationReportPath": "tests/results/_agent/cost/agent-cost-rollup-materialization.json",
+ "outputPath": "tests/results/_agent/cost/github-comment-budget-hook.json",
+ "markdownOutputPath": "tests/results/_agent/cost/github-comment-budget-hook.md",
+ "operatorBudgetCapUsd": 50000,
+ "materializeCostRollup": true,
+ "reservedFundingPurposes": [
+ "calibration"
+ ],
+ "reservedActivationStates": [
+ "hold"
+ ]
+}
diff --git a/tools/priority/Import-HandoffState.ps1 b/tools/priority/Import-HandoffState.ps1
index 607458f40..1d93baa89 100644
--- a/tools/priority/Import-HandoffState.ps1
+++ b/tools/priority/Import-HandoffState.ps1
@@ -46,6 +46,7 @@ $continuitySummary = Read-HandoffJson -Name 'continuity-summary.json'
$monitoringMode = Read-HandoffJson -Name 'monitoring-mode.json'
$governorSummary = Read-HandoffJson -Name 'autonomous-governor-summary.json'
$governorPortfolioSummary = Read-HandoffJson -Name 'autonomous-governor-portfolio-summary.json'
+$contextConcentrator = Read-HandoffJson -Name 'sagan-context-concentrator.json'
$operatorSteeringEvent = Read-HandoffJson -Name 'operator-steering-event.json'
if ($issueSummary) {
@@ -277,6 +278,18 @@ if ($governorSummary) {
Write-Host (" next : {0}" -f (Format-NullableValue $governorSummary.summary.nextAction))
Write-Host (" queue : {0}" -f (Format-NullableValue $governorSummary.summary.queueState))
Write-Host (" signal : {0}" -f (Format-NullableValue $governorSummary.summary.signalQuality))
+ if ($governorSummary.summary.PSObject.Properties['releaseSigningStatus']) {
+ Write-Host (" release : {0}" -f (Format-NullableValue $governorSummary.summary.releaseSigningStatus))
+ if ($governorSummary.summary.PSObject.Properties['releaseSigningExternalBlocker'] -and $governorSummary.summary.releaseSigningExternalBlocker) {
+ Write-Host (" blocker : {0}" -f (Format-NullableValue $governorSummary.summary.releaseSigningExternalBlocker))
+ }
+ if ($governorSummary.summary.PSObject.Properties['releasePublishedBundleState'] -and $governorSummary.summary.releasePublishedBundleState) {
+ Write-Host (" bundle : {0}" -f (Format-NullableValue $governorSummary.summary.releasePublishedBundleState))
+ }
+ if ($governorSummary.summary.PSObject.Properties['releasePublishedBundleReleaseTag'] -and $governorSummary.summary.releasePublishedBundleReleaseTag) {
+ Write-Host (" bundleTag: {0}" -f (Format-NullableValue $governorSummary.summary.releasePublishedBundleReleaseTag))
+ }
+ }
if ($governorSummary.summary.nextOwnerRepository) {
Write-Host (" nextRepo : {0}" -f (Format-NullableValue $governorSummary.summary.nextOwnerRepository))
}
@@ -304,6 +317,21 @@ if ($governorPortfolioSummary) {
Write-Host (" next : {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.nextAction))
Write-Host (" template : {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.templateMonitoringStatus))
Write-Host (" proof : {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.supportedProofStatus))
+ if ($governorPortfolioSummary.summary.PSObject.Properties['viHistoryDistributorDependencyStatus']) {
+ Write-Host (" vhist : {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.viHistoryDistributorDependencyStatus))
+ if ($governorPortfolioSummary.summary.PSObject.Properties['viHistoryDistributorDependencyTargetRepository'] -and $governorPortfolioSummary.summary.viHistoryDistributorDependencyTargetRepository) {
+ Write-Host (" vhistRepo: {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.viHistoryDistributorDependencyTargetRepository))
+ }
+ if ($governorPortfolioSummary.summary.PSObject.Properties['viHistoryDistributorDependencyExternalBlocker'] -and $governorPortfolioSummary.summary.viHistoryDistributorDependencyExternalBlocker) {
+ Write-Host (" vhistBlk : {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.viHistoryDistributorDependencyExternalBlocker))
+ }
+ if ($governorPortfolioSummary.summary.PSObject.Properties['viHistoryDistributorDependencyPublishedBundleState'] -and $governorPortfolioSummary.summary.viHistoryDistributorDependencyPublishedBundleState) {
+ Write-Host (" vhistPub : {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.viHistoryDistributorDependencyPublishedBundleState))
+ }
+ if ($governorPortfolioSummary.summary.PSObject.Properties['viHistoryDistributorDependencyPublishedBundleReleaseTag'] -and $governorPortfolioSummary.summary.viHistoryDistributorDependencyPublishedBundleReleaseTag) {
+ Write-Host (" vhistTag : {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.viHistoryDistributorDependencyPublishedBundleReleaseTag))
+ }
+ }
if ($governorPortfolioSummary.summary.nextOwnerRepository) {
Write-Host (" nextRepo : {0}" -f (Format-NullableValue $governorPortfolioSummary.summary.nextOwnerRepository))
}
@@ -317,6 +345,23 @@ if ($governorPortfolioSummary) {
}
Set-Variable -Name HandoffAutonomousGovernorPortfolioSummary -Scope Global -Value $governorPortfolioSummary -Force
}
+if ($contextConcentrator) {
+ Write-Host '[handoff] Context concentrator' -ForegroundColor Cyan
+ Write-Host (" status : {0}" -f (Format-NullableValue $contextConcentrator.summary.concentrationStatus))
+ if ($contextConcentrator.summary.activeIssueNumber) {
+ Write-Host (" issue : #{0}" -f (Format-NullableValue $contextConcentrator.summary.activeIssueNumber))
+ }
+ Write-Host (" owner : {0}" -f (Format-NullableValue $contextConcentrator.summary.currentOwnerRepository))
+ Write-Host (" next : {0}" -f (Format-NullableValue $contextConcentrator.summary.nextAction))
+ Write-Host (" hot/warm : {0}/{1}" -f (Format-NullableValue $contextConcentrator.summary.hotWorkingSetCount), (Format-NullableValue $contextConcentrator.summary.warmMemoryCount))
+ Write-Host (" archive : {0}" -f (Format-NullableValue $contextConcentrator.summary.archiveCount))
+ Write-Host (" blockers : {0}" -f (Format-NullableValue $contextConcentrator.summary.blockerCount))
+ Write-Host (' spend : ${0}' -f (Format-NullableValue $contextConcentrator.summary.blendedLowerBoundUsd))
+ foreach ($entry in @($contextConcentrator.memory.hotWorkingSet | Select-Object -First 3)) {
+ Write-Host (" - {0} [{1}]" -f (Format-NullableValue $entry.label), (Format-NullableValue $entry.status))
+ }
+ Set-Variable -Name HandoffContextConcentrator -Scope Global -Value $contextConcentrator -Force
+}
if ($operatorSteeringEvent) {
Write-Host '[handoff] Operator steering event' -ForegroundColor Cyan
Write-Host (" steering : {0}" -f (Format-NullableValue $operatorSteeringEvent.steeringKind))
diff --git a/tools/priority/__tests__/autonomous-governor-portfolio-summary-schema.test.mjs b/tools/priority/__tests__/autonomous-governor-portfolio-summary-schema.test.mjs
index 63a7b674c..89d3ef601 100644
--- a/tools/priority/__tests__/autonomous-governor-portfolio-summary-schema.test.mjs
+++ b/tools/priority/__tests__/autonomous-governor-portfolio-summary-schema.test.mjs
@@ -67,6 +67,19 @@ test('autonomous governor portfolio summary schema validates a generated report'
queueState: { status: 'queue-empty', reason: 'queue-empty', openIssueCount: 0, ready: true },
continuity: { status: 'maintained', turnBoundary: 'safe-idle', supervisionState: 'idle-monitoring', operatorPromptRequiredToResume: false },
monitoringMode: { status: 'active', futureAgentAction: 'future-agent-may-pivot', wakeConditionCount: 0 },
+ releaseSigningReadiness: {
+ status: 'missing',
+ codePathState: null,
+ signingCapabilityState: null,
+ signingAuthorityState: null,
+ releaseConductorApplyState: null,
+ publicationState: null,
+ publishedBundleState: null,
+ publishedBundleReleaseTag: null,
+ publishedBundleAuthoritativeConsumerPin: null,
+ externalBlocker: null,
+ blockerCount: 0
+ },
deliveryRuntime: {
status: 'checks-pending',
runtimeStatus: 'waiting-ci',
@@ -117,6 +130,14 @@ test('autonomous governor portfolio summary schema validates a generated report'
wakeTerminalState: 'monitoring',
monitoringStatus: 'active',
futureAgentAction: 'future-agent-may-pivot',
+ releaseSigningStatus: 'missing',
+ releaseSigningAuthorityState: null,
+ releaseConductorApplyState: null,
+ releaseSigningExternalBlocker: null,
+ releasePublicationState: null,
+ releasePublishedBundleState: null,
+ releasePublishedBundleReleaseTag: null,
+ releasePublishedBundleAuthoritativeConsumerPin: null,
queueHandoffStatus: 'checks-pending',
queueHandoffNextWakeCondition: 'checks-green',
queueHandoffPrUrl: 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/pull/1864',
diff --git a/tools/priority/__tests__/autonomous-governor-portfolio-summary.test.mjs b/tools/priority/__tests__/autonomous-governor-portfolio-summary.test.mjs
index 289d36950..d064ad9e9 100644
--- a/tools/priority/__tests__/autonomous-governor-portfolio-summary.test.mjs
+++ b/tools/priority/__tests__/autonomous-governor-portfolio-summary.test.mjs
@@ -42,6 +42,74 @@ function createCompareGovernorSummary(overrides = {}) {
status: 'blocked',
futureAgentAction: 'stay-in-compare-monitoring',
wakeConditionCount: 3
+ },
+ releaseSigningReadiness: {
+ status: 'warn',
+ codePathState: 'ready',
+ signingCapabilityState: 'missing',
+ signingAuthorityState: 'scope-missing',
+ releaseConductorApplyState: 'disabled',
+ publicationState: 'unobserved',
+ publishedBundleState: 'producer-native-incomplete',
+ publishedBundleReleaseTag: 'v0.6.3-tools.14',
+ publishedBundleAuthoritativeConsumerPin: null,
+ externalBlocker: 'workflow-signing-secret-missing'
+ },
+ deliveryRuntime: {
+ executionTopology: {
+ status: 'bundle-committed',
+ executionPlane: 'hosted',
+ providerId: 'hosted-github-workflow',
+ workerSlotId: 'worker-slot-2',
+ activeLogicalLaneCount: 2,
+ seededLogicalLaneCount: 4,
+ catalogCount: 4,
+ runtimeSurface: 'windows-native-teststand',
+ processModelClass: 'parallel-process-model',
+ windowsOnly: true,
+ requestedSimultaneous: true,
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ premiumSaganMode: true,
+ reciprocalLinkReady: true,
+ logicalLaneActivation: {
+ activeLaneCount: 2,
+ seededLaneCount: 4,
+ catalogCount: 4
+ },
+ providerDispatch: {
+ providerId: 'hosted-github-workflow',
+ providerKind: 'hosted-github-workflow',
+ executionPlane: 'hosted',
+ assignmentMode: 'async-validation',
+ dispatchSurface: 'github-actions',
+ completionMode: 'async',
+ workerSlotId: 'worker-slot-2',
+ dispatchStatus: 'completed',
+ completionStatus: 'waiting',
+ failureClass: null
+ },
+ executionBundle: {
+ status: 'committed',
+ planeBinding: 'dual-plane-parity',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ premiumSaganMode: true,
+ reciprocalLinkReady: true,
+ effectiveBillableRateUsdPerHour: 375,
+ executionCellLeaseId: 'exec-lease-123',
+ dockerLaneLeaseId: 'docker-lease-456',
+ harnessInstanceId: 'ts-harness-01',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ cellId: 'cell-sagan-kernel',
+ laneId: 'docker-lane-01',
+ isolatedLaneGroupId:
+ 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+ }
+ }
}
},
wake: {
@@ -84,7 +152,33 @@ function createCompareGovernorSummary(overrides = {}) {
queueHandoffStatus: 'checks-pending',
queueHandoffNextWakeCondition: 'checks-green',
queueHandoffPrUrl: 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/pull/1864',
- queueAuthoritySource: 'delivery-runtime'
+ queueAuthoritySource: 'delivery-runtime',
+ executionTopologyStatus: 'bundle-committed',
+ executionTopologyExecutionPlane: 'hosted',
+ executionTopologyProviderId: 'hosted-github-workflow',
+ executionTopologyWorkerSlotId: 'worker-slot-2',
+ executionTopologyActiveLogicalLaneCount: 2,
+ executionTopologySeededLogicalLaneCount: 4,
+ executionTopologyRuntimeSurface: 'windows-native-teststand',
+ executionTopologyProcessModelClass: 'parallel-process-model',
+ executionTopologyWindowsOnly: true,
+ executionTopologyRequestedSimultaneous: true,
+ executionTopologyCellClass: 'kernel-coordinator',
+ executionTopologySuiteClass: 'dual-plane-parity',
+ executionTopologyOperatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ executionBundleStatus: 'committed',
+ executionBundlePlaneBinding: 'dual-plane-parity',
+ executionBundlePremiumSaganMode: true,
+ executionBundleReciprocalLinkReady: true,
+ executionBundleEffectiveBillableRateUsdPerHour: 375,
+ releaseSigningStatus: 'warn',
+ releaseSigningAuthorityState: 'scope-missing',
+ releaseConductorApplyState: 'disabled',
+ releaseSigningExternalBlocker: 'workflow-signing-secret-missing',
+ releasePublicationState: 'unobserved',
+ releasePublishedBundleState: 'producer-native-incomplete',
+ releasePublishedBundleReleaseTag: 'v0.6.3-tools.14',
+ releasePublishedBundleAuthoritativeConsumerPin: null
},
...overrides
};
@@ -306,9 +400,85 @@ test('runAutonomousGovernorPortfolioSummary keeps compare as owner during active
assert.equal(report.summary.queueHandoffStatus, 'checks-pending');
assert.equal(report.summary.queueHandoffNextWakeCondition, 'checks-green');
assert.equal(report.summary.queueAuthoritySource, 'delivery-runtime');
+ assert.equal(report.summary.executionTopologyStatus, 'bundle-committed');
+ assert.equal(report.summary.executionTopologyExecutionPlane, 'hosted');
+ assert.equal(report.summary.executionTopologyProviderId, 'hosted-github-workflow');
+ assert.equal(report.summary.executionTopologyWorkerSlotId, 'worker-slot-2');
+ assert.equal(report.summary.executionTopologyActiveLogicalLaneCount, 2);
+ assert.equal(report.summary.executionTopologySeededLogicalLaneCount, 4);
+ assert.equal(report.summary.executionTopologyRuntimeSurface, 'windows-native-teststand');
+ assert.equal(report.summary.executionTopologyProcessModelClass, 'parallel-process-model');
+ assert.equal(report.summary.executionTopologyWindowsOnly, true);
+ assert.equal(report.summary.executionTopologyRequestedSimultaneous, true);
+ assert.equal(report.summary.executionTopologyCellClass, 'kernel-coordinator');
+ assert.equal(report.summary.executionTopologySuiteClass, 'dual-plane-parity');
+ assert.equal(report.summary.executionTopologyOperatorAuthorizationRef, 'budget-auth://operator/session-2026-03-24');
+ assert.equal(report.summary.executionBundleStatus, 'committed');
+ assert.equal(report.summary.executionBundlePlaneBinding, 'dual-plane-parity');
+ assert.equal(report.summary.executionBundlePremiumSaganMode, true);
+ assert.equal(report.summary.executionBundleReciprocalLinkReady, true);
+ assert.equal(report.summary.executionBundleEffectiveBillableRateUsdPerHour, 375);
+ assert.equal(report.summary.viHistoryDistributorDependencyStatus, 'blocked');
+ assert.equal(
+ report.summary.viHistoryDistributorDependencyExternalBlocker,
+ 'workflow-signing-secret-missing'
+ );
+ assert.equal(report.summary.viHistoryDistributorDependencyPublicationState, 'unobserved');
+ assert.equal(report.summary.viHistoryDistributorDependencyPublishedBundleState, 'producer-native-incomplete');
+ assert.equal(report.summary.viHistoryDistributorDependencyPublishedBundleReleaseTag, 'v0.6.3-tools.14');
+ assert.equal(report.summary.viHistoryDistributorDependencyAuthoritativeConsumerPin, null);
+ assert.equal(report.summary.viHistoryDistributorDependencySigningAuthorityState, 'scope-missing');
+ assert.equal(report.summary.viHistoryDistributorDependencyReleaseConductorApplyState, 'disabled');
assert.equal(report.compare.queueHandoffPrUrl, 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/pull/1864');
assert.equal(report.compare.queueAuthoritySource, 'delivery-runtime');
+ assert.equal(report.compare.executionTopology.status, 'bundle-committed');
+ assert.equal(report.compare.executionTopology.executionPlane, 'hosted');
+ assert.equal(report.compare.executionTopology.providerId, 'hosted-github-workflow');
+ assert.equal(report.compare.executionTopology.workerSlotId, 'worker-slot-2');
+ assert.equal(report.compare.executionTopology.activeLogicalLaneCount, 2);
+ assert.equal(report.compare.executionTopology.seededLogicalLaneCount, 4);
+ assert.equal(report.compare.executionTopology.runtimeSurface, 'windows-native-teststand');
+ assert.equal(report.compare.executionTopology.processModelClass, 'parallel-process-model');
+ assert.equal(report.compare.executionTopology.windowsOnly, true);
+ assert.equal(report.compare.executionTopology.requestedSimultaneous, true);
+ assert.equal(report.compare.executionTopology.cellClass, 'kernel-coordinator');
+ assert.equal(report.compare.executionTopology.suiteClass, 'dual-plane-parity');
+ assert.equal(report.compare.executionTopology.operatorAuthorizationRef, 'budget-auth://operator/session-2026-03-24');
+ assert.equal(report.compare.executionTopology.logicalLaneActivation.catalogCount, 4);
+ assert.equal(report.compare.executionTopology.providerDispatch.dispatchStatus, 'completed');
+ assert.equal(report.compare.executionTopology.executionBundle.status, 'committed');
+ assert.equal(report.compare.executionTopology.executionBundle.cellClass, 'kernel-coordinator');
+ assert.equal(report.compare.executionTopology.executionBundle.suiteClass, 'dual-plane-parity');
+ assert.equal(
+ report.compare.executionTopology.executionBundle.operatorAuthorizationRef,
+ 'budget-auth://operator/session-2026-03-24'
+ );
+ assert.equal(report.compare.executionBundleStatus, 'committed');
+ assert.equal(report.compare.executionBundlePlaneBinding, 'dual-plane-parity');
+ assert.equal(report.compare.executionBundlePremiumSaganMode, true);
+ assert.equal(report.compare.executionBundleReciprocalLinkReady, true);
+ assert.equal(report.compare.executionBundleEffectiveBillableRateUsdPerHour, 375);
assert.equal(report.portfolio.repositoryCount, 4);
+ assert.deepEqual(report.portfolio.dependencies, [
+ {
+ id: 'vi-history-producer-native-distributor',
+ status: 'blocked',
+ ownerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ dependentRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ requiredCapability: 'vi-history',
+ source: 'compare-release-signing-readiness',
+ releaseSigningStatus: 'warn',
+ releasePublicationState: 'unobserved',
+ publishedBundleState: 'producer-native-incomplete',
+ publishedBundleReleaseTag: 'v0.6.3-tools.14',
+ publishedBundleAuthoritativeConsumerPin: null,
+ signingCapabilityState: 'missing',
+ signingAuthorityState: 'scope-missing',
+ releaseConductorApplyState: 'disabled',
+ externalBlocker: 'workflow-signing-secret-missing',
+ detail: 'awaiting-producer-native-bundle-publication'
+ }
+ ]);
assert.deepEqual(report.portfolio.repositories.find((entry) => entry.id === 'compare').triggeredWakeConditions, [
'compare-queue-not-empty',
'compare-continuity-not-safe-idle',
@@ -334,6 +504,15 @@ test('runAutonomousGovernorPortfolioSummary routes ownership to canonical templa
status: 'blocked',
futureAgentAction: 'reopen-template-monitoring-work',
wakeConditionCount: 1
+ },
+ releaseSigningReadiness: {
+ status: 'warn',
+ codePathState: 'ready',
+ signingCapabilityState: 'missing',
+ signingAuthorityState: 'scope-missing',
+ releaseConductorApplyState: 'disabled',
+ publicationState: 'unobserved',
+ externalBlocker: 'workflow-signing-secret-missing'
}
},
wake: {
@@ -360,7 +539,16 @@ test('runAutonomousGovernorPortfolioSummary routes ownership to canonical templa
continuityStatus: 'maintained',
wakeTerminalState: 'monitoring',
monitoringStatus: 'blocked',
- futureAgentAction: 'reopen-template-monitoring-work'
+ futureAgentAction: 'reopen-template-monitoring-work',
+ releaseSigningStatus: 'warn',
+ releaseSigningAuthorityState: 'scope-missing',
+ releaseConductorApplyState: 'disabled',
+ releaseSigningExternalBlocker: 'workflow-signing-secret-missing',
+ releasePublicationState: 'unobserved',
+ queueHandoffStatus: 'none',
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: 'none'
}
});
const monitoringMode = createMonitoringMode({
@@ -425,3 +613,194 @@ test('runAutonomousGovernorPortfolioSummary routes ownership to canonical templa
['template-canonical-open-issues']
);
});
+
+test('runAutonomousGovernorPortfolioSummary keeps next owner on compare while vi-history distributor dependency is blocked', async () => {
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'governor-portfolio-vi-history-blocked-'));
+ const compareSummary = createCompareGovernorSummary({
+ compare: {
+ queueState: { status: 'queue-empty', reason: 'queue-empty', openIssueCount: 0, ready: true },
+ continuity: {
+ status: 'maintained',
+ turnBoundary: 'safe-idle',
+ supervisionState: 'idle-monitoring',
+ operatorPromptRequiredToResume: false
+ },
+ monitoringMode: {
+ status: 'active',
+ futureAgentAction: 'future-agent-may-pivot',
+ wakeConditionCount: 0
+ },
+ releaseSigningReadiness: {
+ status: 'warn',
+ codePathState: 'ready',
+ signingCapabilityState: 'missing',
+ signingAuthorityState: 'scope-missing',
+ releaseConductorApplyState: 'disabled',
+ publicationState: 'unobserved',
+ externalBlocker: 'workflow-signing-secret-missing'
+ }
+ },
+ wake: {
+ terminalState: 'monitoring',
+ currentStage: 'monitoring',
+ classification: null,
+ decision: null,
+ monitoringStatus: 'active',
+ authoritativeTier: null,
+ blockedLowerTierEvidence: false,
+ replayMatched: false,
+ replayAuthorityCompatible: null,
+ issueNumber: null,
+ issueUrl: null,
+ recommendedOwnerRepository: null
+ },
+ summary: {
+ governorMode: 'monitoring-active',
+ currentOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextOwnerRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ nextAction: 'future-agent-may-pivot',
+ signalQuality: 'idle-monitoring',
+ queueState: 'queue-empty',
+ continuityStatus: 'maintained',
+ wakeTerminalState: 'monitoring',
+ monitoringStatus: 'active',
+ futureAgentAction: 'future-agent-may-pivot',
+ queueHandoffStatus: 'none',
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: 'none',
+ releaseSigningStatus: 'warn',
+ releaseSigningAuthorityState: 'scope-missing',
+ releaseConductorApplyState: 'disabled',
+ releaseSigningExternalBlocker: 'workflow-signing-secret-missing',
+ releasePublicationState: 'unobserved'
+ }
+ });
+ const monitoringMode = createMonitoringMode({
+ compare: {
+ queueState: { reportPath: 'tests/results/_agent/issue/no-standing-priority.json', ready: true, status: 'queue-empty', detail: 'queue-empty' },
+ continuity: { reportPath: 'tests/results/_agent/handoff/continuity-summary.json', ready: true, status: 'maintained', detail: 'safe-idle' },
+ pivotGate: { reportPath: 'tests/results/_agent/promotion/template-pivot-gate-report.json', ready: true, status: 'ready', detail: 'future-agent-may-pivot' },
+ readyForMonitoring: true
+ },
+ summary: {
+ status: 'active',
+ futureAgentAction: 'future-agent-may-pivot',
+ wakeConditionCount: 0,
+ triggeredWakeConditions: []
+ }
+ });
+
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'autonomous-governor-summary.json'), compareSummary);
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'monitoring-mode.json'), monitoringMode);
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'downstream-repo-graph-truth.json'), createRepoGraphTruth());
+
+ const { report } = await runAutonomousGovernorPortfolioSummary({ repoRoot: tmpDir });
+
+ assert.equal(report.summary.governorMode, 'monitoring-active');
+ assert.equal(report.summary.currentOwnerRepository, 'LabVIEW-Community-CI-CD/compare-vi-cli-action');
+ assert.equal(report.summary.nextOwnerRepository, 'LabVIEW-Community-CI-CD/compare-vi-cli-action');
+ assert.equal(report.summary.nextAction, 'complete-compare-vi-history-producer-release');
+ assert.equal(report.summary.ownerDecisionSource, 'compare-vi-history-distributor-dependency');
+ assert.equal(report.summary.viHistoryDistributorDependencyStatus, 'blocked');
+});
+
+test('runAutonomousGovernorPortfolioSummary flips next owner to template once vi-history distributor dependency is ready', async () => {
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'governor-portfolio-vi-history-ready-'));
+ const compareSummary = createCompareGovernorSummary({
+ compare: {
+ queueState: { status: 'queue-empty', reason: 'queue-empty', openIssueCount: 0, ready: true },
+ continuity: {
+ status: 'maintained',
+ turnBoundary: 'safe-idle',
+ supervisionState: 'idle-monitoring',
+ operatorPromptRequiredToResume: false
+ },
+ monitoringMode: {
+ status: 'active',
+ futureAgentAction: 'future-agent-may-pivot',
+ wakeConditionCount: 0
+ },
+ releaseSigningReadiness: {
+ status: 'pass',
+ codePathState: 'ready',
+ signingCapabilityState: 'configured',
+ signingAuthorityState: 'ready',
+ releaseConductorApplyState: 'enabled',
+ publicationState: 'producer-native-ready',
+ publishedBundleState: 'producer-native-ready',
+ publishedBundleReleaseTag: 'v0.6.4-rc.1-tools.1',
+ publishedBundleAuthoritativeConsumerPin: 'v0.6.4-rc.1-tools.1',
+ externalBlocker: null
+ }
+ },
+ wake: {
+ terminalState: 'monitoring',
+ currentStage: 'monitoring',
+ classification: null,
+ decision: null,
+ monitoringStatus: 'active',
+ authoritativeTier: null,
+ blockedLowerTierEvidence: false,
+ replayMatched: false,
+ replayAuthorityCompatible: null,
+ issueNumber: null,
+ issueUrl: null,
+ recommendedOwnerRepository: null
+ },
+ summary: {
+ governorMode: 'monitoring-active',
+ currentOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextOwnerRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ nextAction: 'future-agent-may-pivot',
+ signalQuality: 'idle-monitoring',
+ queueState: 'queue-empty',
+ continuityStatus: 'maintained',
+ wakeTerminalState: 'monitoring',
+ monitoringStatus: 'active',
+ futureAgentAction: 'future-agent-may-pivot',
+ queueHandoffStatus: 'none',
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: 'none',
+ releaseSigningStatus: 'pass',
+ releaseSigningAuthorityState: 'ready',
+ releaseConductorApplyState: 'enabled',
+ releaseSigningExternalBlocker: null,
+ releasePublicationState: 'producer-native-ready',
+ releasePublishedBundleState: 'producer-native-ready',
+ releasePublishedBundleReleaseTag: 'v0.6.4-rc.1-tools.1',
+ releasePublishedBundleAuthoritativeConsumerPin: 'v0.6.4-rc.1-tools.1'
+ }
+ });
+ const monitoringMode = createMonitoringMode({
+ compare: {
+ queueState: { reportPath: 'tests/results/_agent/issue/no-standing-priority.json', ready: true, status: 'queue-empty', detail: 'queue-empty' },
+ continuity: { reportPath: 'tests/results/_agent/handoff/continuity-summary.json', ready: true, status: 'maintained', detail: 'safe-idle' },
+ pivotGate: { reportPath: 'tests/results/_agent/promotion/template-pivot-gate-report.json', ready: true, status: 'ready', detail: 'future-agent-may-pivot' },
+ readyForMonitoring: true
+ },
+ summary: {
+ status: 'active',
+ futureAgentAction: 'future-agent-may-pivot',
+ wakeConditionCount: 0,
+ triggeredWakeConditions: []
+ }
+ });
+
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'autonomous-governor-summary.json'), compareSummary);
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'monitoring-mode.json'), monitoringMode);
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'downstream-repo-graph-truth.json'), createRepoGraphTruth());
+
+ const { report } = await runAutonomousGovernorPortfolioSummary({ repoRoot: tmpDir });
+
+ assert.equal(report.summary.governorMode, 'monitoring-active');
+ assert.equal(report.summary.currentOwnerRepository, 'LabVIEW-Community-CI-CD/compare-vi-cli-action');
+ assert.equal(report.summary.nextOwnerRepository, 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate');
+ assert.equal(report.summary.nextAction, 'future-agent-may-pivot');
+ assert.equal(report.summary.ownerDecisionSource, 'compare-monitoring-mode');
+ assert.equal(report.summary.viHistoryDistributorDependencyStatus, 'ready');
+ assert.equal(report.summary.viHistoryDistributorDependencyPublishedBundleState, 'producer-native-ready');
+ assert.equal(report.summary.viHistoryDistributorDependencyPublishedBundleReleaseTag, 'v0.6.4-rc.1-tools.1');
+ assert.equal(report.summary.viHistoryDistributorDependencyAuthoritativeConsumerPin, 'v0.6.4-rc.1-tools.1');
+});
diff --git a/tools/priority/__tests__/autonomous-governor-summary.test.mjs b/tools/priority/__tests__/autonomous-governor-summary.test.mjs
index e4b669425..0fc0c5a62 100644
--- a/tools/priority/__tests__/autonomous-governor-summary.test.mjs
+++ b/tools/priority/__tests__/autonomous-governor-summary.test.mjs
@@ -102,11 +102,94 @@ function createWakeInvestmentAccounting() {
};
}
+function createReleaseSigningReadiness(overrides = {}) {
+ return {
+ schema: 'priority/release-signing-readiness-report@v1',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ workflowContract: {
+ ready: true,
+ workflowPath: '.github/workflows/release-conductor.yml',
+ reasons: []
+ },
+ secretInventory: {
+ status: 'missing',
+ requiredSecretPresent: false,
+ optionalPublicKeyPresent: false,
+ listedSecretCount: 3,
+ listedSecretNames: ['AUTO_APPROVE_TOKEN', 'GH_POLICY_TOKEN', 'GH_TOKEN'],
+ source: 'github-actions-secrets-api',
+ error: null
+ },
+ releaseConductorApply: {
+ status: 'disabled',
+ variablePresent: false,
+ enabled: false,
+ configuredValue: null,
+ listedVariableCount: 0,
+ listedVariableNames: [],
+ source: 'github-actions-variables-api',
+ error: null
+ },
+ signingAuthority: {
+ status: 'scope-missing',
+ requiredScope: 'admin:ssh_signing_key',
+ scopeAvailable: false,
+ listedKeyCount: null,
+ source: 'github-user-ssh-signing-keys-api',
+ error: 'This API operation needs the \"admin:ssh_signing_key\" scope.'
+ },
+ publication: {
+ status: 'tag-created-not-pushed',
+ tagCreated: true,
+ tagPushed: false,
+ targetTag: 'v0.6.4-rc.1'
+ },
+ summary: {
+ status: 'warn',
+ codePathState: 'ready',
+ signingCapabilityState: 'missing',
+ signingAuthorityState: 'scope-missing',
+ releaseConductorApplyState: 'disabled',
+ publicationState: 'tag-created-not-pushed',
+ publishedBundleState: 'producer-native-incomplete',
+ publishedBundleReleaseTag: 'v0.6.3-tools.14',
+ publishedBundleAuthoritativeConsumerPin: null,
+ externalBlocker: 'workflow-signing-secret-missing',
+ blockerCount: 3
+ },
+ blockers: [
+ {
+ code: 'workflow-signing-secret-missing',
+ message: 'RELEASE_TAG_SIGNING_PRIVATE_KEY is not configured for the repository Actions secrets surface.'
+ },
+ {
+ code: 'release-conductor-apply-disabled',
+ message: 'RELEASE_CONDUCTOR_ENABLED is not set to 1 for the repository Actions variable surface.'
+ },
+ {
+ code: 'workflow-signing-admin-scope-missing',
+ message: 'admin:ssh_signing_key is not available to the current automation identity, so SSH signing-key authority cannot be verified or managed.'
+ }
+ ],
+ ...overrides
+ };
+}
+
function createDeliveryRuntimeState(overrides = {}) {
return {
schema: 'priority/delivery-agent-runtime-state@v1',
status: 'waiting-ci',
laneLifecycle: 'waiting-ci',
+ logicalLaneActivation: {
+ seededLaneCount: 4,
+ activeLaneCount: 2,
+ catalog: [
+ { id: 'logical-lane-01', activationState: 'active' },
+ { id: 'logical-lane-02', activationState: 'active' },
+ { id: 'logical-lane-03', activationState: 'seeded' },
+ { id: 'logical-lane-04', activationState: 'seeded' }
+ ]
+ },
queueAuthorityRefresh: {
attempted: false,
status: null,
@@ -131,7 +214,65 @@ function createDeliveryRuntimeState(overrides = {}) {
outcome: 'waiting-ci',
blockerClass: 'none',
nextWakeCondition: 'checks-green',
- reason: 'Waiting for hosted checks to finish before merge queue advances.'
+ reason: 'Waiting for hosted checks to finish before merge queue advances.',
+ providerDispatch: {
+ providerId: 'hosted-github-workflow',
+ providerKind: 'hosted-github-workflow',
+ executionPlane: 'hosted',
+ assignmentMode: 'async-validation',
+ dispatchSurface: 'github-actions',
+ completionMode: 'async',
+ workerSlotId: 'worker-slot-2',
+ dispatchStatus: 'completed',
+ completionStatus: 'waiting',
+ failureClass: null
+ },
+ executionTopology: {
+ status: 'bundle-committed',
+ executionPlane: 'hosted',
+ providerId: 'hosted-github-workflow',
+ workerSlotId: 'worker-slot-2',
+ activeLogicalLaneCount: 2,
+ seededLogicalLaneCount: 4,
+ catalogCount: 4,
+ runtimeSurface: 'windows-native-teststand',
+ processModelClass: 'parallel-process-model',
+ windowsOnly: true,
+ requestedSimultaneous: true,
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ premiumSaganMode: true,
+ reciprocalLinkReady: true,
+ executionCellLeaseId: 'exec-lease-123',
+ dockerLaneLeaseId: 'docker-lease-456',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: 'ts-harness-01',
+ cellId: 'cell-sagan-kernel',
+ laneId: 'docker-lane-01',
+ planeBinding: 'dual-plane-parity'
+ },
+ concurrentLaneStatus: {
+ executionBundle: {
+ status: 'committed',
+ planeBinding: 'dual-plane-parity',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ premiumSaganMode: true,
+ reciprocalLinkReady: true,
+ effectiveBillableRateUsdPerHour: 375,
+ executionCellLeaseId: 'exec-lease-123',
+ dockerLaneLeaseId: 'docker-lease-456',
+ harnessInstanceId: 'ts-harness-01',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ cellId: 'cell-sagan-kernel',
+ laneId: 'docker-lane-01',
+ isolatedLaneGroupId:
+ 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+ }
+ }
},
...overrides
};
@@ -253,6 +394,9 @@ test('runAutonomousGovernorSummary reports compare governance work when the late
assert.equal(report.summary.nextAction, 'continue-compare-governance-work');
assert.equal(report.summary.signalQuality, 'validated-governance-work');
assert.equal(report.funding.invoiceTurnId, 'invoice-turn-2026-03-HQ1VJLMV-0027');
+ assert.equal(report.compare.releaseSigningReadiness.status, 'missing');
+ assert.equal(report.summary.releaseSigningStatus, 'missing');
+ assert.equal(report.summary.releaseSigningExternalBlocker, null);
});
test('runAutonomousGovernorSummary reports monitoring-active when no wake lifecycle exists', async () => {
@@ -270,10 +414,44 @@ test('runAutonomousGovernorSummary reports monitoring-active when no wake lifecy
assert.equal(report.summary.nextOwnerRepository, 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate');
assert.equal(report.wake.terminalState, null);
assert.equal(report.compare.deliveryRuntime.status, 'none');
+ assert.equal(report.compare.releaseSigningReadiness.status, 'missing');
assert.equal(report.compare.deliveryRuntime.queueAuthorityRefresh.attempted, false);
assert.equal(report.compare.deliveryRuntime.queueAuthorityRefresh.status, null);
assert.equal(report.summary.queueHandoffStatus, 'none');
assert.equal(report.summary.queueAuthoritySource, 'none');
+ assert.equal(report.summary.releaseSigningStatus, 'missing');
+});
+
+test('runAutonomousGovernorSummary carries explicit release signing blocker state into the governor summary', async () => {
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'governor-summary-release-signing-'));
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'issue', 'no-standing-priority.json'), createQueueEmpty());
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'continuity-summary.json'), createContinuitySummary());
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'monitoring-mode.json'), createMonitoringMode());
+ writeJson(
+ path.join(tmpDir, 'tests', 'results', '_agent', 'release', 'release-signing-readiness.json'),
+ createReleaseSigningReadiness()
+ );
+
+ const { report } = await runAutonomousGovernorSummary({ repoRoot: tmpDir });
+
+ assert.equal(report.compare.releaseSigningReadiness.status, 'warn');
+ assert.equal(report.compare.releaseSigningReadiness.codePathState, 'ready');
+ assert.equal(report.compare.releaseSigningReadiness.signingCapabilityState, 'missing');
+ assert.equal(report.compare.releaseSigningReadiness.signingAuthorityState, 'scope-missing');
+ assert.equal(report.compare.releaseSigningReadiness.releaseConductorApplyState, 'disabled');
+ assert.equal(report.compare.releaseSigningReadiness.publicationState, 'tag-created-not-pushed');
+ assert.equal(report.compare.releaseSigningReadiness.publishedBundleState, 'producer-native-incomplete');
+ assert.equal(report.compare.releaseSigningReadiness.publishedBundleReleaseTag, 'v0.6.3-tools.14');
+ assert.equal(report.compare.releaseSigningReadiness.publishedBundleAuthoritativeConsumerPin, null);
+ assert.equal(report.compare.releaseSigningReadiness.externalBlocker, 'workflow-signing-secret-missing');
+ assert.equal(report.summary.releaseSigningStatus, 'warn');
+ assert.equal(report.summary.releaseSigningAuthorityState, 'scope-missing');
+ assert.equal(report.summary.releaseConductorApplyState, 'disabled');
+ assert.equal(report.summary.releaseSigningExternalBlocker, 'workflow-signing-secret-missing');
+ assert.equal(report.summary.releasePublicationState, 'tag-created-not-pushed');
+ assert.equal(report.summary.releasePublishedBundleState, 'producer-native-incomplete');
+ assert.equal(report.summary.releasePublishedBundleReleaseTag, 'v0.6.3-tools.14');
+ assert.equal(report.summary.releasePublishedBundleAuthoritativeConsumerPin, null);
});
test('runAutonomousGovernorSummary carries queue-owned delivery runtime state into the governor summary', async () => {
@@ -297,14 +475,177 @@ test('runAutonomousGovernorSummary carries queue-owned delivery runtime state in
assert.equal(report.compare.deliveryRuntime.laneLifecycle, 'waiting-ci');
assert.equal(report.compare.deliveryRuntime.nextWakeCondition, 'checks-green');
assert.equal(report.compare.deliveryRuntime.prUrl, 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/pull/1864');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.status, 'bundle-committed');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.executionPlane, 'hosted');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.providerId, 'hosted-github-workflow');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.workerSlotId, 'worker-slot-2');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.activeLogicalLaneCount, 2);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.seededLogicalLaneCount, 4);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.catalogCount, 4);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.runtimeSurface, 'windows-native-teststand');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.processModelClass, 'parallel-process-model');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.windowsOnly, true);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.requestedSimultaneous, true);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.cellClass, 'kernel-coordinator');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.suiteClass, 'dual-plane-parity');
+ assert.equal(
+ report.compare.deliveryRuntime.executionTopology.operatorAuthorizationRef,
+ 'budget-auth://operator/session-2026-03-24'
+ );
+ assert.equal(report.compare.deliveryRuntime.executionTopology.logicalLaneActivation.activeLaneCount, 2);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.providerDispatch.dispatchStatus, 'completed');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.executionBundle.status, 'committed');
+ assert.equal(report.compare.deliveryRuntime.executionBundle.status, 'committed');
+ assert.equal(report.compare.deliveryRuntime.executionBundle.planeBinding, 'dual-plane-parity');
+ assert.equal(report.compare.deliveryRuntime.executionBundle.cellClass, 'kernel-coordinator');
+ assert.equal(report.compare.deliveryRuntime.executionBundle.suiteClass, 'dual-plane-parity');
+ assert.equal(report.compare.deliveryRuntime.executionBundle.premiumSaganMode, true);
+ assert.equal(report.compare.deliveryRuntime.executionBundle.reciprocalLinkReady, true);
+ assert.equal(report.compare.deliveryRuntime.executionBundle.effectiveBillableRateUsdPerHour, 375);
+ assert.equal(
+ report.compare.deliveryRuntime.executionBundle.operatorAuthorizationRef,
+ 'budget-auth://operator/session-2026-03-24'
+ );
assert.equal(report.compare.deliveryRuntime.queueAuthorityRefresh.attempted, false);
assert.equal(report.compare.deliveryRuntime.queueAuthorityRefresh.summaryPath, null);
+ assert.equal(report.summary.executionTopologyStatus, 'bundle-committed');
+ assert.equal(report.summary.executionTopologyExecutionPlane, 'hosted');
+ assert.equal(report.summary.executionTopologyProviderId, 'hosted-github-workflow');
+ assert.equal(report.summary.executionTopologyWorkerSlotId, 'worker-slot-2');
+ assert.equal(report.summary.executionTopologyActiveLogicalLaneCount, 2);
+ assert.equal(report.summary.executionTopologySeededLogicalLaneCount, 4);
+ assert.equal(report.summary.executionTopologyRuntimeSurface, 'windows-native-teststand');
+ assert.equal(report.summary.executionTopologyProcessModelClass, 'parallel-process-model');
+ assert.equal(report.summary.executionTopologyWindowsOnly, true);
+ assert.equal(report.summary.executionTopologyRequestedSimultaneous, true);
+ assert.equal(report.summary.executionTopologyCellClass, 'kernel-coordinator');
+ assert.equal(report.summary.executionTopologySuiteClass, 'dual-plane-parity');
+ assert.equal(report.summary.executionTopologyOperatorAuthorizationRef, 'budget-auth://operator/session-2026-03-24');
+ assert.equal(report.summary.executionBundleStatus, 'committed');
+ assert.equal(report.summary.executionBundlePlaneBinding, 'dual-plane-parity');
+ assert.equal(report.summary.executionBundlePremiumSaganMode, true);
+ assert.equal(report.summary.executionBundleReciprocalLinkReady, true);
+ assert.equal(report.summary.executionBundleEffectiveBillableRateUsdPerHour, 375);
assert.equal(report.summary.queueHandoffStatus, 'checks-pending');
assert.equal(report.summary.queueHandoffNextWakeCondition, 'checks-green');
assert.equal(report.summary.queueHandoffPrUrl, 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/pull/1864');
assert.equal(report.summary.queueAuthoritySource, 'delivery-runtime');
});
+test('runAutonomousGovernorSummary prefers concentrated delivery execution topology over raw bundle-derived conflicts', async () => {
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'governor-summary-execution-topology-preference-'));
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'issue', 'no-standing-priority.json'), createQueueEmpty());
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'continuity-summary.json'), createContinuitySummary());
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'monitoring-mode.json'), createMonitoringMode());
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'issue', 'wake-lifecycle.json'), createWakeLifecycle());
+ writeJson(
+ path.join(tmpDir, 'tests', 'results', '_agent', 'capital', 'wake-investment-accounting.json'),
+ createWakeInvestmentAccounting()
+ );
+ writeJson(
+ path.join(tmpDir, 'tests', 'results', '_agent', 'runtime', 'delivery-agent-state.json'),
+ createDeliveryRuntimeState({
+ activeLane: {
+ issue: 1863,
+ prUrl: 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/pull/1864',
+ laneLifecycle: 'waiting-ci',
+ actionType: 'merge-pr',
+ outcome: 'waiting-ci',
+ blockerClass: 'none',
+ nextWakeCondition: 'checks-green',
+ reason: 'Waiting for hosted checks to finish before merge queue advances.',
+ providerDispatch: {
+ providerId: 'hosted-github-workflow',
+ providerKind: 'hosted-github-workflow',
+ executionPlane: 'hosted',
+ assignmentMode: 'async-validation',
+ dispatchSurface: 'github-actions',
+ completionMode: 'async',
+ workerSlotId: 'worker-slot-2',
+ dispatchStatus: 'completed',
+ completionStatus: 'waiting',
+ failureClass: null
+ },
+ executionTopology: {
+ status: 'provider-waiting',
+ executionPlane: 'local',
+ providerId: 'local-codex',
+ workerSlotId: 'worker-slot-9',
+ activeLogicalLaneCount: 1,
+ seededLogicalLaneCount: 2,
+ catalogCount: 2,
+ runtimeSurface: 'windows-native-teststand',
+ processModelClass: 'sequential-process-model',
+ windowsOnly: true,
+ requestedSimultaneous: false,
+ cellClass: 'worker-cell',
+ suiteClass: 'single-plane-review',
+ operatorAuthorizationRef: 'budget-auth://operator/session-override',
+ premiumSaganMode: false,
+ reciprocalLinkReady: false,
+ executionCellLeaseId: 'exec-lease-override',
+ dockerLaneLeaseId: 'docker-lease-override',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: 'ts-harness-override',
+ cellId: 'cell-worker-09',
+ laneId: 'docker-lane-09',
+ planeBinding: 'native-labview-2026-64'
+ },
+ concurrentLaneStatus: {
+ executionBundle: {
+ status: 'committed',
+ planeBinding: 'dual-plane-parity',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ premiumSaganMode: true,
+ reciprocalLinkReady: true,
+ effectiveBillableRateUsdPerHour: 375,
+ executionCellLeaseId: 'exec-lease-123',
+ dockerLaneLeaseId: 'docker-lease-456',
+ harnessInstanceId: 'ts-harness-01',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ cellId: 'cell-sagan-kernel',
+ laneId: 'docker-lane-01'
+ }
+ }
+ }
+ })
+ );
+
+ const { report } = await runAutonomousGovernorSummary({ repoRoot: tmpDir });
+
+ assert.equal(report.compare.deliveryRuntime.executionTopology.status, 'provider-waiting');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.executionPlane, 'local');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.providerId, 'local-codex');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.workerSlotId, 'worker-slot-9');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.activeLogicalLaneCount, 1);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.seededLogicalLaneCount, 2);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.catalogCount, 2);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.processModelClass, 'sequential-process-model');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.requestedSimultaneous, false);
+ assert.equal(report.compare.deliveryRuntime.executionTopology.cellClass, 'worker-cell');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.suiteClass, 'single-plane-review');
+ assert.equal(
+ report.compare.deliveryRuntime.executionTopology.operatorAuthorizationRef,
+ 'budget-auth://operator/session-override'
+ );
+ assert.equal(report.compare.deliveryRuntime.executionTopology.providerDispatch.dispatchStatus, 'completed');
+ assert.equal(report.compare.deliveryRuntime.executionTopology.executionBundle.status, 'committed');
+ assert.equal(report.compare.deliveryRuntime.executionBundle.status, 'committed');
+ assert.equal(report.summary.executionTopologyStatus, 'provider-waiting');
+ assert.equal(report.summary.executionTopologyExecutionPlane, 'local');
+ assert.equal(report.summary.executionTopologyProviderId, 'local-codex');
+ assert.equal(report.summary.executionTopologyWorkerSlotId, 'worker-slot-9');
+ assert.equal(report.summary.executionTopologyActiveLogicalLaneCount, 1);
+ assert.equal(report.summary.executionTopologySeededLogicalLaneCount, 2);
+ assert.equal(report.summary.executionTopologyProcessModelClass, 'sequential-process-model');
+ assert.equal(report.summary.executionTopologyRequestedSimultaneous, false);
+ assert.equal(report.summary.executionTopologyCellClass, 'worker-cell');
+ assert.equal(report.summary.executionTopologySuiteClass, 'single-plane-review');
+ assert.equal(report.summary.executionTopologyOperatorAuthorizationRef, 'budget-auth://operator/session-override');
+});
+
test('runAutonomousGovernorSummary exposes queue authority refresh telemetry from delivery runtime state', async () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'governor-summary-runtime-refresh-'));
writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'issue', 'no-standing-priority.json'), createQueueEmpty());
diff --git a/tools/priority/__tests__/concurrent-lane-status-schema.test.mjs b/tools/priority/__tests__/concurrent-lane-status-schema.test.mjs
index 733ebcca8..83c19c95d 100644
--- a/tools/priority/__tests__/concurrent-lane-status-schema.test.mjs
+++ b/tools/priority/__tests__/concurrent-lane-status-schema.test.mjs
@@ -24,6 +24,7 @@ test('concurrent lane status schema validates the generated receipt', async () =
const schema = JSON.parse(await readFile(schemaPath, 'utf8'));
const tempDir = mkdtempSync(path.join(os.tmpdir(), 'concurrent-lane-status-schema-'));
const applyReceiptPath = path.join(tempDir, 'apply.json');
+ const executionBundleReceiptPath = path.join(tempDir, 'execution-cell-bundle.json');
writeJson(applyReceiptPath, {
schema: 'priority/concurrent-lane-apply-receipt@v1',
generatedAt: '2026-03-21T00:00:00.000Z',
@@ -87,9 +88,37 @@ test('concurrent lane status schema validates the generated receipt', async () =
shadowLaneIds: []
}
});
+ writeJson(executionBundleReceiptPath, {
+ schema: 'priority/execution-cell-bundle-report@v1',
+ status: 'granted',
+ cellId: 'cell-sagan-kernel',
+ laneId: 'docker-lane-01',
+ summary: {
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ executionCellLeaseId: 'exec-lease-123',
+ dockerLaneLeaseId: 'docker-lease-456',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: 'ts-harness-01',
+ planeBinding: 'dual-plane-parity',
+ premiumSaganMode: true,
+ reciprocalLinkReady: false,
+ effectiveBillableRateUsdPerHour: 375,
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+ }
+ });
const { receipt } = await observeConcurrentLaneStatus(
- parseArgs(['node', 'concurrent-lane-status.mjs', '--apply-receipt', applyReceiptPath]),
+ parseArgs([
+ 'node',
+ 'concurrent-lane-status.mjs',
+ '--apply-receipt',
+ applyReceiptPath,
+ '--execution-bundle-receipt',
+ executionBundleReceiptPath
+ ]),
{
ensureGhCliFn: () => {},
getRepoRootFn: () => tempDir,
@@ -107,6 +136,8 @@ test('concurrent lane status schema validates the generated receipt', async () =
addFormats(ajv);
const validate = ajv.compile(schema);
assert.equal(validate(receipt), true, JSON.stringify(validate.errors, null, 2));
+ assert.equal(receipt.executionBundle.status, 'granted');
+ assert.equal(receipt.summary.executionBundlePremiumSaganMode, true);
assert.equal(receipt.plan.schema, 'priority/concurrent-lane-plan@v1');
assert.equal(receipt.plan.source, 'file');
assert.equal(receipt.plan.recommendedBundleId, 'hosted-only-proof');
diff --git a/tools/priority/__tests__/concurrent-lane-status.test.mjs b/tools/priority/__tests__/concurrent-lane-status.test.mjs
index 126ab8a4c..e1b9d428f 100644
--- a/tools/priority/__tests__/concurrent-lane-status.test.mjs
+++ b/tools/priority/__tests__/concurrent-lane-status.test.mjs
@@ -149,13 +149,51 @@ function createApplyReceipt(overrides = {}) {
test('observeConcurrentLaneStatus projects active hosted lanes and queued PR merge state', async () => {
const tempDir = createTempDir();
const applyReceiptPath = path.join(tempDir, 'tests', 'results', '_agent', 'runtime', 'concurrent-lane-apply-receipt.json');
+ const executionBundleReceiptPath = path.join(
+ tempDir,
+ 'tests',
+ 'results',
+ '_agent',
+ 'runtime',
+ 'execution-cell-bundle.json'
+ );
const outputPath = path.join(tempDir, 'tests', 'results', '_agent', 'runtime', 'concurrent-lane-status-receipt.json');
writeJson(applyReceiptPath, createApplyReceipt());
+ writeJson(executionBundleReceiptPath, {
+ schema: 'priority/execution-cell-bundle-report@v1',
+ status: 'committed',
+ cellId: 'cell-sagan-kernel',
+ laneId: 'docker-lane-01',
+ summary: {
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ executionCellLeaseId: 'exec-lease-123',
+ dockerLaneLeaseId: 'docker-lease-456',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: 'ts-harness-01',
+ planeBinding: 'dual-plane-parity',
+ premiumSaganMode: true,
+ reciprocalLinkReady: true,
+ effectiveBillableRateUsdPerHour: 375,
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+ }
+ });
const ghJsonCalls = [];
const ghGraphqlCalls = [];
const { receipt, outputPath: writtenPath } = await observeConcurrentLaneStatus(
- parseArgs(['node', 'concurrent-lane-status.mjs', '--apply-receipt', applyReceiptPath, '--output', outputPath]),
+ parseArgs([
+ 'node',
+ 'concurrent-lane-status.mjs',
+ '--apply-receipt',
+ applyReceiptPath,
+ '--execution-bundle-receipt',
+ executionBundleReceiptPath,
+ '--output',
+ outputPath
+ ]),
{
ensureGhCliFn: () => {},
getRepoRootFn: () => tempDir,
@@ -227,9 +265,19 @@ test('observeConcurrentLaneStatus projects active hosted lanes and queued PR mer
assert.equal(receipt.plan.selectedBundleId, 'hosted-plus-manual-linux-docker');
assert.equal(receipt.hostedRun.observationStatus, 'active');
assert.equal(receipt.pullRequest.observationStatus, 'queued');
+ assert.equal(receipt.executionBundle.status, 'committed');
+ assert.equal(receipt.executionBundle.cellClass, 'kernel-coordinator');
+ assert.equal(receipt.executionBundle.suiteClass, 'dual-plane-parity');
+ assert.equal(receipt.executionBundle.harnessKind, 'teststand-compare-harness');
+ assert.equal(receipt.executionBundle.reciprocalLinkReady, true);
+ assert.equal(receipt.executionBundle.premiumSaganMode, true);
+ assert.equal(receipt.executionBundle.operatorAuthorizationRef, 'budget-auth://operator/session-2026-03-24');
assert.equal(receipt.summary.orchestratorDisposition, 'wait-hosted-run');
assert.equal(receipt.summary.activeLaneCount, 2);
assert.equal(receipt.summary.deferredLaneCount, 1);
+ assert.equal(receipt.summary.executionBundleStatus, 'committed');
+ assert.equal(receipt.summary.executionBundleReciprocalLinkReady, true);
+ assert.equal(receipt.summary.executionBundlePremiumSaganMode, true);
assert.equal(receipt.laneStatuses[0].idleClassification, null);
assert.equal(receipt.laneStatuses[2].idleClassification?.state, 'waiting-merge');
assert.equal(receipt.summary.idleClassificationCoverage.managedLaneCount, 3);
@@ -353,6 +401,7 @@ test('observeConcurrentLaneStatus settles completed hosted runs and keeps deferr
);
assert.equal(receipt.status, 'settled');
+ assert.equal(receipt.executionBundle, null);
assert.equal(receipt.plan.path, 'tests/results/_agent/runtime/concurrent-lane-plan.json');
assert.equal(receipt.plan.schema, 'priority/concurrent-lane-plan@v1');
assert.equal(receipt.plan.source, 'file');
@@ -398,6 +447,7 @@ test('observeConcurrentLaneStatus fails closed when hosted workflow observation
);
assert.equal(receipt.status, 'failed');
+ assert.equal(receipt.executionBundle, null);
assert.equal(receipt.hostedRun.observationStatus, 'failed');
assert.equal(receipt.summary.orchestratorDisposition, 'hold-investigate');
assert.match(receipt.observationErrors[0] ?? '', /rate limited/i);
diff --git a/tools/priority/__tests__/delivery-agent-schema.test.mjs b/tools/priority/__tests__/delivery-agent-schema.test.mjs
index 5e7df30f7..64bd4d633 100644
--- a/tools/priority/__tests__/delivery-agent-schema.test.mjs
+++ b/tools/priority/__tests__/delivery-agent-schema.test.mjs
@@ -792,6 +792,44 @@ test('delivery-agent runtime state schema validates persisted runtime state', as
completionMode: 'async',
selectedSlotId: 'worker-slot-2',
requiresLocalCheckout: false
+ },
+ concurrentLaneStatus: {
+ receiptPath: 'tests/results/_agent/runtime/concurrent-lane-status-receipt.json',
+ status: 'settled',
+ selectedBundleId: 'hosted-plus-manual-linux-docker',
+ executionBundle: {
+ status: 'committed',
+ cellId: 'cell-sagan-kernel',
+ laneId: 'docker-lane-01',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ executionCellLeaseId: 'exec-lease-123',
+ dockerLaneLeaseId: 'docker-lease-456',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: 'ts-harness-01',
+ planeBinding: 'dual-plane-parity',
+ premiumSaganMode: true,
+ reciprocalLinkReady: true,
+ effectiveBillableRateUsdPerHour: 375,
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ isolatedLaneGroupId:
+ 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+ },
+ summary: {
+ laneCount: 3,
+ activeLaneCount: 2,
+ completedLaneCount: 0,
+ failedLaneCount: 0,
+ deferredLaneCount: 1,
+ manualLaneCount: 1,
+ shadowLaneCount: 0,
+ executionBundleStatus: 'committed',
+ executionBundleReciprocalLinkReady: true,
+ executionBundlePremiumSaganMode: true,
+ pullRequestStatus: 'queued',
+ orchestratorDisposition: 'wait-hosted-run'
+ }
}
}
}
@@ -955,6 +993,38 @@ test('delivery-agent runtime state schema validates persisted runtime state', as
assert.equal(state.activeLane.workerProviderSelection.selectedProviderId, 'hosted-github-workflow');
assert.equal(state.activeLane.providerDispatch.providerId, 'hosted-github-workflow');
assert.equal(state.activeLane.providerDispatch.workerSlotId, 'worker-slot-2');
+ assert.equal(state.activeLane.executionTopology.status, 'bundle-committed');
+ assert.equal(state.activeLane.executionTopology.executionPlane, 'hosted');
+ assert.equal(state.activeLane.executionTopology.providerId, 'hosted-github-workflow');
+ assert.equal(state.activeLane.executionTopology.workerSlotId, 'worker-slot-2');
+ assert.equal(state.activeLane.executionTopology.cellId, 'cell-sagan-kernel');
+ assert.equal(state.activeLane.executionTopology.laneId, 'docker-lane-01');
+ assert.equal(state.activeLane.executionTopology.cellClass, 'kernel-coordinator');
+ assert.equal(state.activeLane.executionTopology.suiteClass, 'dual-plane-parity');
+ assert.equal(state.activeLane.executionTopology.planeBinding, 'dual-plane-parity');
+ assert.equal(state.activeLane.executionTopology.harnessKind, 'teststand-compare-harness');
+ assert.equal(state.activeLane.executionTopology.harnessInstanceId, 'ts-harness-01');
+ assert.equal(state.activeLane.executionTopology.executionCellLeaseId, 'exec-lease-123');
+ assert.equal(state.activeLane.executionTopology.dockerLaneLeaseId, 'docker-lease-456');
+ assert.equal(state.activeLane.executionTopology.premiumSaganMode, true);
+ assert.equal(state.activeLane.executionTopology.reciprocalLinkReady, true);
+ assert.equal(state.activeLane.executionTopology.operatorAuthorizationRef, 'budget-auth://operator/session-2026-03-24');
+ assert.equal(state.activeLane.executionTopology.runtimeSurface, 'windows-native-teststand');
+ assert.equal(state.activeLane.executionTopology.processModelClass, 'parallel-process-model');
+ assert.equal(state.activeLane.executionTopology.windowsOnly, true);
+ assert.equal(state.activeLane.executionTopology.requestedSimultaneous, true);
+ assert.equal(state.activeLane.concurrentLaneStatus.executionBundle.status, 'committed');
+ assert.equal(state.activeLane.concurrentLaneStatus.executionBundle.planeBinding, 'dual-plane-parity');
+ assert.equal(state.activeLane.concurrentLaneStatus.executionBundle.cellClass, 'kernel-coordinator');
+ assert.equal(state.activeLane.concurrentLaneStatus.executionBundle.suiteClass, 'dual-plane-parity');
+ assert.equal(state.activeLane.concurrentLaneStatus.executionBundle.harnessKind, 'teststand-compare-harness');
+ assert.equal(state.activeLane.concurrentLaneStatus.executionBundle.premiumSaganMode, true);
+ assert.equal(state.activeLane.concurrentLaneStatus.executionBundle.reciprocalLinkReady, true);
+ assert.equal(state.activeLane.concurrentLaneStatus.executionBundle.effectiveBillableRateUsdPerHour, 375);
+ assert.equal(
+ state.activeLane.concurrentLaneStatus.executionBundle.operatorAuthorizationRef,
+ 'budget-auth://operator/session-2026-03-24'
+ );
assert.equal(state.activeLane.planeTransition.from, 'origin');
assert.equal(state.activeLane.planeTransition.to, 'upstream');
assert.equal(state.artifacts.planeTransition.action, 'promote');
diff --git a/tools/priority/__tests__/docker-lane-handshake-schema.test.mjs b/tools/priority/__tests__/docker-lane-handshake-schema.test.mjs
new file mode 100644
index 000000000..8356ac13f
--- /dev/null
+++ b/tools/priority/__tests__/docker-lane-handshake-schema.test.mjs
@@ -0,0 +1,102 @@
+#!/usr/bin/env node
+
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { readFile } from 'node:fs/promises';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import Ajv2020 from 'ajv/dist/2020.js';
+import addFormats from 'ajv-formats';
+
+const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
+
+test('docker lane handshake report schema validates a premium Sagan dual-lane grant receipt', async () => {
+ const stateSchemaPath = path.join(repoRoot, 'docs', 'schemas', 'docker-lane-handshake-v1.schema.json');
+ const reportSchemaPath = path.join(repoRoot, 'docs', 'schemas', 'docker-lane-handshake-report-v1.schema.json');
+ const stateSchema = JSON.parse(await readFile(stateSchemaPath, 'utf8'));
+ const reportSchema = JSON.parse(await readFile(reportSchemaPath, 'utf8'));
+
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
+ addFormats(ajv);
+ ajv.addSchema(stateSchema, stateSchema.$id);
+ const validate = ajv.compile(reportSchema);
+
+ const report = {
+ schema: 'priority/docker-lane-handshake-report@v1',
+ generatedAt: '2026-03-23T23:55:00.000Z',
+ action: 'grant',
+ status: 'granted',
+ laneId: 'docker-agent-sagan-dual-01',
+ handshakePath: 'C:/repo/.git/docker-lane-handshakes/docker-agent-sagan-dual-01.json',
+ policy: {
+ operatorId: 'sergio',
+ currency: 'USD',
+ laborRateUsdPerHour: 250,
+ premiumSaganRateMultiplier: 1.5
+ },
+ handshake: {
+ schema: 'priority/docker-lane-handshake@v1',
+ generatedAt: '2026-03-23T23:55:00.000Z',
+ laneId: 'docker-agent-sagan-dual-01',
+ resourceKind: 'docker-lane',
+ state: 'granted',
+ sequence: 2,
+ heartbeatAt: '2026-03-23T23:55:00.000Z',
+ host: {
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ platform: 'windows',
+ computerName: 'canonical-builder',
+ canonical: {
+ version: '10.0.26200',
+ buildNumber: '26200',
+ ubr: 8037
+ }
+ },
+ request: {
+ requestId: 'request-123',
+ requestedAt: '2026-03-23T23:54:00.000Z',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ capabilities: ['docker-lane', 'native-labview-2026-32'],
+ premiumDualLaneRequested: true,
+ operatorId: 'sergio',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-23'
+ },
+ grant: {
+ grantedAt: '2026-03-23T23:55:00.000Z',
+ grantor: 'sagan-governor',
+ leaseId: 'lease-123',
+ ttlSeconds: 1800,
+ grantedCapabilities: ['docker-lane', 'native-labview-2026-32'],
+ billableRateMultiplier: 1.5,
+ billableRateUsdPerHour: 375,
+ premiumSaganMode: true,
+ policyDecision: 'sagan-premium-dual-lane',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-23'
+ },
+ commit: null,
+ release: null
+ },
+ summary: {
+ handshakeState: 'granted',
+ leaseId: 'lease-123',
+ holder: 'sagan',
+ premiumSaganMode: true,
+ billableRateMultiplier: 1.5,
+ billableRateUsdPerHour: 375,
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-23',
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ linkedExecutionCellId: null,
+ linkedExecutionCellLeaseId: null,
+ isStale: false,
+ ageSeconds: 0,
+ ttlSeconds: 1800,
+ denialReasons: [],
+ observations: []
+ }
+ };
+
+ assert.equal(validate(report), true, JSON.stringify(validate.errors, null, 2));
+});
diff --git a/tools/priority/__tests__/docker-lane-handshake.test.mjs b/tools/priority/__tests__/docker-lane-handshake.test.mjs
new file mode 100644
index 000000000..b6d181af7
--- /dev/null
+++ b/tools/priority/__tests__/docker-lane-handshake.test.mjs
@@ -0,0 +1,441 @@
+#!/usr/bin/env node
+
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+
+import {
+ DEFAULT_TTL_SECONDS,
+ DOCKER_LANE_CAPABILITY,
+ NATIVE_LV32_CAPABILITY,
+ PREMIUM_RATE_MULTIPLIER,
+ handshakePathForLane,
+ isHandshakeStale,
+ main,
+ runDockerLaneHandshake
+} from '../docker-lane-handshake.mjs';
+
+async function withTempDir(prefix, fn) {
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), `${prefix}-`));
+ try {
+ return await fn(root);
+ } finally {
+ await fs.rm(root, { recursive: true, force: true });
+ }
+}
+
+async function writeJson(filePath, payload) {
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
+ await fs.writeFile(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+function createHostPlaneReport() {
+ return {
+ schema: 'labview-2026-host-plane-report@v1',
+ host: {
+ computerName: 'canonical-builder',
+ osFingerprint: {
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ platform: 'windows',
+ canonical: {
+ version: '10.0.26200',
+ buildNumber: '26200',
+ ubr: 8037
+ }
+ }
+ }
+ };
+}
+
+function createOperatorCostProfile() {
+ return {
+ schema: 'priority/operator-cost-profile@v1',
+ currency: 'USD',
+ defaultOperatorId: 'sergio',
+ operators: [
+ {
+ id: 'sergio',
+ laborRateUsdPerHour: 250,
+ active: true
+ }
+ ]
+ };
+}
+
+test('request creates a docker-lane handshake with host isolated-lane fingerprint context', async () => {
+ await withTempDir('docker-lane-handshake-request', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ const report = await runDockerLaneHandshake({
+ action: 'request',
+ laneId: 'docker-agent-epicurus-linux-01',
+ agentId: 'epicurus',
+ agentClass: 'subagent',
+ capabilities: [DOCKER_LANE_CAPABILITY],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot: path.join(root, 'handshakes'),
+ repoRoot: root,
+ now: new Date('2026-03-23T23:50:00.000Z')
+ });
+
+ assert.equal(report.status, 'requested');
+ assert.equal(report.handshake.state, 'requested');
+ assert.equal(report.handshake.host.isolatedLaneGroupId, createHostPlaneReport().host.osFingerprint.isolatedLaneGroupId);
+ assert.equal(report.handshake.request.premiumDualLaneRequested, false);
+ });
+});
+
+test('grant computes ordinary subagent docker rate from operator profile', async () => {
+ await withTempDir('docker-lane-handshake-grant-ordinary', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const handshakeRoot = path.join(root, 'handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runDockerLaneHandshake({
+ action: 'request',
+ laneId: 'docker-agent-singer-linux-01',
+ agentId: 'singer',
+ agentClass: 'subagent',
+ capabilities: [DOCKER_LANE_CAPABILITY],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:50:00.000Z')
+ });
+
+ const report = await runDockerLaneHandshake({
+ action: 'grant',
+ laneId: 'docker-agent-singer-linux-01',
+ agentId: 'singer',
+ agentClass: 'subagent',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:51:00.000Z')
+ });
+
+ assert.equal(report.status, 'granted');
+ assert.equal(report.handshake.grant.billableRateMultiplier, 1);
+ assert.equal(report.handshake.grant.billableRateUsdPerHour, 250);
+ assert.equal(report.handshake.grant.premiumSaganMode, false);
+ assert.equal(report.handshake.grant.ttlSeconds, DEFAULT_TTL_SECONDS);
+ });
+});
+
+test('grant denies premium dual-lane requests for subagents', async () => {
+ await withTempDir('docker-lane-handshake-deny-subagent-premium', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const handshakeRoot = path.join(root, 'handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runDockerLaneHandshake({
+ action: 'request',
+ laneId: 'docker-agent-hooke-linux-01',
+ agentId: 'hooke',
+ agentClass: 'subagent',
+ capabilities: [DOCKER_LANE_CAPABILITY, NATIVE_LV32_CAPABILITY],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:50:00.000Z')
+ });
+
+ const report = await runDockerLaneHandshake({
+ action: 'grant',
+ laneId: 'docker-agent-hooke-linux-01',
+ agentId: 'hooke',
+ agentClass: 'subagent',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:51:00.000Z')
+ });
+
+ assert.equal(report.status, 'denied');
+ assert.match(report.summary.denialReasons.join('\n'), /premium-sagan-only/);
+ });
+});
+
+test('grant requires operator authorization for premium Sagan dual-lane mode and computes 1.5x rate when authorized', async () => {
+ await withTempDir('docker-lane-handshake-sagan-premium', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const handshakeRoot = path.join(root, 'handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runDockerLaneHandshake({
+ action: 'request',
+ laneId: 'docker-agent-sagan-dual-01',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ capabilities: [DOCKER_LANE_CAPABILITY, NATIVE_LV32_CAPABILITY],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:50:00.000Z')
+ });
+
+ const denied = await runDockerLaneHandshake({
+ action: 'grant',
+ laneId: 'docker-agent-sagan-dual-01',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:51:00.000Z')
+ });
+ assert.equal(denied.status, 'denied');
+ assert.match(denied.summary.denialReasons.join('\n'), /operator-authorization-required/);
+
+ const requestPath = handshakePathForLane('docker-agent-sagan-dual-01', handshakeRoot);
+ const existing = JSON.parse(await fs.readFile(requestPath, 'utf8'));
+ existing.request.operatorAuthorizationRef = 'budget-auth://operator/session-2026-03-23';
+ await writeJson(requestPath, existing);
+
+ const granted = await runDockerLaneHandshake({
+ action: 'grant',
+ laneId: 'docker-agent-sagan-dual-01',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:52:00.000Z')
+ });
+
+ assert.equal(granted.status, 'granted');
+ assert.equal(granted.handshake.grant.premiumSaganMode, true);
+ assert.equal(granted.handshake.grant.billableRateMultiplier, PREMIUM_RATE_MULTIPLIER);
+ assert.equal(granted.handshake.grant.billableRateUsdPerHour, 375);
+ assert.equal(granted.summary.handshakeState, 'granted');
+ assert.equal(granted.summary.leaseId, granted.handshake.grant.leaseId);
+ });
+});
+
+test('commit heartbeat and release keep the same handshake and permit active inspection', async () => {
+ await withTempDir('docker-lane-handshake-life-cycle', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const handshakeRoot = path.join(root, 'handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runDockerLaneHandshake({
+ action: 'request',
+ laneId: 'docker-agent-mill-linux-01',
+ agentId: 'mill',
+ agentClass: 'subagent',
+ capabilities: [DOCKER_LANE_CAPABILITY],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:50:00.000Z')
+ });
+
+ const granted = await runDockerLaneHandshake({
+ action: 'grant',
+ laneId: 'docker-agent-mill-linux-01',
+ agentId: 'mill',
+ agentClass: 'subagent',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:51:00.000Z')
+ });
+
+ const committed = await runDockerLaneHandshake({
+ action: 'commit',
+ laneId: 'docker-agent-mill-linux-01',
+ agentId: 'mill',
+ leaseId: granted.handshake.grant.leaseId,
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:52:00.000Z')
+ });
+ assert.equal(committed.status, 'committed');
+ assert.equal(committed.handshake.state, 'active');
+ assert.equal(committed.summary.linkedExecutionCellId, null);
+ assert.equal(committed.summary.linkedExecutionCellLeaseId, null);
+
+ const renewed = await runDockerLaneHandshake({
+ action: 'heartbeat',
+ laneId: 'docker-agent-mill-linux-01',
+ agentId: 'mill',
+ leaseId: granted.handshake.grant.leaseId,
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:53:00.000Z')
+ });
+ assert.equal(renewed.status, 'renewed');
+ assert.equal(renewed.handshake.state, 'active');
+
+ const activeInspect = await runDockerLaneHandshake({
+ action: 'inspect',
+ laneId: 'docker-agent-mill-linux-01',
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:53:30.000Z')
+ });
+ assert.equal(activeInspect.status, 'active');
+ assert.equal(isHandshakeStale(activeInspect.handshake, Date.parse('2026-03-23T23:53:30.000Z')), false);
+
+ const release = await runDockerLaneHandshake({
+ action: 'release',
+ laneId: 'docker-agent-mill-linux-01',
+ agentId: 'mill',
+ leaseId: granted.handshake.grant.leaseId,
+ artifactPaths: ['tests/results/_agent/runtime/docker-lane-proof.json'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:54:00.000Z')
+ });
+ assert.equal(release.status, 'released');
+ assert.equal(release.handshake.state, 'released');
+ assert.equal(release.summary.handshakeState, 'released');
+ assert.deepEqual(release.handshake.release.artifactPaths, ['tests/results/_agent/runtime/docker-lane-proof.json']);
+ });
+});
+
+test('commit binds docker lane to a linked execution-cell report with the same agent and host fingerprint', async () => {
+ await withTempDir('docker-lane-handshake-linked-cell', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const handshakeRoot = path.join(root, 'handshakes');
+ const executionCellReportPath = path.join(root, 'execution-cell-report.json');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+ await writeJson(executionCellReportPath, {
+ schema: 'priority/execution-cell-lease-report@v1',
+ cellId: 'exec-cell-boyle-02',
+ lease: {
+ cellId: 'exec-cell-boyle-02',
+ host: createHostPlaneReport().host.osFingerprint,
+ request: {
+ agentId: 'boyle',
+ planeBinding: 'native-labview-2026-64',
+ harnessKind: 'teststand-compare-harness'
+ },
+ grant: { leaseId: 'exec-lease-123' }
+ },
+ summary: {
+ holder: 'boyle',
+ leaseId: 'exec-lease-123',
+ harnessKind: 'teststand-compare-harness',
+ planeBinding: 'native-labview-2026-64',
+ isolatedLaneGroupId: createHostPlaneReport().host.osFingerprint.isolatedLaneGroupId,
+ fingerprintSha256: createHostPlaneReport().host.osFingerprint.fingerprintSha256
+ }
+ });
+
+ await runDockerLaneHandshake({
+ action: 'request',
+ laneId: 'docker-agent-boyle-02',
+ agentId: 'boyle',
+ agentClass: 'subagent',
+ capabilities: [DOCKER_LANE_CAPABILITY],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T00:20:00.000Z')
+ });
+ const granted = await runDockerLaneHandshake({
+ action: 'grant',
+ laneId: 'docker-agent-boyle-02',
+ agentId: 'boyle',
+ agentClass: 'subagent',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T00:21:00.000Z')
+ });
+
+ const committed = await runDockerLaneHandshake({
+ action: 'commit',
+ laneId: 'docker-agent-boyle-02',
+ agentId: 'boyle',
+ leaseId: granted.handshake.grant.leaseId,
+ executionCellReportPath,
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T00:22:00.000Z')
+ });
+
+ assert.equal(committed.status, 'committed');
+ assert.equal(committed.handshake.commit.executionCellId, 'exec-cell-boyle-02');
+ assert.equal(committed.handshake.commit.executionCellLeaseId, 'exec-lease-123');
+ assert.equal(committed.summary.linkedExecutionCellId, 'exec-cell-boyle-02');
+ assert.equal(committed.summary.linkedExecutionCellLeaseId, 'exec-lease-123');
+ });
+});
+
+test('docker lane handshake CLI main writes a request receipt', async () => {
+ await withTempDir('docker-lane-handshake-cli', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const outputPath = path.join(root, 'docker-lane-handshake-cli.json');
+ const handshakeRoot = path.join(root, 'docker-lane-handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ const exitCode = await main([
+ 'node',
+ path.join(root, 'docker-lane-handshake.mjs'),
+ '--action',
+ 'request',
+ '--lane-id',
+ 'docker-agent-boyle-05',
+ '--agent-id',
+ 'boyle',
+ '--agent-class',
+ 'subagent',
+ '--capability',
+ 'docker-lane',
+ '--host-plane-report',
+ hostPlaneReportPath,
+ '--operator-cost-profile',
+ operatorCostProfilePath,
+ '--handshake-root',
+ handshakeRoot,
+ '--output',
+ outputPath
+ ]);
+
+ assert.equal(exitCode, 0);
+ const receipt = JSON.parse(await fs.readFile(outputPath, 'utf8'));
+ assert.equal(receipt.status, 'requested');
+ assert.equal(receipt.laneId, 'docker-agent-boyle-05');
+ assert.equal(receipt.summary.handshakeState, 'requested');
+ });
+});
diff --git a/tools/priority/__tests__/execution-cell-bundle-schema.test.mjs b/tools/priority/__tests__/execution-cell-bundle-schema.test.mjs
new file mode 100644
index 000000000..4a190392d
--- /dev/null
+++ b/tools/priority/__tests__/execution-cell-bundle-schema.test.mjs
@@ -0,0 +1,247 @@
+#!/usr/bin/env node
+
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { readFile } from 'node:fs/promises';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import Ajv2020 from 'ajv/dist/2020.js';
+import addFormats from 'ajv-formats';
+
+const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
+
+test('execution cell bundle report schema validates a premium Sagan kernel receipt', async () => {
+ const executionCellStateSchema = JSON.parse(
+ await readFile(path.join(repoRoot, 'docs', 'schemas', 'execution-cell-lease-v1.schema.json'), 'utf8')
+ );
+ const executionCellReportSchema = JSON.parse(
+ await readFile(path.join(repoRoot, 'docs', 'schemas', 'execution-cell-lease-report-v1.schema.json'), 'utf8')
+ );
+ const dockerStateSchema = JSON.parse(
+ await readFile(path.join(repoRoot, 'docs', 'schemas', 'docker-lane-handshake-v1.schema.json'), 'utf8')
+ );
+ const dockerReportSchema = JSON.parse(
+ await readFile(path.join(repoRoot, 'docs', 'schemas', 'docker-lane-handshake-report-v1.schema.json'), 'utf8')
+ );
+ const bundleSchema = JSON.parse(
+ await readFile(path.join(repoRoot, 'docs', 'schemas', 'execution-cell-bundle-report-v1.schema.json'), 'utf8')
+ );
+
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
+ addFormats(ajv);
+ ajv.addSchema(executionCellStateSchema, executionCellStateSchema.$id);
+ ajv.addSchema(executionCellReportSchema, executionCellReportSchema.$id);
+ ajv.addSchema(dockerStateSchema, dockerStateSchema.$id);
+ ajv.addSchema(dockerReportSchema, dockerReportSchema.$id);
+ const validate = ajv.compile(bundleSchema);
+
+ const report = {
+ schema: 'priority/execution-cell-bundle-report@v1',
+ generatedAt: '2026-03-24T02:10:00.000Z',
+ action: 'grant',
+ status: 'granted',
+ cellId: 'exec-cell-sagan-kernel-02',
+ laneId: 'docker-agent-sagan-kernel-02',
+ outputPath: 'tests/results/_agent/runtime/execution-cell-bundle.json',
+ executionCellReportPath: 'tests/results/_agent/runtime/execution-cell-lease.json',
+ dockerLaneReportPath: 'tests/results/_agent/runtime/docker-lane-handshake.json',
+ executionCell: {
+ schema: 'priority/execution-cell-lease-report@v1',
+ generatedAt: '2026-03-24T02:10:00.000Z',
+ action: 'grant',
+ status: 'granted',
+ cellId: 'exec-cell-sagan-kernel-02',
+ leasePath: 'C:/repo/.git/execution-cell-leases/exec-cell-sagan-kernel-02.json',
+ policy: {
+ operatorId: 'sergio',
+ currency: 'USD',
+ laborRateUsdPerHour: 250
+ },
+ lease: {
+ schema: 'priority/execution-cell-lease@v1',
+ generatedAt: '2026-03-24T02:10:00.000Z',
+ cellId: 'exec-cell-sagan-kernel-02',
+ resourceKind: 'execution-cell',
+ state: 'granted',
+ sequence: 2,
+ heartbeatAt: '2026-03-24T02:10:00.000Z',
+ host: {
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ platform: 'windows',
+ computerName: 'canonical-builder',
+ canonical: {
+ version: '10.0.26200',
+ buildNumber: '26200',
+ ubr: 8037
+ }
+ },
+ request: {
+ requestId: 'request-123',
+ requestedAt: '2026-03-24T02:09:00.000Z',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane', 'native-labview-2026-32'],
+ premiumDualLaneRequested: true,
+ operatorId: 'sergio',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ workingRoot: 'E:/comparevi-lanes/cells/sagan-kernel-02/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/sagan-kernel-02/artifacts'
+ },
+ grant: {
+ grantedAt: '2026-03-24T02:10:00.000Z',
+ grantor: 'execution-cell-governor',
+ leaseId: 'lease-123',
+ ttlSeconds: 1800,
+ premiumDualLaneRequested: true,
+ premiumSaganMode: true,
+ policyDecision: 'sagan-premium-dual-lane',
+ grantedCapabilities: ['teststand-harness', 'docker-lane', 'native-labview-2026-32'],
+ billableRateMultiplier: 1.5,
+ billableRateUsdPerHour: 375
+ },
+ commit: null,
+ release: null
+ },
+ summary: {
+ leaseState: 'granted',
+ leaseId: 'lease-123',
+ holder: 'sagan',
+ agentClass: 'sagan',
+ cellClass: 'kernel-coordinator',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: null,
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'dual-plane-parity',
+ premiumSaganMode: true,
+ billableRateMultiplier: 1.5,
+ billableRateUsdPerHour: 375,
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ linkedDockerLaneId: null,
+ linkedDockerLaneLeaseId: null,
+ workingRoot: 'E:/comparevi-lanes/cells/sagan-kernel-02/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/sagan-kernel-02/artifacts',
+ isStale: false,
+ ageSeconds: 0,
+ ttlSeconds: 1800,
+ denialReasons: [],
+ observations: []
+ }
+ },
+ dockerLane: {
+ schema: 'priority/docker-lane-handshake-report@v1',
+ generatedAt: '2026-03-24T02:10:00.000Z',
+ action: 'grant',
+ status: 'granted',
+ laneId: 'docker-agent-sagan-kernel-02',
+ handshakePath: 'C:/repo/.git/docker-lane-handshakes/docker-agent-sagan-kernel-02.json',
+ policy: {
+ operatorId: 'sergio',
+ currency: 'USD',
+ laborRateUsdPerHour: 250,
+ premiumSaganRateMultiplier: 1.5
+ },
+ handshake: {
+ schema: 'priority/docker-lane-handshake@v1',
+ generatedAt: '2026-03-24T02:10:00.000Z',
+ laneId: 'docker-agent-sagan-kernel-02',
+ resourceKind: 'docker-lane',
+ state: 'granted',
+ sequence: 2,
+ heartbeatAt: '2026-03-24T02:10:00.000Z',
+ host: {
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ platform: 'windows',
+ computerName: 'canonical-builder',
+ canonical: {
+ version: '10.0.26200',
+ buildNumber: '26200',
+ ubr: 8037
+ }
+ },
+ request: {
+ requestId: 'request-456',
+ requestedAt: '2026-03-24T02:09:00.000Z',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ capabilities: ['docker-lane', 'native-labview-2026-32', 'teststand-harness'],
+ premiumDualLaneRequested: true,
+ operatorId: 'sergio',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24'
+ },
+ grant: {
+ grantedAt: '2026-03-24T02:10:00.000Z',
+ grantor: 'sagan-governor',
+ leaseId: 'lease-456',
+ ttlSeconds: 1800,
+ grantedCapabilities: ['docker-lane', 'native-labview-2026-32', 'teststand-harness'],
+ billableRateMultiplier: 1.5,
+ billableRateUsdPerHour: 375,
+ premiumSaganMode: true,
+ policyDecision: 'sagan-premium-dual-lane',
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24'
+ },
+ commit: null,
+ release: null
+ },
+ summary: {
+ handshakeState: 'granted',
+ leaseId: 'lease-456',
+ holder: 'sagan',
+ premiumSaganMode: true,
+ billableRateMultiplier: 1.5,
+ billableRateUsdPerHour: 375,
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ linkedExecutionCellId: null,
+ linkedExecutionCellLeaseId: null,
+ isStale: false,
+ ageSeconds: 0,
+ ttlSeconds: 1800,
+ denialReasons: [],
+ observations: []
+ }
+ },
+ rollbacks: {
+ executionCell: null,
+ dockerLane: null
+ },
+ summary: {
+ holder: 'sagan',
+ agentClass: 'sagan',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: null,
+ executionCellLeaseId: 'lease-123',
+ dockerLaneLeaseId: 'lease-456',
+ linkedExecutionCellId: null,
+ linkedExecutionCellLeaseId: null,
+ linkedDockerLaneId: null,
+ linkedDockerLaneLeaseId: null,
+ reciprocalLinkReady: false,
+ dockerRequested: true,
+ windowsNativeTestStand: true,
+ effectiveBillableRateMultiplier: 1.5,
+ effectiveBillableRateUsdPerHour: 375,
+ premiumSaganMode: true,
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ capabilities: ['teststand-harness', 'docker-lane', 'native-labview-2026-32'],
+ denialReasons: [],
+ observations: ['agent-billed-once-at-effective-rate']
+ }
+ };
+
+ assert.equal(validate(report), true, JSON.stringify(validate.errors, null, 2));
+});
diff --git a/tools/priority/__tests__/execution-cell-bundle.test.mjs b/tools/priority/__tests__/execution-cell-bundle.test.mjs
new file mode 100644
index 000000000..d96d89794
--- /dev/null
+++ b/tools/priority/__tests__/execution-cell-bundle.test.mjs
@@ -0,0 +1,401 @@
+#!/usr/bin/env node
+
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+
+import { main, runExecutionCellBundle } from '../execution-cell-bundle.mjs';
+
+async function withTempDir(prefix, fn) {
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), `${prefix}-`));
+ try {
+ return await fn(root);
+ } finally {
+ await fs.rm(root, { recursive: true, force: true });
+ }
+}
+
+async function writeJson(filePath, payload) {
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
+ await fs.writeFile(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+function createHostPlaneReport() {
+ return {
+ schema: 'labview-2026-host-plane-report@v1',
+ host: {
+ computerName: 'canonical-builder',
+ osFingerprint: {
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ platform: 'windows',
+ canonical: {
+ version: '10.0.26200',
+ buildNumber: '26200',
+ ubr: 8037
+ }
+ }
+ }
+ };
+}
+
+function createOperatorCostProfile() {
+ return {
+ schema: 'priority/operator-cost-profile@v1',
+ currency: 'USD',
+ defaultOperatorId: 'sergio',
+ operators: [
+ {
+ id: 'sergio',
+ laborRateUsdPerHour: 250,
+ active: true
+ }
+ ]
+ };
+}
+
+test('execution-cell bundle grants coordinated worker cell and docker lane at ordinary rate', async () => {
+ await withTempDir('execution-cell-bundle-worker', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'execution-cell-leases');
+ const handshakeRoot = path.join(root, 'docker-lane-handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ const requested = await runExecutionCellBundle({
+ action: 'request',
+ cellId: 'exec-cell-hooke-02',
+ laneId: 'docker-agent-hooke-02',
+ agentId: 'hooke',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-64',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ workingRoot: 'E:/comparevi-lanes/cells/hooke-02/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/hooke-02/artifacts',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:00:00.000Z')
+ });
+
+ assert.equal(requested.status, 'requested');
+ assert.equal(requested.summary.dockerRequested, true);
+
+ const granted = await runExecutionCellBundle({
+ action: 'grant',
+ cellId: 'exec-cell-hooke-02',
+ laneId: 'docker-agent-hooke-02',
+ agentId: 'hooke',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-64',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:01:00.000Z')
+ });
+
+ assert.equal(granted.status, 'granted');
+ assert.equal(granted.executionCell.status, 'granted');
+ assert.equal(granted.dockerLane.status, 'granted');
+ assert.equal(granted.summary.effectiveBillableRateUsdPerHour, 250);
+ assert.equal(granted.summary.premiumSaganMode, false);
+ assert.equal(granted.summary.windowsNativeTestStand, true);
+ assert.equal(granted.summary.reciprocalLinkReady, false);
+ });
+});
+
+test('execution-cell bundle infers premium Sagan dual-lane mode for dual-plane parity with docker', async () => {
+ await withTempDir('execution-cell-bundle-sagan-premium', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'execution-cell-leases');
+ const handshakeRoot = path.join(root, 'docker-lane-handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runExecutionCellBundle({
+ action: 'request',
+ cellId: 'exec-cell-sagan-kernel-02',
+ laneId: 'docker-agent-sagan-kernel-02',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ workingRoot: 'E:/comparevi-lanes/cells/sagan-kernel-02/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/sagan-kernel-02/artifacts',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:02:00.000Z')
+ });
+
+ const granted = await runExecutionCellBundle({
+ action: 'grant',
+ cellId: 'exec-cell-sagan-kernel-02',
+ laneId: 'docker-agent-sagan-kernel-02',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:03:00.000Z')
+ });
+
+ assert.equal(granted.status, 'granted');
+ assert.equal(granted.executionCell.status, 'granted');
+ assert.equal(granted.dockerLane.status, 'granted');
+ assert.equal(granted.summary.premiumSaganMode, true);
+ assert.equal(granted.summary.effectiveBillableRateUsdPerHour, 375);
+ assert.equal(granted.summary.reciprocalLinkReady, false);
+ assert.deepEqual(
+ granted.summary.capabilities.sort(),
+ ['docker-lane', 'native-labview-2026-32', 'teststand-harness'].sort()
+ );
+ });
+});
+
+test('execution-cell bundle denies linux-bound TestStand cells and rolls back requested docker lanes', async () => {
+ await withTempDir('execution-cell-bundle-linux-teststand', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'execution-cell-leases');
+ const handshakeRoot = path.join(root, 'docker-lane-handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runExecutionCellBundle({
+ action: 'request',
+ cellId: 'exec-cell-mill-linux-01',
+ laneId: 'docker-agent-mill-linux-01',
+ agentId: 'mill',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'docker-desktop/linux-container-2026',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:04:00.000Z')
+ });
+
+ const denied = await runExecutionCellBundle({
+ action: 'grant',
+ cellId: 'exec-cell-mill-linux-01',
+ laneId: 'docker-agent-mill-linux-01',
+ agentId: 'mill',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'docker-desktop/linux-container-2026',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:05:00.000Z')
+ });
+
+ assert.equal(denied.status, 'denied');
+ assert.match(denied.summary.denialReasons.join('\n'), /teststand-windows-native-only/);
+ assert.equal(denied.rollbacks.dockerLane.status, 'released');
+ });
+});
+
+test('execution-cell bundle commits and releases both leases together', async () => {
+ await withTempDir('execution-cell-bundle-commit-release', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'execution-cell-leases');
+ const handshakeRoot = path.join(root, 'docker-lane-handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runExecutionCellBundle({
+ action: 'request',
+ cellId: 'exec-cell-epicurus-03',
+ laneId: 'docker-agent-epicurus-03',
+ agentId: 'epicurus',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-64',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:06:00.000Z')
+ });
+ await runExecutionCellBundle({
+ action: 'grant',
+ cellId: 'exec-cell-epicurus-03',
+ laneId: 'docker-agent-epicurus-03',
+ agentId: 'epicurus',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-64',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:07:00.000Z')
+ });
+
+ const committed = await runExecutionCellBundle({
+ action: 'commit',
+ cellId: 'exec-cell-epicurus-03',
+ laneId: 'docker-agent-epicurus-03',
+ agentId: 'epicurus',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-64',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ harnessInstanceId: 'harness-epicurus-03',
+ workingRoot: 'E:/comparevi-lanes/cells/epicurus-03/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/epicurus-03/artifacts',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:08:00.000Z')
+ });
+
+ assert.equal(committed.status, 'committed');
+ assert.equal(committed.executionCell.status, 'committed');
+ assert.equal(committed.dockerLane.status, 'committed');
+ assert.equal(committed.summary.executionCellLeaseId, committed.executionCell.summary.leaseId);
+ assert.equal(committed.summary.dockerLaneLeaseId, committed.dockerLane.summary.leaseId);
+ assert.equal(committed.summary.linkedExecutionCellId, 'exec-cell-epicurus-03');
+ assert.equal(committed.summary.linkedDockerLaneId, 'docker-agent-epicurus-03');
+ assert.equal(committed.executionCell.summary.linkedDockerLaneId, 'docker-agent-epicurus-03');
+ assert.equal(
+ committed.executionCell.summary.linkedDockerLaneLeaseId,
+ committed.dockerLane.summary.leaseId
+ );
+ assert.equal(committed.dockerLane.summary.linkedExecutionCellId, 'exec-cell-epicurus-03');
+ assert.equal(
+ committed.dockerLane.summary.linkedExecutionCellLeaseId,
+ committed.executionCell.summary.leaseId
+ );
+ assert.equal(committed.summary.reciprocalLinkReady, true);
+
+ const released = await runExecutionCellBundle({
+ action: 'release',
+ cellId: 'exec-cell-epicurus-03',
+ laneId: 'docker-agent-epicurus-03',
+ agentId: 'epicurus',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-64',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ handshakeRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T02:09:00.000Z')
+ });
+
+ assert.equal(released.status, 'released');
+ assert.equal(released.executionCell.status, 'released');
+ assert.equal(released.dockerLane.status, 'released');
+ });
+});
+
+test('execution-cell bundle CLI main writes a request receipt', async () => {
+ await withTempDir('execution-cell-bundle-cli', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const outputPath = path.join(root, 'execution-cell-bundle-cli.json');
+ const leaseRoot = path.join(root, 'execution-cell-leases');
+ const handshakeRoot = path.join(root, 'docker-lane-handshakes');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ const exitCode = await main([
+ 'node',
+ path.join(root, 'execution-cell-bundle.mjs'),
+ '--action',
+ 'request',
+ '--cell-id',
+ 'exec-cell-boyle-04',
+ '--lane-id',
+ 'docker-agent-boyle-04',
+ '--agent-id',
+ 'boyle',
+ '--agent-class',
+ 'subagent',
+ '--cell-class',
+ 'worker',
+ '--suite-class',
+ 'single-compare',
+ '--plane-binding',
+ 'native-labview-2026-64',
+ '--capability',
+ 'teststand-harness',
+ '--capability',
+ 'docker-lane',
+ '--host-plane-report',
+ hostPlaneReportPath,
+ '--operator-cost-profile',
+ operatorCostProfilePath,
+ '--lease-root',
+ leaseRoot,
+ '--handshake-root',
+ handshakeRoot,
+ '--output',
+ outputPath
+ ]);
+
+ assert.equal(exitCode, 0);
+ const receipt = JSON.parse(await fs.readFile(outputPath, 'utf8'));
+ assert.equal(receipt.status, 'requested');
+ assert.equal(receipt.cellId, 'exec-cell-boyle-04');
+ assert.equal(receipt.laneId, 'docker-agent-boyle-04');
+ });
+});
diff --git a/tools/priority/__tests__/execution-cell-lease-schema.test.mjs b/tools/priority/__tests__/execution-cell-lease-schema.test.mjs
new file mode 100644
index 000000000..881835172
--- /dev/null
+++ b/tools/priority/__tests__/execution-cell-lease-schema.test.mjs
@@ -0,0 +1,122 @@
+#!/usr/bin/env node
+
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { readFile } from 'node:fs/promises';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import Ajv2020 from 'ajv/dist/2020.js';
+import addFormats from 'ajv-formats';
+
+const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
+
+test('execution cell lease report schema validates an active teststand harness lease', async () => {
+ const stateSchemaPath = path.join(repoRoot, 'docs', 'schemas', 'execution-cell-lease-v1.schema.json');
+ const reportSchemaPath = path.join(repoRoot, 'docs', 'schemas', 'execution-cell-lease-report-v1.schema.json');
+ const stateSchema = JSON.parse(await readFile(stateSchemaPath, 'utf8'));
+ const reportSchema = JSON.parse(await readFile(reportSchemaPath, 'utf8'));
+
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
+ addFormats(ajv);
+ ajv.addSchema(stateSchema, stateSchema.$id);
+ const validate = ajv.compile(reportSchema);
+
+ const report = {
+ schema: 'priority/execution-cell-lease-report@v1',
+ generatedAt: '2026-03-24T00:00:00.000Z',
+ action: 'commit',
+ status: 'committed',
+ cellId: 'exec-cell-hooke-01',
+ leasePath: 'C:/repo/.git/execution-cell-leases/exec-cell-hooke-01.json',
+ policy: {
+ operatorId: 'sergio',
+ currency: 'USD',
+ laborRateUsdPerHour: 250
+ },
+ lease: {
+ schema: 'priority/execution-cell-lease@v1',
+ generatedAt: '2026-03-24T00:00:00.000Z',
+ cellId: 'exec-cell-hooke-01',
+ resourceKind: 'execution-cell',
+ state: 'active',
+ sequence: 3,
+ heartbeatAt: '2026-03-24T00:00:00.000Z',
+ host: {
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ platform: 'windows',
+ computerName: 'canonical-builder',
+ canonical: {
+ version: '10.0.26200',
+ buildNumber: '26200',
+ ubr: 8037
+ }
+ },
+ request: {
+ requestId: 'request-123',
+ requestedAt: '2026-03-23T23:58:00.000Z',
+ agentId: 'hooke',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'native-labview-2026-dual',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'dual-plane-parity'],
+ premiumDualLaneRequested: false,
+ operatorId: 'sergio',
+ operatorAuthorizationRef: null,
+ workingRoot: 'E:/comparevi-lanes/cells/hooke-01/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/hooke-01/artifacts'
+ },
+ grant: {
+ grantedAt: '2026-03-23T23:59:00.000Z',
+ grantor: 'execution-cell-governor',
+ leaseId: 'lease-123',
+ ttlSeconds: 1800,
+ premiumDualLaneRequested: false,
+ premiumSaganMode: false,
+ policyDecision: 'ordinary-execution-cell',
+ grantedCapabilities: ['teststand-harness', 'dual-plane-parity'],
+ billableRateMultiplier: 1,
+ billableRateUsdPerHour: 250
+ },
+ commit: {
+ committedAt: '2026-03-24T00:00:00.000Z',
+ harnessInstanceId: 'harness-hooke-01',
+ dockerLaneId: 'docker-agent-hooke-01',
+ dockerLaneLeaseId: 'docker-lease-123',
+ workingRoot: 'E:/comparevi-lanes/cells/hooke-01/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/hooke-01/artifacts'
+ },
+ release: null
+ },
+ summary: {
+ leaseState: 'active',
+ leaseId: 'lease-123',
+ holder: 'hooke',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: 'harness-hooke-01',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'native-labview-2026-dual',
+ premiumSaganMode: false,
+ billableRateMultiplier: 1,
+ billableRateUsdPerHour: 250,
+ operatorAuthorizationRef: null,
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ linkedDockerLaneId: 'docker-agent-hooke-01',
+ linkedDockerLaneLeaseId: 'docker-lease-123',
+ workingRoot: 'E:/comparevi-lanes/cells/hooke-01/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/hooke-01/artifacts',
+ isStale: false,
+ ageSeconds: 0,
+ ttlSeconds: 1800,
+ denialReasons: [],
+ observations: []
+ }
+ };
+
+ assert.equal(validate(report), true, JSON.stringify(validate.errors, null, 2));
+});
diff --git a/tools/priority/__tests__/execution-cell-lease.test.mjs b/tools/priority/__tests__/execution-cell-lease.test.mjs
new file mode 100644
index 000000000..d64e82fcf
--- /dev/null
+++ b/tools/priority/__tests__/execution-cell-lease.test.mjs
@@ -0,0 +1,459 @@
+#!/usr/bin/env node
+
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+
+import {
+ DEFAULT_TTL_SECONDS,
+ isExecutionCellLeaseStale,
+ leasePathForCell,
+ runExecutionCellLease
+} from '../execution-cell-lease.mjs';
+
+async function withTempDir(prefix, fn) {
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), `${prefix}-`));
+ try {
+ return await fn(root);
+ } finally {
+ await fs.rm(root, { recursive: true, force: true });
+ }
+}
+
+async function writeJson(filePath, payload) {
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
+ await fs.writeFile(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+function createHostPlaneReport() {
+ return {
+ schema: 'labview-2026-host-plane-report@v1',
+ host: {
+ computerName: 'canonical-builder',
+ osFingerprint: {
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ platform: 'windows',
+ canonical: {
+ version: '10.0.26200',
+ buildNumber: '26200',
+ ubr: 8037
+ }
+ }
+ }
+ };
+}
+
+function createOperatorCostProfile() {
+ return {
+ schema: 'priority/operator-cost-profile@v1',
+ currency: 'USD',
+ defaultOperatorId: 'sergio',
+ operators: [
+ {
+ id: 'sergio',
+ laborRateUsdPerHour: 250,
+ active: true
+ }
+ ]
+ };
+}
+
+test('request and grant create an execution cell lease with host fingerprint and operator rate', async () => {
+ await withTempDir('execution-cell-lease-request-grant', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'leases');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ const requested = await runExecutionCellLease({
+ action: 'request',
+ cellId: 'exec-cell-hooke-01',
+ agentId: 'hooke',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'native-labview-2026-dual',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'dual-plane-parity'],
+ workingRoot: 'E:/comparevi-lanes/cells/hooke-01/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/hooke-01/artifacts',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:50:00.000Z')
+ });
+
+ assert.equal(requested.status, 'requested');
+ assert.equal(requested.lease.request.agentId, 'hooke');
+ assert.equal(requested.lease.request.cellClass, 'worker');
+ assert.equal(requested.lease.request.suiteClass, 'dual-plane-parity');
+ assert.equal(requested.lease.host.isolatedLaneGroupId, createHostPlaneReport().host.osFingerprint.isolatedLaneGroupId);
+
+ const granted = await runExecutionCellLease({
+ action: 'grant',
+ cellId: 'exec-cell-hooke-01',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:51:00.000Z')
+ });
+
+ assert.equal(granted.status, 'granted');
+ assert.equal(granted.lease.grant.billableRateMultiplier, 1);
+ assert.equal(granted.lease.grant.billableRateUsdPerHour, 250);
+ assert.equal(granted.lease.grant.ttlSeconds, DEFAULT_TTL_SECONDS);
+ assert.equal(granted.lease.grant.premiumSaganMode, false);
+ });
+});
+
+test('commit and release stamp the harness instance and artifact paths', async () => {
+ await withTempDir('execution-cell-lease-lifecycle', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'leases');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runExecutionCellLease({
+ action: 'request',
+ cellId: 'exec-cell-epicurus-02',
+ agentId: 'epicurus',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-64',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:52:00.000Z')
+ });
+
+ const granted = await runExecutionCellLease({
+ action: 'grant',
+ cellId: 'exec-cell-epicurus-02',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:53:00.000Z')
+ });
+
+ const committed = await runExecutionCellLease({
+ action: 'commit',
+ cellId: 'exec-cell-epicurus-02',
+ leaseId: granted.lease.grant.leaseId,
+ harnessInstanceId: 'harness-epicurus-02',
+ workingRoot: 'E:/comparevi-lanes/cells/epicurus-02/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/epicurus-02/artifacts',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:54:00.000Z')
+ });
+
+ assert.equal(committed.status, 'committed');
+ assert.equal(committed.lease.state, 'active');
+ assert.equal(committed.lease.commit.harnessInstanceId, 'harness-epicurus-02');
+ assert.equal(committed.summary.linkedDockerLaneId, null);
+ assert.equal(committed.summary.linkedDockerLaneLeaseId, null);
+
+ const released = await runExecutionCellLease({
+ action: 'release',
+ cellId: 'exec-cell-epicurus-02',
+ leaseId: granted.lease.grant.leaseId,
+ artifactPaths: ['tests/results/_agent/runtime/teststand-session.json'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:55:00.000Z')
+ });
+
+ assert.equal(released.status, 'released');
+ assert.equal(released.lease.release.artifactPaths[0], 'tests/results/_agent/runtime/teststand-session.json');
+ });
+});
+
+test('commit binds execution cell to a linked docker-lane report with the same agent and host fingerprint', async () => {
+ await withTempDir('execution-cell-lease-linked-docker', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'leases');
+ const dockerLaneReportPath = path.join(root, 'docker-lane-report.json');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+ await writeJson(dockerLaneReportPath, {
+ schema: 'priority/docker-lane-handshake-report@v1',
+ laneId: 'docker-agent-boyle-01',
+ handshake: {
+ laneId: 'docker-agent-boyle-01',
+ host: createHostPlaneReport().host.osFingerprint,
+ request: { agentId: 'boyle' },
+ grant: { leaseId: 'docker-lease-123' }
+ },
+ summary: {
+ holder: 'boyle',
+ leaseId: 'docker-lease-123',
+ isolatedLaneGroupId: createHostPlaneReport().host.osFingerprint.isolatedLaneGroupId,
+ fingerprintSha256: createHostPlaneReport().host.osFingerprint.fingerprintSha256
+ }
+ });
+
+ await runExecutionCellLease({
+ action: 'request',
+ cellId: 'exec-cell-boyle-01',
+ agentId: 'boyle',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-64',
+ capabilities: ['teststand-harness'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T00:10:00.000Z')
+ });
+ const granted = await runExecutionCellLease({
+ action: 'grant',
+ cellId: 'exec-cell-boyle-01',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T00:11:00.000Z')
+ });
+
+ const committed = await runExecutionCellLease({
+ action: 'commit',
+ cellId: 'exec-cell-boyle-01',
+ leaseId: granted.lease.grant.leaseId,
+ harnessInstanceId: 'harness-boyle-01',
+ dockerLaneReportPath,
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T00:12:00.000Z')
+ });
+
+ assert.equal(committed.status, 'committed');
+ assert.equal(committed.lease.commit.dockerLaneId, 'docker-agent-boyle-01');
+ assert.equal(committed.lease.commit.dockerLaneLeaseId, 'docker-lease-123');
+ assert.equal(committed.summary.linkedDockerLaneId, 'docker-agent-boyle-01');
+ assert.equal(committed.summary.linkedDockerLaneLeaseId, 'docker-lease-123');
+ });
+});
+
+test('inspect reports staleness for abandoned active execution cells', async () => {
+ await withTempDir('execution-cell-lease-stale', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'leases');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runExecutionCellLease({
+ action: 'request',
+ cellId: 'exec-cell-singer-03',
+ agentId: 'singer',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'native-labview-2026-32',
+ capabilities: ['teststand-harness'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T20:00:00.000Z')
+ });
+ const granted = await runExecutionCellLease({
+ action: 'grant',
+ cellId: 'exec-cell-singer-03',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T20:01:00.000Z')
+ });
+ await runExecutionCellLease({
+ action: 'commit',
+ cellId: 'exec-cell-singer-03',
+ leaseId: granted.lease.grant.leaseId,
+ harnessInstanceId: 'harness-singer-03',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T20:02:00.000Z')
+ });
+
+ const leasePath = leasePathForCell('exec-cell-singer-03', leaseRoot);
+ const existing = JSON.parse(await fs.readFile(leasePath, 'utf8'));
+ assert.equal(isExecutionCellLeaseStale(existing, Date.parse('2026-03-23T21:00:01.000Z')), true);
+
+ const inspected = await runExecutionCellLease({
+ action: 'inspect',
+ cellId: 'exec-cell-singer-03',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T21:00:01.000Z')
+ });
+
+ assert.equal(inspected.status, 'stale');
+ assert.equal(inspected.summary.isStale, true);
+ });
+});
+
+test('premium dual-lane kernel cell requires Sagan authorization and applies premium labor rate', async () => {
+ await withTempDir('execution-cell-lease-premium-sagan', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'leases');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runExecutionCellLease({
+ action: 'request',
+ cellId: 'exec-cell-sagan-kernel-01',
+ agentId: 'sagan',
+ agentClass: 'sagan',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness', 'docker-lane', 'native-labview-2026-32'],
+ operatorAuthorizationRef: 'operator-premium-approved-2026-03-23',
+ workingRoot: 'E:/comparevi-lanes/cells/sagan-kernel-01/work',
+ artifactRoot: 'E:/comparevi-lanes/cells/sagan-kernel-01/artifacts',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:56:00.000Z')
+ });
+
+ const granted = await runExecutionCellLease({
+ action: 'grant',
+ cellId: 'exec-cell-sagan-kernel-01',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:57:00.000Z')
+ });
+
+ assert.equal(granted.status, 'granted');
+ assert.equal(granted.lease.request.cellClass, 'kernel-coordinator');
+ assert.equal(granted.lease.request.premiumDualLaneRequested, true);
+ assert.equal(granted.lease.grant.premiumSaganMode, true);
+ assert.equal(granted.lease.grant.policyDecision, 'sagan-premium-dual-lane');
+ assert.deepEqual(granted.lease.grant.grantedCapabilities.sort(), [
+ 'docker-lane',
+ 'native-labview-2026-32',
+ 'teststand-harness'
+ ]);
+ assert.equal(granted.lease.grant.billableRateMultiplier, 1.5);
+ assert.equal(granted.lease.grant.billableRateUsdPerHour, 375);
+ assert.equal(granted.summary.premiumSaganMode, true);
+ assert.equal(granted.summary.cellClass, 'kernel-coordinator');
+ assert.equal(granted.summary.operatorAuthorizationRef, 'operator-premium-approved-2026-03-23');
+ });
+});
+
+test('premium dual-lane kernel cell is denied for non-Sagan worker requests', async () => {
+ await withTempDir('execution-cell-lease-premium-denied', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'leases');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runExecutionCellLease({
+ action: 'request',
+ cellId: 'exec-cell-hooke-kernel-01',
+ agentId: 'hooke',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'dual-plane-parity',
+ planeBinding: 'dual-plane-parity',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['docker-lane', 'native-labview-2026-32'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:58:00.000Z')
+ });
+
+ const denied = await runExecutionCellLease({
+ action: 'grant',
+ cellId: 'exec-cell-hooke-kernel-01',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-23T23:59:00.000Z')
+ });
+
+ assert.equal(denied.status, 'denied');
+ assert.deepEqual(denied.summary.denialReasons.sort(), [
+ 'operator-authorization-required',
+ 'premium-kernel-cell-required',
+ 'premium-sagan-only'
+ ]);
+ });
+});
+
+test('teststand execution cells fail closed for linux or container plane bindings', async () => {
+ await withTempDir('execution-cell-lease-teststand-windows-only', async (root) => {
+ const hostPlaneReportPath = path.join(root, 'host-plane.json');
+ const operatorCostProfilePath = path.join(root, 'operator-cost-profile.json');
+ const leaseRoot = path.join(root, 'leases');
+ await writeJson(hostPlaneReportPath, createHostPlaneReport());
+ await writeJson(operatorCostProfilePath, createOperatorCostProfile());
+
+ await runExecutionCellLease({
+ action: 'request',
+ cellId: 'exec-cell-hooke-linux-01',
+ agentId: 'hooke',
+ agentClass: 'subagent',
+ cellClass: 'worker',
+ suiteClass: 'single-compare',
+ planeBinding: 'docker-desktop/linux-container-2026',
+ harnessKind: 'teststand-compare-harness',
+ capabilities: ['teststand-harness'],
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T00:02:00.000Z')
+ });
+
+ const denied = await runExecutionCellLease({
+ action: 'grant',
+ cellId: 'exec-cell-hooke-linux-01',
+ hostPlaneReportPath,
+ operatorCostProfilePath,
+ leaseRoot,
+ repoRoot: root,
+ now: new Date('2026-03-24T00:03:00.000Z')
+ });
+
+ assert.equal(denied.status, 'denied');
+ assert.equal(denied.summary.denialReasons.includes('teststand-windows-native-only'), true);
+ });
+});
diff --git a/tools/priority/__tests__/github-comment-budget-hook-schema.test.mjs b/tools/priority/__tests__/github-comment-budget-hook-schema.test.mjs
new file mode 100644
index 000000000..6e58d71ac
--- /dev/null
+++ b/tools/priority/__tests__/github-comment-budget-hook-schema.test.mjs
@@ -0,0 +1,91 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+
+import { Ajv2020 } from 'ajv/dist/2020.js';
+import addFormats from 'ajv-formats';
+
+import { runGitHubCommentBudgetHook } from '../github-comment-budget-hook.mjs';
+
+const repoRoot = path.resolve(process.cwd());
+
+function readJson(filePath) {
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
+}
+
+function writeJson(filePath, payload) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+test('github-comment-budget-hook report and policy validate against checked-in schemas', () => {
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'github-comment-budget-hook-schema-'));
+ const repo = path.join(tempDir, 'repo');
+ const policyPath = path.join(repo, 'tools', 'policy', 'github-comment-budget-hook.json');
+ writeJson(policyPath, {
+ schema: 'priority/github-comment-budget-hook-policy@v1',
+ costRollupPath: 'tests/results/_agent/cost/agent-cost-rollup.json',
+ materializationPolicyPath: 'tools/policy/agent-cost-rollup-materialization.json',
+ materializationReportPath: 'tests/results/_agent/cost/agent-cost-rollup-materialization.json',
+ outputPath: 'tests/results/_agent/cost/github-comment-budget-hook.json',
+ markdownOutputPath: 'tests/results/_agent/cost/github-comment-budget-hook.md',
+ operatorBudgetCapUsd: 50000,
+ materializeCostRollup: true,
+ reservedFundingPurposes: ['calibration'],
+ reservedActivationStates: ['hold']
+ });
+
+ const { report } = runGitHubCommentBudgetHook(
+ {
+ repoRoot: repo,
+ policyPath,
+ targetKind: 'pr',
+ targetNumber: 1908
+ },
+ {
+ runMaterializeAgentCostRollupFn: ({ costRollupPath, outputPath }) => {
+ writeJson(costRollupPath, {
+ schema: 'priority/agent-cost-rollup@v1',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ summary: {
+ metrics: {
+ totalTurns: 1,
+ liveTurnCount: 0,
+ backgroundTurnCount: 1,
+ totalUsd: 1.5,
+ operatorLaborUsd: 4,
+ operatorLaborMissingTurnCount: 0,
+ blendedTotalUsd: 5.5,
+ estimatedPrepaidUsdRemaining: 398.5
+ },
+ provenance: {
+ operatorProfiles: [{ operatorProfilePath: 'tools/policy/operator-cost-profile.json' }],
+ invoiceTurns: []
+ }
+ },
+ billingWindow: {
+ invoiceTurnId: 'invoice-turn-2026-03-HQ1VJLMV-0027',
+ invoiceId: 'HQ1VJLMV-0027',
+ fundingPurpose: 'operational',
+ activationState: 'active',
+ prepaidUsd: 400,
+ pricingBasis: 'prepaid-credit',
+ selection: { mode: 'hold', reason: null }
+ }
+ });
+ writeJson(outputPath, { schema: 'priority/agent-cost-rollup-materialization@v1', summary: { status: 'pass' } });
+ return { costRollupPath, outputPath };
+ }
+ }
+ );
+
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
+ addFormats(ajv);
+ const validatePolicy = ajv.compile(readJson(path.join(repoRoot, 'docs', 'schemas', 'github-comment-budget-hook-policy-v1.schema.json')));
+ const validateReport = ajv.compile(readJson(path.join(repoRoot, 'docs', 'schemas', 'github-comment-budget-hook-report-v1.schema.json')));
+
+ assert.equal(validatePolicy(readJson(policyPath)), true, JSON.stringify(validatePolicy.errors, null, 2));
+ assert.equal(validateReport(report), true, JSON.stringify(validateReport.errors, null, 2));
+});
diff --git a/tools/priority/__tests__/github-comment-budget-hook.test.mjs b/tools/priority/__tests__/github-comment-budget-hook.test.mjs
new file mode 100644
index 000000000..3802ac3aa
--- /dev/null
+++ b/tools/priority/__tests__/github-comment-budget-hook.test.mjs
@@ -0,0 +1,145 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+
+import {
+ COMMENT_HOOK_END_MARKER,
+ COMMENT_HOOK_START_MARKER,
+ appendBudgetHook,
+ runGitHubCommentBudgetHook,
+ stripExistingBudgetHook
+} from '../github-comment-budget-hook.mjs';
+
+function writeJson(filePath, payload) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+function createRollupFixture() {
+ return {
+ schema: 'priority/agent-cost-rollup@v1',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ summary: {
+ metrics: {
+ totalTurns: 3,
+ liveTurnCount: 1,
+ backgroundTurnCount: 2,
+ totalUsd: 12.5,
+ operatorLaborUsd: 30,
+ operatorLaborMissingTurnCount: 1,
+ blendedTotalUsd: null,
+ estimatedPrepaidUsdRemaining: 387.5
+ },
+ provenance: {
+ operatorProfiles: [
+ {
+ operatorProfilePath: 'tools/policy/operator-cost-profile.json'
+ }
+ ],
+ invoiceTurns: [
+ {
+ invoiceTurnId: 'invoice-turn-2026-03-HQ1VJLMV-0027',
+ invoiceId: 'HQ1VJLMV-0027',
+ fundingPurpose: 'operational',
+ activationState: 'active',
+ prepaidUsd: 400,
+ operatorNote: 'Operational window.'
+ },
+ {
+ invoiceTurnId: 'invoice-turn-2026-03-HQ1VJLMV-0028',
+ invoiceId: 'HQ1VJLMV-0028',
+ fundingPurpose: 'calibration',
+ activationState: 'hold',
+ prepaidUsd: 100,
+ operatorNote: 'Reserved calibration window.'
+ }
+ ]
+ }
+ },
+ billingWindow: {
+ invoiceTurnId: 'invoice-turn-2026-03-HQ1VJLMV-0027',
+ invoiceId: 'HQ1VJLMV-0027',
+ fundingPurpose: 'operational',
+ activationState: 'active',
+ prepaidUsd: 400,
+ pricingBasis: 'prepaid-credit',
+ selection: {
+ mode: 'hold',
+ reason: 'Calibration funding window remains on hold before activation.'
+ }
+ }
+ };
+}
+
+test('stripExistingBudgetHook removes the previous budget block cleanly', () => {
+ const original = ['Intro line', '', COMMENT_HOOK_START_MARKER, 'old hook', COMMENT_HOOK_END_MARKER, '', 'Tail line'].join('\n');
+ assert.equal(stripExistingBudgetHook(original), 'Intro line\n\nTail line');
+});
+
+test('appendBudgetHook appends exactly one hook block', () => {
+ const hook = `${COMMENT_HOOK_START_MARKER}\nHook\n${COMMENT_HOOK_END_MARKER}`;
+ const once = appendBudgetHook('Hello', hook);
+ const twice = appendBudgetHook(once, hook);
+ assert.equal(once, twice);
+ assert.match(twice, /Hello/);
+ assert.match(twice, new RegExp(COMMENT_HOOK_START_MARKER.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
+});
+
+test('runGitHubCommentBudgetHook emits a durable lower-bound budget hook with reserved calibration context', () => {
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'github-comment-budget-hook-'));
+ const repoRoot = path.join(tempDir, 'repo');
+ fs.mkdirSync(repoRoot, { recursive: true });
+ const policyPath = path.join(repoRoot, 'tools', 'policy', 'github-comment-budget-hook.json');
+ const outputPath = path.join(repoRoot, 'tests', 'results', '_agent', 'cost', 'github-comment-budget-hook.json');
+ const markdownOutputPath = path.join(repoRoot, 'tests', 'results', '_agent', 'cost', 'github-comment-budget-hook.md');
+ const rollupPath = path.join(repoRoot, 'tests', 'results', '_agent', 'cost', 'agent-cost-rollup.json');
+
+ writeJson(policyPath, {
+ schema: 'priority/github-comment-budget-hook-policy@v1',
+ costRollupPath: 'tests/results/_agent/cost/agent-cost-rollup.json',
+ materializationPolicyPath: 'tools/policy/agent-cost-rollup-materialization.json',
+ materializationReportPath: 'tests/results/_agent/cost/agent-cost-rollup-materialization.json',
+ outputPath: 'tests/results/_agent/cost/github-comment-budget-hook.json',
+ markdownOutputPath: 'tests/results/_agent/cost/github-comment-budget-hook.md',
+ operatorBudgetCapUsd: 50000,
+ materializeCostRollup: true,
+ reservedFundingPurposes: ['calibration'],
+ reservedActivationStates: ['hold']
+ });
+
+ const result = runGitHubCommentBudgetHook(
+ {
+ repoRoot,
+ policyPath,
+ targetKind: 'issue',
+ targetNumber: 1907
+ },
+ {
+ runMaterializeAgentCostRollupFn: ({ costRollupPath, outputPath: materializationPath }) => {
+ writeJson(costRollupPath, createRollupFixture());
+ writeJson(materializationPath, {
+ schema: 'priority/agent-cost-rollup-materialization@v1',
+ summary: { status: 'pass' }
+ });
+ return {
+ costRollupPath,
+ outputPath: materializationPath
+ };
+ }
+ }
+ );
+
+ assert.equal(result.report.summary.status, 'warn');
+ assert.equal(result.report.summary.operatorBudgetCapUsd, 50000);
+ assert.equal(result.report.summary.operatorBudgetRemainingStatus, 'lower-bound');
+ assert.equal(result.report.summary.observedBlendedLowerBoundUsd, 42.5);
+ assert.equal(result.report.turns.backgroundTurnCount, 2);
+ assert.equal(result.report.funding.reservedFunding.count, 1);
+ assert.equal(result.report.funding.reservedFunding.totalReservedUsd, 100);
+ assert.equal(fs.existsSync(outputPath), true);
+ assert.equal(fs.existsSync(markdownOutputPath), true);
+ assert.match(result.markdown, /blended lower bound \$42\.500000/);
+ assert.match(result.markdown, /calibration reserve \$100\.000000/);
+});
diff --git a/tools/priority/__tests__/handoff-entrypoint-contract.test.mjs b/tools/priority/__tests__/handoff-entrypoint-contract.test.mjs
index 2d6b17a0c..984b6b74b 100644
--- a/tools/priority/__tests__/handoff-entrypoint-contract.test.mjs
+++ b/tools/priority/__tests__/handoff-entrypoint-contract.test.mjs
@@ -31,6 +31,7 @@ test('AGENT_HANDOFF stays bounded and points agents to live state artifacts', ()
assert.match(handoff, /tests\/results\/_agent\/handoff\/entrypoint-status\.json/);
assert.match(handoff, /tests\/results\/_agent\/handoff\/monitoring-mode\.json/);
assert.match(handoff, /tests\/results\/_agent\/handoff\/autonomous-governor-summary\.json/);
+ assert.match(handoff, /tests\/results\/_agent\/handoff\/sagan-context-concentrator\.json/);
assert.match(handoff, /tests\/results\/_agent\/handoff\/autonomous-governor-portfolio-summary\.json/);
assert.match(handoff, /tests\/results\/_agent\/handoff\/\*\.json/);
assert.match(handoff, /tests\/results\/_agent\/sessions\/\*\.json/);
@@ -62,18 +63,26 @@ test('handoff entrypoint contract is wired into automation and operator docs', (
assert.match(printHandoff, /continuity-summary\.json/);
assert.match(printHandoff, /handoff-monitoring-mode\.mjs/);
assert.match(printHandoff, /monitoring-mode\.json/);
+ assert.match(printHandoff, /release-published-bundle-observer\.mjs/);
+ assert.match(printHandoff, /release-published-bundle-observer\.json/);
+ assert.match(printHandoff, /release-signing-readiness\.mjs/);
+ assert.match(printHandoff, /release-signing-readiness\.json/);
assert.match(printHandoff, /autonomous-governor-summary\.mjs/);
assert.match(printHandoff, /autonomous-governor-summary\.json/);
assert.match(printHandoff, /autonomous-governor-portfolio-summary\.mjs/);
assert.match(printHandoff, /autonomous-governor-portfolio-summary\.json/);
+ assert.match(printHandoff, /sagan-context-concentrator\.mjs/);
+ assert.match(printHandoff, /sagan-context-concentrator\.json/);
assert.match(printHandoff, /docker-review-loop-summary\.json/);
assert.match(importHandoff, /entrypoint-status\.json/);
assert.match(importHandoff, /continuity-summary\.json/);
assert.match(importHandoff, /monitoring-mode\.json/);
assert.match(importHandoff, /autonomous-governor-summary\.json/);
assert.match(importHandoff, /autonomous-governor-portfolio-summary\.json/);
+ assert.match(importHandoff, /sagan-context-concentrator\.json/);
assert.match(importHandoff, /\[handoff\] Autonomous governor summary/);
assert.match(importHandoff, /\[handoff\] Governor portfolio summary/);
+ assert.match(importHandoff, /\[handoff\] Context concentrator/);
assert.match(importHandoff, /\[handoff\] Monitoring mode/);
assert.match(importHandoff, /\[handoff\] Continuity summary/);
assert.match(importHandoff, /docker-review-loop-summary\.json/);
@@ -94,8 +103,12 @@ test('handoff entrypoint contract is wired into automation and operator docs', (
assert.match(handoffGuide, /monitoring-mode\.json/);
assert.match(handoffGuide, /autonomous-governor-summary\.json/);
assert.match(handoffGuide, /autonomous-governor-portfolio-summary\.json/);
+ assert.match(handoffGuide, /sagan-context-concentrator\.json/);
assert.match(handoffGuide, /docker-review-loop-summary\.json/);
+ assert.match(handoffGuide, /release-signing/i);
assert.match(handoffGuide, /priority:handoff/);
+ assert.match(handoffGuide, /priority:context:concentrate/);
+ assert.match(handoffGuide, /subagent/i);
assert.match(handoffGuide, /queue-empty/);
assert.match(handoffGuide, /future agents may pivot/i);
});
diff --git a/tools/priority/__tests__/labview-2026-host-plane-report-schema.test.mjs b/tools/priority/__tests__/labview-2026-host-plane-report-schema.test.mjs
index 376eb36ff..8dd548f3b 100644
--- a/tools/priority/__tests__/labview-2026-host-plane-report-schema.test.mjs
+++ b/tools/priority/__tests__/labview-2026-host-plane-report-schema.test.mjs
@@ -16,7 +16,52 @@ test('labview-2026 host plane schema validates the shadow-plane policy contract'
const report = {
schema: 'labview-2026-host-plane-report@v1',
generatedAt: '2026-03-21T00:00:00.000Z',
- host: { os: 'windows', computerName: 'builder' },
+ host: {
+ os: 'windows',
+ computerName: 'builder',
+ osFingerprint: {
+ role: 'canonical-host-baseline',
+ comparisonScope: 'isolated-lane-group',
+ platform: 'windows',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ canonical: {
+ version: '10.0.26200',
+ buildNumber: '26200',
+ ubr: 8037,
+ displayVersion: '25H2',
+ editionId: 'Professional',
+ installationType: 'Client',
+ architecture: '64-bit',
+ systemType: 'x64-based PC',
+ buildLabEx: '26100.1.amd64fre.ge_release.240331-1435'
+ },
+ advisory: {
+ caption: 'Microsoft Windows 11 Pro',
+ productName: 'Windows 10 Pro',
+ currentVersionCompatibility: '6.3',
+ brandingMismatch: true,
+ installDate: '2026-02-14T03:49:47.0000000-08:00',
+ lastBootUpTime: '2026-03-20T09:06:51.0000000-07:00'
+ },
+ sources: {
+ registryPath: 'HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion',
+ cimClass: 'Win32_OperatingSystem',
+ systemClass: 'Win32_ComputerSystem',
+ comparisonFields: [
+ 'version',
+ 'buildNumber',
+ 'ubr',
+ 'displayVersion',
+ 'editionId',
+ 'installationType',
+ 'architecture',
+ 'systemType',
+ 'buildLabEx'
+ ]
+ }
+ }
+ },
runner: { hostIsRunner: true, runnerName: 'builder', githubActions: false },
docker: {
operatorLabels: ['linux-docker-fast-loop', 'windows-docker-fast-loop', 'dual-docker-fast-loop']
diff --git a/tools/priority/__tests__/labview-2026-host-plane-runbook.test.mjs b/tools/priority/__tests__/labview-2026-host-plane-runbook.test.mjs
index cd30fce3d..2ee3d28db 100644
--- a/tools/priority/__tests__/labview-2026-host-plane-runbook.test.mjs
+++ b/tools/priority/__tests__/labview-2026-host-plane-runbook.test.mjs
@@ -27,12 +27,19 @@ test('single-host runbook points to the authoritative commands and artifacts', (
const runbook = readFile(runbookPath);
assert.match(runbook, /node tools\/npm\/run-script\.mjs env:labview:2026:host-planes/);
+ assert.match(runbook, /node tools\/npm\/run-script\.mjs priority:lane:docker:handshake/);
assert.match(runbook, /pwsh -NoLogo -NoProfile -File tools\/Test-DockerDesktopFastLoop\.ps1 -LaneScope linux -StepTimeoutSeconds 600/);
assert.match(runbook, /pwsh -NoLogo -NoProfile -File tools\/Test-DockerDesktopFastLoop\.ps1 -LaneScope windows -StepTimeoutSeconds 600/);
assert.match(runbook, /pwsh -NoLogo -NoProfile -File tools\/Test-DockerDesktopFastLoop\.ps1 -LaneScope both -StepTimeoutSeconds 600/);
+ assert.match(runbook, /tools\/TestStand-CompareHarness\.ps1/);
assert.match(runbook, /node tools\/npm\/run-script\.mjs history:diagnostics:show -- --ResultsRoot tests\/results\/local-parity\/windows/);
assert.match(runbook, /labview-2026-host-plane-report\.json/);
assert.match(runbook, /labview-2026-host-plane-summary\.md/);
+ assert.match(runbook, /docker-lane-handshake\.json/);
+ assert.match(runbook, /Only `sagan` may lease `docker-lane` and `native-labview-2026-32` simultaneously/);
+ assert.match(runbook, /operatorAuthorizationRef/);
+ assert.match(runbook, /host\.osFingerprint/);
+ assert.match(runbook, /fingerprintSha256/);
assert.match(runbook, /docker-runtime-fastloop-readiness\.json/);
assert.match(runbook, /docker-fast-loop-summary-path/);
assert.match(runbook, /docker-fast-loop-status-path/);
@@ -66,6 +73,8 @@ test('developer guide and documentation manifest point back to the single-host r
assert.ok(entry, 'documentation manifest should include the host-plane diagnostics entry');
assert.ok(entry.files.includes('docs/SINGLE_HOST_LABVIEW_2026_PLANES.md'));
assert.ok(entry.files.includes('docs/DEVELOPER_GUIDE.md'));
+ assert.ok(entry.files.includes('tools/priority/docker-lane-handshake.mjs'));
+ assert.ok(entry.files.includes('tools/TestStand-CompareHarness.ps1'));
assert.ok(entry.files.includes('tools/Write-DockerFastLoopReadiness.ps1'));
assert.ok(entry.files.includes('tools/Write-DockerFastLoopProof.ps1'));
assert.ok(entry.files.includes('tools/Show-DockerFastLoopDiagnostics.ps1'));
diff --git a/tools/priority/__tests__/monitoring-work-injection-schema.test.mjs b/tools/priority/__tests__/monitoring-work-injection-schema.test.mjs
index 3b4fc7d5f..d5ef8e7ea 100644
--- a/tools/priority/__tests__/monitoring-work-injection-schema.test.mjs
+++ b/tools/priority/__tests__/monitoring-work-injection-schema.test.mjs
@@ -124,11 +124,30 @@ test('monitoring work injection report matches schema', async () => {
monitoringStatus: 'active',
futureAgentAction: 'future-agent-may-pivot',
governorMode: 'compare-governance-work',
- nextAction: 'continue-compare-governance-work'
+ nextAction: 'continue-compare-governance-work',
+ queueHandoffStatus: null,
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: null
},
portfolio: {
repositoryCount: 4,
repositories: [],
+ dependencies: [
+ {
+ id: 'vi-history-producer-native-distributor',
+ status: 'unknown',
+ ownerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ dependentRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ requiredCapability: 'vi-history',
+ source: 'compare-release-signing-readiness',
+ releaseSigningStatus: null,
+ releasePublicationState: null,
+ signingCapabilityState: null,
+ externalBlocker: null,
+ detail: 'fixture'
+ }
+ ],
unsupportedPaths: []
},
summary: {
@@ -141,6 +160,14 @@ test('monitoring work injection report matches schema', async () => {
templateMonitoringStatus: 'pass',
supportedProofStatus: 'pass',
repoGraphStatus: 'pass',
+ queueHandoffStatus: null,
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: null,
+ viHistoryDistributorDependencyStatus: 'unknown',
+ viHistoryDistributorDependencyTargetRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ viHistoryDistributorDependencyExternalBlocker: null,
+ viHistoryDistributorDependencyPublicationState: null,
portfolioWakeConditionCount: 0,
triggeredWakeConditions: []
}
diff --git a/tools/priority/__tests__/monitoring-work-injection.test.mjs b/tools/priority/__tests__/monitoring-work-injection.test.mjs
index 465701d83..bdef2b0ad 100644
--- a/tools/priority/__tests__/monitoring-work-injection.test.mjs
+++ b/tools/priority/__tests__/monitoring-work-injection.test.mjs
@@ -64,7 +64,10 @@ function createGovernorPortfolioSummary({
governorMode = 'compare-governance-work',
nextAction = 'continue-compare-governance-work',
ownerDecisionSource = 'compare-governor-summary',
- status = 'active'
+ status = 'active',
+ viHistoryDistributorDependencyStatus = 'unknown',
+ viHistoryDistributorDependencyExternalBlocker = null,
+ viHistoryDistributorDependencyPublicationState = null
} = {}) {
return {
schema: 'priority/autonomous-governor-portfolio-summary-report@v1',
@@ -81,11 +84,30 @@ function createGovernorPortfolioSummary({
monitoringStatus: 'active',
futureAgentAction: 'future-agent-may-pivot',
governorMode,
- nextAction
+ nextAction,
+ queueHandoffStatus: null,
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: null
},
portfolio: {
repositoryCount: 4,
repositories: [],
+ dependencies: [
+ {
+ id: 'vi-history-producer-native-distributor',
+ status: viHistoryDistributorDependencyStatus,
+ ownerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ dependentRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ requiredCapability: 'vi-history',
+ source: 'compare-release-signing-readiness',
+ releaseSigningStatus: null,
+ releasePublicationState: viHistoryDistributorDependencyPublicationState,
+ signingCapabilityState: null,
+ externalBlocker: viHistoryDistributorDependencyExternalBlocker,
+ detail: 'fixture'
+ }
+ ],
unsupportedPaths: []
},
summary: {
@@ -98,6 +120,14 @@ function createGovernorPortfolioSummary({
templateMonitoringStatus: 'pass',
supportedProofStatus: 'pass',
repoGraphStatus: 'pass',
+ queueHandoffStatus: null,
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: null,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
portfolioWakeConditionCount: 0,
triggeredWakeConditions: []
}
diff --git a/tools/priority/__tests__/pr-spend-projection.test.mjs b/tools/priority/__tests__/pr-spend-projection.test.mjs
index e39be7198..6e0f22115 100644
--- a/tools/priority/__tests__/pr-spend-projection.test.mjs
+++ b/tools/priority/__tests__/pr-spend-projection.test.mjs
@@ -325,7 +325,10 @@ test('runPrSpendProjection writes JSON and markdown outputs and can upsert a com
posted = { repo, prNumber, body };
return { posted: true, mode: 'update-existing-marker-comment' };
},
- lookupCurrentLoginFn: () => 'automation-user'
+ lookupCurrentLoginFn: () => 'automation-user',
+ runGitHubCommentBudgetHookFn: () => ({
+ markdown: '\n_Budget hook_: stub.\n\n'
+ })
}
);
@@ -409,7 +412,10 @@ test('runPrSpendProjection materializes a missing cost rollup before projection'
outputPath: materializationReportPath,
costRollupPath: requestedPath
};
- }
+ },
+ runGitHubCommentBudgetHookFn: () => ({
+ markdown: '\n_Budget hook_: stub.\n\n'
+ })
}
);
@@ -490,7 +496,10 @@ test('runPrSpendProjection rematerializes when an existing rollup has no matchin
outputPath: requestedOutputPath,
costRollupPath: requestedPath
};
- }
+ },
+ runGitHubCommentBudgetHookFn: () => ({
+ markdown: '\n_Budget hook_: stub.\n\n'
+ })
}
);
diff --git a/tools/priority/__tests__/release-conductor-workflow-contract.test.mjs b/tools/priority/__tests__/release-conductor-workflow-contract.test.mjs
index d416ae1cd..2a808b2c6 100644
--- a/tools/priority/__tests__/release-conductor-workflow-contract.test.mjs
+++ b/tools/priority/__tests__/release-conductor-workflow-contract.test.mjs
@@ -12,9 +12,33 @@ test('release conductor workflow keeps workflow_run proposal-only when apply mod
const workflowPath = path.join(repoRoot, '.github', 'workflows', 'release-conductor.yml');
const workflow = await readFile(workflowPath, 'utf8');
+ assert.match(workflow, /repair_existing_tag:/);
+ assert.match(workflow, /description:\s+'Repair an existing authoritative tag as a signed annotated tag'/);
assert.match(workflow, /RELEASE_CONDUCTOR_ENABLED:\s+\$\{\{\s*vars\.RELEASE_CONDUCTOR_ENABLED \|\| '0'\s*\}\}/);
+ assert.match(workflow, /name:\s+Configure release tag signing material/);
+ assert.match(workflow, /if \[\[ -z "\$\{RELEASE_TAG_SIGNING_PRIVATE_KEY:-\}" \]\]; then/);
+ assert.match(workflow, /if \[\[ -z "\$\{GH_TOKEN:-\}" \]\]; then/);
+ assert.match(workflow, /RELEASE_TAG_SIGNING_IDENTITY_NAME:\s+\$\{\{\s*vars\.RELEASE_TAG_SIGNING_IDENTITY_NAME \|\| ''\s*\}\}/);
+ assert.match(workflow, /RELEASE_TAG_SIGNING_IDENTITY_EMAIL:\s+\$\{\{\s*vars\.RELEASE_TAG_SIGNING_IDENTITY_EMAIL \|\| ''\s*\}\}/);
+ assert.match(workflow, /signing_login="\$\(gh api user --jq '\.login'\)"/);
+ assert.match(workflow, /signing_id="\$\(gh api user --jq '\.id'\)"/);
+ assert.match(workflow, /git config gpg\.format ssh/);
+ assert.match(workflow, /git config user\.signingkey "\$public_key_path"/);
+ assert.match(workflow, /git config user\.name "\$signing_name"/);
+ assert.match(workflow, /git config user\.email "\$signing_email"/);
+ assert.match(workflow, /RELEASE_TAG_SIGNING_BACKEND=ssh/);
+ assert.match(workflow, /RELEASE_TAG_SIGNING_SOURCE=workflow-secret/);
+ assert.match(workflow, /RELEASE_TAG_SIGNING_IDENTITY_SOURCE=\$identity_source/);
assert.match(
workflow,
/elseif \(\$eventName -eq 'workflow_run'\) \{\s+\$apply = \$conductorEnabled\s+if \(-not \$apply\) \{\s+Write-Host 'Release conductor apply mode disabled; workflow_run will remain proposal-only\.'\s+\}\s+\}/ms
);
+ assert.match(workflow, /RELEASE_TAG_SIGNING_BACKEND:\s+\$\{\{\s*env\.RELEASE_TAG_SIGNING_BACKEND \|\| ''\s*\}\}/);
+ assert.match(workflow, /RELEASE_TAG_SIGNING_SOURCE:\s+\$\{\{\s*env\.RELEASE_TAG_SIGNING_SOURCE \|\| ''\s*\}\}/);
+ assert.match(
+ workflow,
+ /node tools\/npm\/run-script\.mjs priority:queue:supervisor -- --dry-run --report tests\/results\/_agent\/queue\/queue-supervisor-report\.json/
+ );
+ assert.match(workflow, /if \('\$\{\{\s*inputs\.repair_existing_tag\s*\}\}' -eq 'true'\) \{\s+\$args \+= '--repair-existing-tag'\s+\}/ms);
+ assert.match(workflow, /tests\/results\/_agent\/queue\/queue-supervisor-report\.json/);
});
diff --git a/tools/priority/__tests__/release-conductor.test.mjs b/tools/priority/__tests__/release-conductor.test.mjs
index 1b1a317c3..4878089a1 100644
--- a/tools/priority/__tests__/release-conductor.test.mjs
+++ b/tools/priority/__tests__/release-conductor.test.mjs
@@ -40,6 +40,7 @@ test('parseArgs applies defaults and supports burst-style apply flags', () => {
const defaults = parseArgs(['node', 'release-conductor.mjs']);
assert.equal(defaults.apply, false);
assert.equal(defaults.dryRun, true);
+ assert.equal(defaults.repairExistingTag, false);
assert.equal(defaults.channel, 'stable');
assert.equal(defaults.dwellMinutes, 60);
@@ -47,6 +48,7 @@ test('parseArgs applies defaults and supports burst-style apply flags', () => {
'node',
'release-conductor.mjs',
'--apply',
+ '--repair-existing-tag',
'--repo',
'owner/repo',
'--channel',
@@ -60,6 +62,7 @@ test('parseArgs applies defaults and supports burst-style apply flags', () => {
]);
assert.equal(parsed.apply, true);
assert.equal(parsed.dryRun, false);
+ assert.equal(parsed.repairExistingTag, true);
assert.equal(parsed.repo, 'owner/repo');
assert.equal(parsed.channel, 'rc');
assert.equal(parsed.version, '0.8.0-rc.1');
@@ -90,6 +93,34 @@ test('gate evaluators classify pass/fail deterministically', () => {
assert.equal(queueFail.status, 'fail');
assert.ok(queueFail.reasons.includes('queue-paused'));
+ const queueIdlePass = evaluateQueueHealthGate({
+ exists: true,
+ error: null,
+ payload: {
+ paused: true,
+ pausedReasons: ['success-rate-below-threshold'],
+ throughputController: { mode: 'stabilize' },
+ runtimeFleet: {
+ totals: {
+ queued: 0,
+ inProgress: 0,
+ stalled: 0
+ }
+ },
+ queueInventory: {
+ mergeQueueOccupancy: 0,
+ readyQueuedCount: 0
+ },
+ summary: {
+ quarantinedCount: 0
+ }
+ }
+ });
+ assert.equal(queueIdlePass.status, 'pass');
+ assert.equal(queueIdlePass.paused, true);
+ assert.equal(queueIdlePass.controllerMode, 'stabilize');
+ assert.deepEqual(queueIdlePass.reasons, ['release-safe-idle-queue-pause']);
+
const policyPass = evaluatePolicySnapshotGate({
exists: true,
error: null,
@@ -118,6 +149,18 @@ test('gate evaluators classify pass/fail deterministically', () => {
});
assert.equal(quarantineFail.status, 'fail');
assert.equal(quarantineFail.staleCount, 1);
+
+ const quarantineUnavailable = evaluateQuarantineGate({
+ now,
+ staleHours: 12,
+ queueReportEnvelope: {
+ exists: false,
+ error: null,
+ payload: null
+ }
+ });
+ assert.equal(quarantineUnavailable.status, 'fail');
+ assert.equal(quarantineUnavailable.staleHours, 12);
});
test('runReleaseConductor blocks apply when release conductor flag is disabled', async () => {
@@ -348,7 +391,7 @@ test('runReleaseConductor still blocks dry-run when the dwell window contains wo
assert.ok(report.decision.blockers.some((entry) => entry.code === 'green-dwell-failed'));
});
-test('runReleaseConductor creates signed tag when apply is enabled and signing key is available', async () => {
+test('runReleaseConductor creates and publishes a signed tag when apply is enabled and signing key is available', async () => {
const readJsonOptionalFn = async (filePath) => {
const normalized = String(filePath);
if (normalized.includes('queue-supervisor-report.json')) {
@@ -386,11 +429,36 @@ test('runReleaseConductor creates signed tag when apply is enabled and signing k
const runCommandFn = (command, args) => {
commandCalls.push({ command, args });
if (command === 'git' && args[0] === 'config') {
- return { status: 0, stdout: 'ABC123', stderr: '' };
+ if (args[2] === 'user.signingkey') {
+ return { status: 0, stdout: '/tmp/release-signing.pub', stderr: '' };
+ }
+ if (args[2] === 'gpg.format') {
+ return { status: 0, stdout: 'ssh', stderr: '' };
+ }
+ if (args[2] === 'remote.upstream.url') {
+ return { status: 0, stdout: 'https://github.com/owner/repo.git', stderr: '' };
+ }
+ return { status: 1, stdout: '', stderr: 'missing config' };
+ }
+ if (command === 'git' && args[0] === 'ls-remote') {
+ return {
+ status: 0,
+ stdout: [
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\trefs/tags/v0.8.0-rc.1',
+ 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\trefs/tags/v0.8.0-rc.1^{}'
+ ].join('\n'),
+ stderr: ''
+ };
+ }
+ if (command === 'git' && args[0] === 'rev-parse') {
+ return { status: 0, stdout: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n', stderr: '' };
}
if (command === 'git' && args[0] === 'tag') {
return { status: 0, stdout: '', stderr: '' };
}
+ if (command === 'git' && args[0] === 'push') {
+ return { status: 0, stdout: '', stderr: '' };
+ }
return { status: 0, stdout: '', stderr: '' };
};
@@ -425,10 +493,678 @@ test('runReleaseConductor creates signed tag when apply is enabled and signing k
assert.equal(report.decision.status, 'pass');
assert.equal(report.release.proposalOnly, false);
assert.equal(report.release.tagCreated, true);
+ assert.equal(report.release.tagPushed, true);
+ assert.equal(report.release.tagPushRemote.remoteName, 'upstream');
+ assert.equal(report.release.signingMaterial.backend, 'ssh');
+ assert.ok(commandCalls.some((entry) => entry.command === 'git' && entry.args[0] === 'tag'));
+ assert.ok(commandCalls.some((entry) => entry.command === 'git' && entry.args[0] === 'push'));
+});
+
+test('runReleaseConductor allows apply when queue pause is only an idle success-rate throttle', async () => {
+ const readJsonOptionalFn = async (filePath) => {
+ const normalized = String(filePath);
+ if (normalized.includes('queue-supervisor-report.json')) {
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ paused: true,
+ pausedReasons: ['success-rate-below-threshold'],
+ throughputController: { mode: 'stabilize' },
+ runtimeFleet: {
+ totals: {
+ queued: 0,
+ inProgress: 0,
+ stalled: 0
+ }
+ },
+ queueInventory: {
+ mergeQueueOccupancy: 0,
+ readyQueuedCount: 0
+ },
+ summary: {
+ quarantinedCount: 0
+ },
+ retryHistory: {}
+ }
+ };
+ }
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ schema: 'priority/policy-live-state@v1',
+ generatedAt: '2026-03-06T10:00:00Z',
+ state: {}
+ }
+ };
+ };
+
+ const runGhJsonFn = (args) => {
+ if (args[0] === 'api') {
+ return makeWorkflowRunsResponse(String(args[1]));
+ }
+ throw new Error(`unexpected gh args: ${args.join(' ')}`);
+ };
+
+ const commandCalls = [];
+ const runCommandFn = (command, args) => {
+ commandCalls.push({ command, args });
+ if (command === 'git' && args[0] === 'config') {
+ if (args[2] === 'user.signingkey') {
+ return { status: 0, stdout: '/tmp/release-signing.pub', stderr: '' };
+ }
+ if (args[2] === 'gpg.format') {
+ return { status: 0, stdout: 'ssh', stderr: '' };
+ }
+ if (args[2] === 'remote.upstream.url') {
+ return { status: 0, stdout: 'https://github.com/owner/repo.git', stderr: '' };
+ }
+ return { status: 1, stdout: '', stderr: 'missing config' };
+ }
+ if (command === 'git' && args[0] === 'tag') {
+ return { status: 0, stdout: '', stderr: '' };
+ }
+ if (command === 'git' && args[0] === 'push') {
+ return { status: 0, stdout: '', stderr: '' };
+ }
+ return { status: 0, stdout: '', stderr: '' };
+ };
+
+ const { report, exitCode } = await runReleaseConductor({
+ repoRoot: process.cwd(),
+ now: new Date('2026-03-06T12:00:00.000Z'),
+ args: {
+ apply: true,
+ dryRun: false,
+ repairExistingTag: false,
+ reportPath: 'tests/results/_agent/release/release-conductor-report.json',
+ queueReportPath: 'tests/results/_agent/queue/queue-supervisor-report.json',
+ policySnapshotPath: 'tests/results/_agent/policy/policy-state-snapshot.json',
+ repo: 'owner/repo',
+ stream: 'comparevi-cli',
+ channel: 'rc',
+ version: '0.8.0-rc.1',
+ dwellMinutes: 60,
+ quarantineStaleHours: 24,
+ help: false
+ },
+ environment: {
+ GITHUB_REPOSITORY: 'owner/repo',
+ RELEASE_CONDUCTOR_ENABLED: '1'
+ },
+ runGhJsonFn,
+ runCommandFn,
+ readJsonOptionalFn,
+ writeReportFn: async (reportPath) => reportPath
+ });
+
+ assert.equal(exitCode, 0);
+ assert.equal(report.gates.queueHealth.status, 'pass');
+ assert.deepEqual(report.gates.queueHealth.reasons, ['release-safe-idle-queue-pause']);
+ assert.equal(report.release.proposalOnly, false);
assert.ok(commandCalls.some((entry) => entry.command === 'git' && entry.args[0] === 'tag'));
+ assert.ok(commandCalls.some((entry) => entry.command === 'git' && entry.args[0] === 'push'));
+});
+
+test('runReleaseConductor blocks apply when authoritative tag already exists and repair mode is not requested', async () => {
+ const readJsonOptionalFn = async (filePath) => {
+ const normalized = String(filePath);
+ if (normalized.includes('queue-supervisor-report.json')) {
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ paused: false,
+ throughputController: { mode: 'healthy' },
+ retryHistory: {}
+ }
+ };
+ }
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ schema: 'priority/policy-live-state@v1',
+ generatedAt: '2026-03-06T10:00:00Z',
+ state: {}
+ }
+ };
+ };
+
+ const runGhJsonFn = (args) => {
+ if (args[0] === 'api') {
+ return makeWorkflowRunsResponse(String(args[1]));
+ }
+ throw new Error(`unexpected gh args: ${args.join(' ')}`);
+ };
+
+ const commandCalls = [];
+ const runCommandFn = (command, args) => {
+ commandCalls.push({ command, args });
+ if (command === 'git' && args[0] === 'config') {
+ if (args[2] === 'user.signingkey') {
+ return { status: 0, stdout: '/tmp/release-signing.pub', stderr: '' };
+ }
+ if (args[2] === 'gpg.format') {
+ return { status: 0, stdout: 'ssh', stderr: '' };
+ }
+ if (args[2] === 'remote.upstream.url') {
+ return { status: 0, stdout: 'https://github.com/owner/repo.git', stderr: '' };
+ }
+ return { status: 1, stdout: '', stderr: 'missing config' };
+ }
+ if (command === 'git' && args[0] === 'ls-remote') {
+ return {
+ status: 0,
+ stdout: [
+ '1111111111111111111111111111111111111111\trefs/tags/v0.8.0-rc.1',
+ '2222222222222222222222222222222222222222\trefs/tags/v0.8.0-rc.1^{}'
+ ].join('\n'),
+ stderr: ''
+ };
+ }
+ if (command === 'git' && args[0] === 'rev-parse') {
+ return { status: 1, stdout: '', stderr: '' };
+ }
+ return { status: 0, stdout: '', stderr: '' };
+ };
+
+ const { report, exitCode } = await runReleaseConductor({
+ repoRoot: process.cwd(),
+ now: new Date('2026-03-06T12:00:00.000Z'),
+ args: {
+ apply: true,
+ dryRun: false,
+ repairExistingTag: false,
+ reportPath: 'tests/results/_agent/release/release-conductor-report.json',
+ queueReportPath: 'tests/results/_agent/queue/queue-supervisor-report.json',
+ policySnapshotPath: 'tests/results/_agent/policy/policy-state-snapshot.json',
+ repo: 'owner/repo',
+ stream: 'comparevi-cli',
+ channel: 'rc',
+ version: '0.8.0-rc.1',
+ dwellMinutes: 60,
+ quarantineStaleHours: 24,
+ help: false
+ },
+ environment: {
+ GITHUB_REPOSITORY: 'owner/repo',
+ RELEASE_CONDUCTOR_ENABLED: '1'
+ },
+ runGhJsonFn,
+ runCommandFn,
+ readJsonOptionalFn,
+ writeReportFn: async (reportPath) => reportPath
+ });
+
+ assert.equal(exitCode, 1);
+ assert.equal(report.release.repair.status, 'repair-available');
+ assert.equal(report.release.repair.remoteTagExists, true);
+ assert.equal(report.release.repair.remoteTargetCommitOid, '2222222222222222222222222222222222222222');
+ assert.ok(report.decision.blockers.some((entry) => entry.code === 'existing-tag-requires-repair-mode'));
+ assert.equal(commandCalls.some((entry) => entry.command === 'git' && entry.args[0] === 'tag'), false);
+});
+
+test('runReleaseConductor reports a repair plan in dry-run for an existing authoritative tag', async () => {
+ const readJsonOptionalFn = async (filePath) => {
+ const normalized = String(filePath);
+ if (normalized.includes('queue-supervisor-report.json')) {
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ paused: false,
+ throughputController: { mode: 'healthy' },
+ retryHistory: {}
+ }
+ };
+ }
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ schema: 'priority/policy-live-state@v1',
+ generatedAt: '2026-03-06T10:00:00Z',
+ state: {}
+ }
+ };
+ };
+
+ const runGhJsonFn = (args) => {
+ if (args[0] === 'api') {
+ return makeWorkflowRunsResponse(String(args[1]));
+ }
+ throw new Error(`unexpected gh args: ${args.join(' ')}`);
+ };
+
+ const runCommandFn = (command, args) => {
+ if (command === 'git' && args[0] === 'config') {
+ if (args[2] === 'remote.upstream.url') {
+ return { status: 0, stdout: 'https://github.com/owner/repo.git', stderr: '' };
+ }
+ return { status: 1, stdout: '', stderr: 'missing config' };
+ }
+ if (command === 'git' && args[0] === 'ls-remote') {
+ return {
+ status: 0,
+ stdout: [
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\trefs/tags/v0.8.0-rc.1',
+ 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\trefs/tags/v0.8.0-rc.1^{}'
+ ].join('\n'),
+ stderr: ''
+ };
+ }
+ if (command === 'git' && args[0] === 'rev-parse') {
+ return { status: 0, stdout: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n', stderr: '' };
+ }
+ return { status: 0, stdout: '', stderr: '' };
+ };
+
+ const { report, exitCode } = await runReleaseConductor({
+ repoRoot: process.cwd(),
+ now: new Date('2026-03-06T12:00:00.000Z'),
+ args: {
+ apply: false,
+ dryRun: true,
+ repairExistingTag: true,
+ reportPath: 'tests/results/_agent/release/release-conductor-report.json',
+ queueReportPath: 'tests/results/_agent/queue/queue-supervisor-report.json',
+ policySnapshotPath: 'tests/results/_agent/policy/policy-state-snapshot.json',
+ repo: 'owner/repo',
+ stream: 'comparevi-cli',
+ channel: 'rc',
+ version: '0.8.0-rc.1',
+ dwellMinutes: 60,
+ quarantineStaleHours: 24,
+ help: false
+ },
+ environment: {
+ GITHUB_REPOSITORY: 'owner/repo',
+ RELEASE_CONDUCTOR_ENABLED: '0'
+ },
+ runGhJsonFn,
+ runCommandFn,
+ readJsonOptionalFn,
+ writeReportFn: async (reportPath) => reportPath
+ });
+
+ assert.equal(exitCode, 0);
+ assert.equal(report.decision.status, 'pass');
+ assert.equal(report.release.repair.requested, true);
+ assert.equal(report.release.repair.status, 'ready');
+ assert.equal(report.release.repair.remoteTagExists, true);
+ assert.equal(report.release.repair.remoteTagAnnotated, true);
+ assert.equal(report.release.repair.remoteTagObjectOid, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
+ assert.equal(report.release.repair.remoteTargetCommitOid, 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+ assert.equal(report.release.repair.localTagPresent, true);
+ assert.equal(report.release.proposalOnly, true);
});
-test('runReleaseConductor stays proposal-only when signing material is unavailable', async () => {
+test('runReleaseConductor repairs an existing authoritative tag when repair mode is enabled', async () => {
+ const readJsonOptionalFn = async (filePath) => {
+ const normalized = String(filePath);
+ if (normalized.includes('queue-supervisor-report.json')) {
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ paused: false,
+ throughputController: { mode: 'healthy' },
+ retryHistory: {}
+ }
+ };
+ }
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ schema: 'priority/policy-live-state@v1',
+ generatedAt: '2026-03-06T10:00:00Z',
+ state: {}
+ }
+ };
+ };
+
+ const runGhJsonFn = (args) => {
+ if (args[0] === 'api') {
+ return makeWorkflowRunsResponse(String(args[1]));
+ }
+ throw new Error(`unexpected gh args: ${args.join(' ')}`);
+ };
+
+ const commandCalls = [];
+ const runCommandFn = (command, args) => {
+ commandCalls.push({ command, args });
+ if (command === 'git' && args[0] === 'config') {
+ if (args[2] === 'user.signingkey') {
+ return { status: 0, stdout: '/tmp/release-signing.pub', stderr: '' };
+ }
+ if (args[2] === 'gpg.format') {
+ return { status: 0, stdout: 'ssh', stderr: '' };
+ }
+ if (args[2] === 'remote.upstream.url') {
+ return { status: 0, stdout: 'https://github.com/owner/repo.git', stderr: '' };
+ }
+ return { status: 1, stdout: '', stderr: 'missing config' };
+ }
+ if (command === 'git' && args[0] === 'ls-remote') {
+ return {
+ status: 0,
+ stdout: [
+ '1111111111111111111111111111111111111111\trefs/tags/v0.8.0-rc.1',
+ '2222222222222222222222222222222222222222\trefs/tags/v0.8.0-rc.1^{}'
+ ].join('\n'),
+ stderr: ''
+ };
+ }
+ if (command === 'git' && args[0] === 'rev-parse') {
+ return { status: 0, stdout: '1111111111111111111111111111111111111111\n', stderr: '' };
+ }
+ if (command === 'git' && args[0] === 'tag' && args[1] === '-d') {
+ return { status: 0, stdout: `Deleted tag '${args[2]}'`, stderr: '' };
+ }
+ if (command === 'git' && args[0] === 'tag') {
+ return { status: 0, stdout: '', stderr: '' };
+ }
+ if (command === 'git' && args[0] === 'push') {
+ return { status: 0, stdout: '', stderr: '' };
+ }
+ return { status: 0, stdout: '', stderr: '' };
+ };
+
+ const { report, exitCode } = await runReleaseConductor({
+ repoRoot: process.cwd(),
+ now: new Date('2026-03-06T12:00:00.000Z'),
+ args: {
+ apply: true,
+ dryRun: false,
+ repairExistingTag: true,
+ reportPath: 'tests/results/_agent/release/release-conductor-report.json',
+ queueReportPath: 'tests/results/_agent/queue/queue-supervisor-report.json',
+ policySnapshotPath: 'tests/results/_agent/policy/policy-state-snapshot.json',
+ repo: 'owner/repo',
+ stream: 'comparevi-cli',
+ channel: 'rc',
+ version: '0.8.0-rc.1',
+ dwellMinutes: 60,
+ quarantineStaleHours: 24,
+ help: false
+ },
+ environment: {
+ GITHUB_REPOSITORY: 'owner/repo',
+ RELEASE_CONDUCTOR_ENABLED: '1'
+ },
+ runGhJsonFn,
+ runCommandFn,
+ readJsonOptionalFn,
+ writeReportFn: async (reportPath) => reportPath
+ });
+
+ assert.equal(exitCode, 0);
+ assert.equal(report.decision.status, 'pass');
+ assert.equal(report.release.proposalOnly, false);
+ assert.equal(report.release.tagCreated, true);
+ assert.equal(report.release.tagPushed, true);
+ assert.equal(report.release.repair.status, 'repaired');
+ assert.equal(report.release.repair.localTagDeleted, true);
+ assert.equal(report.release.repair.tagRecreated, true);
+ assert.equal(report.release.publicationReplay.requested, true);
+ assert.equal(report.release.publicationReplay.status, 'dispatched');
+ assert.equal(report.release.publicationReplay.dispatched, true);
+ assert.equal(report.release.publicationReplay.ref, 'develop');
+ assert.equal(report.release.publicationReplay.tagInputName, 'release_tag');
+ assert.equal(report.release.publicationReplay.tagInputValue, 'v0.8.0-rc.1');
+ assert.equal(
+ commandCalls.some(
+ (entry) =>
+ entry.command === 'git' &&
+ entry.args[0] === 'push' &&
+ entry.args[1] === '--force-with-lease=refs/tags/v0.8.0-rc.1:1111111111111111111111111111111111111111'
+ ),
+ true
+ );
+ assert.equal(
+ commandCalls.some(
+ (entry) =>
+ entry.command === 'git' &&
+ entry.args[0] === 'tag' &&
+ entry.args[1] === '-s' &&
+ entry.args[2] === '-f' &&
+ entry.args[3] === 'v0.8.0-rc.1' &&
+ entry.args[4] === '2222222222222222222222222222222222222222'
+ ),
+ true
+ );
+ assert.equal(
+ commandCalls.some(
+ (entry) =>
+ entry.command === 'gh' &&
+ entry.args[0] === 'workflow' &&
+ entry.args[1] === 'run' &&
+ entry.args[2] === 'release.yml' &&
+ entry.args[3] === '--ref' &&
+ entry.args[4] === 'develop' &&
+ entry.args[5] === '-f' &&
+ entry.args[6] === 'release_tag=v0.8.0-rc.1'
+ ),
+ true
+ );
+});
+
+test('runReleaseConductor fails apply when repaired tag publication replay dispatch fails', async () => {
+ const readJsonOptionalFn = async (filePath) => {
+ const normalized = String(filePath);
+ if (normalized.includes('queue-supervisor-report.json')) {
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ paused: false,
+ throughputController: { mode: 'healthy' },
+ retryHistory: {}
+ }
+ };
+ }
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ schema: 'priority/policy-live-state@v1',
+ generatedAt: '2026-03-06T10:00:00Z',
+ state: {}
+ }
+ };
+ };
+
+ const runGhJsonFn = (args) => {
+ if (args[0] === 'api') {
+ return makeWorkflowRunsResponse(String(args[1]));
+ }
+ throw new Error(`unexpected gh args: ${args.join(' ')}`);
+ };
+
+ const runCommandFn = (command, args) => {
+ if (command === 'git' && args[0] === 'config') {
+ if (args[2] === 'user.signingkey') {
+ return { status: 0, stdout: '/tmp/release-signing.pub', stderr: '' };
+ }
+ if (args[2] === 'gpg.format') {
+ return { status: 0, stdout: 'ssh', stderr: '' };
+ }
+ if (args[2] === 'remote.upstream.url') {
+ return { status: 0, stdout: 'https://github.com/owner/repo.git', stderr: '' };
+ }
+ return { status: 1, stdout: '', stderr: 'missing config' };
+ }
+ if (command === 'git' && args[0] === 'ls-remote') {
+ return {
+ status: 0,
+ stdout: [
+ '1111111111111111111111111111111111111111\trefs/tags/v0.8.0-rc.1',
+ '2222222222222222222222222222222222222222\trefs/tags/v0.8.0-rc.1^{}'
+ ].join('\n'),
+ stderr: ''
+ };
+ }
+ if (command === 'git' && args[0] === 'rev-parse') {
+ return { status: 0, stdout: '1111111111111111111111111111111111111111\n', stderr: '' };
+ }
+ if (command === 'git' && args[0] === 'tag' && args[1] === '-d') {
+ return { status: 0, stdout: `Deleted tag '${args[2]}'`, stderr: '' };
+ }
+ if (command === 'git' && args[0] === 'tag') {
+ return { status: 0, stdout: '', stderr: '' };
+ }
+ if (command === 'git' && args[0] === 'push') {
+ return { status: 0, stdout: '', stderr: '' };
+ }
+ if (command === 'gh' && args[0] === 'workflow' && args[1] === 'run') {
+ return { status: 1, stdout: '', stderr: 'dispatch denied' };
+ }
+ return { status: 0, stdout: '', stderr: '' };
+ };
+
+ const { report, exitCode } = await runReleaseConductor({
+ repoRoot: process.cwd(),
+ now: new Date('2026-03-06T12:00:00.000Z'),
+ args: {
+ apply: true,
+ dryRun: false,
+ repairExistingTag: true,
+ reportPath: 'tests/results/_agent/release/release-conductor-report.json',
+ queueReportPath: 'tests/results/_agent/queue/queue-supervisor-report.json',
+ policySnapshotPath: 'tests/results/_agent/policy/policy-state-snapshot.json',
+ repo: 'owner/repo',
+ stream: 'comparevi-cli',
+ channel: 'rc',
+ version: '0.8.0-rc.1',
+ dwellMinutes: 60,
+ quarantineStaleHours: 24,
+ help: false
+ },
+ environment: {
+ GITHUB_REPOSITORY: 'owner/repo',
+ RELEASE_CONDUCTOR_ENABLED: '1'
+ },
+ runGhJsonFn,
+ runCommandFn,
+ readJsonOptionalFn,
+ writeReportFn: async (reportPath) => reportPath
+ });
+
+ assert.equal(exitCode, 1);
+ assert.equal(report.decision.status, 'fail');
+ assert.equal(report.release.repair.status, 'repaired');
+ assert.equal(report.release.publicationReplay.requested, true);
+ assert.equal(report.release.publicationReplay.status, 'dispatch-failed');
+ assert.equal(report.release.publicationReplay.dispatched, false);
+ assert.equal(report.release.publicationReplay.ref, 'develop');
+ assert.equal(report.release.publicationReplay.tagInputName, 'release_tag');
+ assert.equal(report.release.publicationReplay.tagInputValue, 'v0.8.0-rc.1');
+ assert.equal(report.release.publicationReplay.error, 'dispatch denied');
+ assert.ok(report.decision.blockers.some((entry) => entry.code === 'release-replay-dispatch-failed'));
+});
+
+test('runReleaseConductor fails apply when signed tag push remote is unavailable', async () => {
+ const readJsonOptionalFn = async (filePath) => {
+ const normalized = String(filePath);
+ if (normalized.includes('queue-supervisor-report.json')) {
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ paused: false,
+ throughputController: { mode: 'healthy' },
+ retryHistory: {}
+ }
+ };
+ }
+ return {
+ exists: true,
+ error: null,
+ path: filePath,
+ payload: {
+ schema: 'priority/policy-live-state@v1',
+ generatedAt: '2026-03-06T10:00:00Z',
+ state: {}
+ }
+ };
+ };
+
+ const runGhJsonFn = (args) => {
+ if (args[0] === 'api') {
+ return makeWorkflowRunsResponse(String(args[1]));
+ }
+ throw new Error(`unexpected gh args: ${args.join(' ')}`);
+ };
+
+ const commandCalls = [];
+ const runCommandFn = (command, args) => {
+ commandCalls.push({ command, args });
+ if (command === 'git' && args[0] === 'config') {
+ if (args[2] === 'user.signingkey') {
+ return { status: 0, stdout: '/tmp/release-signing.pub', stderr: '' };
+ }
+ if (args[2] === 'gpg.format') {
+ return { status: 0, stdout: 'ssh', stderr: '' };
+ }
+ return { status: 1, stdout: '', stderr: 'missing config' };
+ }
+ if (command === 'git' && args[0] === 'tag') {
+ return { status: 0, stdout: '', stderr: '' };
+ }
+ return { status: 0, stdout: '', stderr: '' };
+ };
+
+ const { report, exitCode } = await runReleaseConductor({
+ repoRoot: process.cwd(),
+ now: new Date('2026-03-06T12:00:00.000Z'),
+ args: {
+ apply: true,
+ dryRun: false,
+ reportPath: 'tests/results/_agent/release/release-conductor-report.json',
+ queueReportPath: 'tests/results/_agent/queue/queue-supervisor-report.json',
+ policySnapshotPath: 'tests/results/_agent/policy/policy-state-snapshot.json',
+ repo: 'owner/repo',
+ stream: 'comparevi-cli',
+ channel: 'stable',
+ version: '0.8.0',
+ dwellMinutes: 60,
+ quarantineStaleHours: 24,
+ help: false
+ },
+ environment: {
+ GITHUB_REPOSITORY: 'owner/repo',
+ RELEASE_CONDUCTOR_ENABLED: '1'
+ },
+ runGhJsonFn,
+ runCommandFn,
+ readJsonOptionalFn,
+ writeReportFn: async (reportPath) => reportPath
+ });
+
+ assert.equal(exitCode, 1);
+ assert.equal(report.decision.status, 'fail');
+ assert.equal(report.release.tagCreated, true);
+ assert.equal(report.release.tagPushed, false);
+ assert.equal(report.release.tagPushRemote.remoteName, null);
+ assert.ok(report.decision.blockers.some((entry) => entry.code === 'tag-push-remote-missing'));
+ assert.equal(commandCalls.some((entry) => entry.command === 'git' && entry.args[0] === 'push'), false);
+});
+
+test('runReleaseConductor blocks apply when signing material is unavailable', async () => {
const readJsonOptionalFn = async (filePath) => {
const normalized = String(filePath);
if (normalized.includes('queue-supervisor-report.json')) {
@@ -498,9 +1234,11 @@ test('runReleaseConductor stays proposal-only when signing material is unavailab
writeReportFn: async (reportPath) => reportPath
});
- assert.equal(exitCode, 0);
- assert.equal(report.decision.status, 'pass');
+ assert.equal(exitCode, 1);
+ assert.equal(report.decision.status, 'fail');
assert.equal(report.release.proposalOnly, true);
assert.equal(report.release.tagCreated, false);
+ assert.equal(report.release.signingMaterial.available, false);
+ assert.ok(report.decision.blockers.some((entry) => entry.code === 'tag-signing-material-missing'));
assert.equal(commandCalls.some((entry) => entry.command === 'git' && entry.args[0] === 'tag'), false);
});
diff --git a/tools/priority/__tests__/release-published-bundle-observer-schema.test.mjs b/tools/priority/__tests__/release-published-bundle-observer-schema.test.mjs
new file mode 100644
index 000000000..e6100b50b
--- /dev/null
+++ b/tools/priority/__tests__/release-published-bundle-observer-schema.test.mjs
@@ -0,0 +1,140 @@
+import assert from 'node:assert/strict';
+import { execFileSync } from 'node:child_process';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { fileURLToPath } from 'node:url';
+
+import { runReleasePublishedBundleObserver } from '../release-published-bundle-observer.mjs';
+
+function toGlobPath(filePath) {
+ return path.resolve(filePath).replace(/\\/g, '/');
+}
+
+function resolveValidatorRepoRoot(repoRoot) {
+ const localValidatorOk =
+ fs.existsSync(path.join(repoRoot, 'dist', 'tools', 'schemas', 'validate-json.js')) &&
+ fs.existsSync(path.join(repoRoot, 'node_modules', 'ajv', 'package.json')) &&
+ fs.existsSync(path.join(repoRoot, 'node_modules', 'argparse', 'package.json'));
+ if (localValidatorOk) {
+ return repoRoot;
+ }
+ const candidates = [
+ path.resolve(repoRoot, '..', 'compare-monitoring-canonical'),
+ path.resolve(repoRoot, '..', '1843-wake-lifecycle-state-machine')
+ ];
+ return (
+ candidates.find(
+ (candidate) =>
+ fs.existsSync(path.join(candidate, 'dist', 'tools', 'schemas', 'validate-json.js')) &&
+ fs.existsSync(path.join(candidate, 'node_modules', 'ajv', 'package.json')) &&
+ fs.existsSync(path.join(candidate, 'node_modules', 'argparse', 'package.json'))
+ ) || repoRoot
+ );
+}
+
+function runSchemaValidate(repoRoot, schemaPath, dataPath) {
+ const validatorRepoRoot = resolveValidatorRepoRoot(repoRoot);
+ execFileSync('node', ['dist/tools/schemas/validate-json.js', '--schema', toGlobPath(schemaPath), '--data', toGlobPath(dataPath)], {
+ cwd: validatorRepoRoot,
+ stdio: 'pipe'
+ });
+}
+
+function writeJson(filePath, payload) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+test('release published bundle observer report matches schema', async () => {
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'release-published-bundle-observer-schema-'));
+ const bundleRoot = path.join(tmpDir, 'bundle', 'CompareVI.Tools-v0.6.4-rc.1');
+ const archivePath = path.join(tmpDir, 'download', 'CompareVI.Tools-v0.6.4-rc.1.zip');
+
+ fs.mkdirSync(path.join(bundleRoot, 'tools', 'CompareVI.Tools'), { recursive: true });
+ fs.mkdirSync(path.dirname(archivePath), { recursive: true });
+ fs.writeFileSync(archivePath, 'zip-placeholder', 'utf8');
+ fs.writeFileSync(path.join(bundleRoot, 'tools', 'CompareVI.Tools', 'CompareVI.Tools.psd1'), '@{}', 'utf8');
+ writeJson(path.join(bundleRoot, 'comparevi-tools-release.json'), {
+ schema: 'comparevi-tools-release-manifest@v1',
+ versionContract: {
+ authoritativeConsumerPin: '0.6.4-rc.1',
+ authoritativeConsumerPinKind: 'release-version'
+ },
+ consumerContract: {
+ historyFacade: { schema: 'comparevi-tools/history-facade@v1' },
+ localRuntimeProfiles: { schema: 'comparevi-tools/runtime-profiles@v1' },
+ localOperatorSession: { schema: 'comparevi-tools/local-operator-session@v1' },
+ diagnosticsCommentRenderer: { schema: 'comparevi-tools/diagnostics-comment-renderer@v1' },
+ hostedNiLinuxRunner: { schema: 'comparevi-tools/hosted-ni-linux-runner@v1' },
+ dockerImageContract: {
+ schema: 'comparevi-tools/docker-image-contract@v1',
+ images: {
+ hostedNiLinuxRunner: {
+ imageRef: 'nationalinstruments/labview:2026q1-linux'
+ }
+ }
+ },
+ capabilities: {
+ viHistory: {
+ schema: 'comparevi-tools/vi-history-capability@v1',
+ capabilityId: 'vi-history',
+ distributionRole: 'upstream-producer',
+ distributionModel: 'release-bundle',
+ bundleImportPath: 'tools/CompareVI.Tools/CompareVI.Tools.psd1',
+ releaseAssetPattern: 'CompareVI.Tools-v.zip',
+ contractPaths: {
+ historyFacade: 'consumerContract.historyFacade',
+ localRuntimeProfiles: 'consumerContract.localRuntimeProfiles',
+ localOperatorSession: 'consumerContract.localOperatorSession',
+ diagnosticsCommentRenderer: 'consumerContract.diagnosticsCommentRenderer',
+ hostedNiLinuxRunner: 'consumerContract.hostedNiLinuxRunner'
+ }
+ },
+ dockerProfile: {
+ schema: 'comparevi-tools/docker-profile-capability@v1',
+ capabilityId: 'docker-profile',
+ distributionRole: 'upstream-producer',
+ distributionModel: 'release-bundle',
+ bundleImportPath: 'tools/CompareVI.Tools/CompareVI.Tools.psd1',
+ releaseAssetPattern: 'CompareVI.Tools-v.zip',
+ authoritativeImageContractSource: 'consumerContract.dockerImageContract'
+ }
+ }
+ }
+ });
+
+ const outputPath = path.join(tmpDir, 'tests', 'results', '_agent', 'release', 'release-published-bundle-observer.json');
+ const { report } = await runReleasePublishedBundleObserver(
+ {
+ repoRoot: tmpDir,
+ repo: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ outputPath
+ },
+ {
+ now: new Date('2026-03-23T19:19:00Z'),
+ runGhJsonFn: () => [
+ {
+ id: 70,
+ tag_name: 'v0.6.4-rc.1',
+ name: 'v0.6.4-rc.1',
+ draft: false,
+ prerelease: true,
+ published_at: '2026-03-23T19:12:00Z',
+ assets: [{ name: 'CompareVI.Tools-v0.6.4-rc.1.zip', id: 71 }]
+ }
+ ],
+ downloadAssetFn: () => archivePath,
+ extractArchiveFn: () => bundleRoot
+ }
+ );
+
+ runSchemaValidate(
+ repoRoot,
+ path.join(repoRoot, 'docs', 'schemas', 'release-published-bundle-observer-report-v1.schema.json'),
+ outputPath
+ );
+ assert.equal(report.schema, 'priority/release-published-bundle-observer-report@v1');
+});
diff --git a/tools/priority/__tests__/release-published-bundle-observer.test.mjs b/tools/priority/__tests__/release-published-bundle-observer.test.mjs
new file mode 100644
index 000000000..9b5b0a85e
--- /dev/null
+++ b/tools/priority/__tests__/release-published-bundle-observer.test.mjs
@@ -0,0 +1,228 @@
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import {
+ DEFAULT_OUTPUT_PATH,
+ DEFAULT_RESULTS_DIR,
+ parseArgs,
+ runReleasePublishedBundleObserver
+} from '../release-published-bundle-observer.mjs';
+
+function writeJson(filePath, payload) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+test('parseArgs keeps defaults and accepts overrides', () => {
+ const parsed = parseArgs([
+ 'node',
+ 'release-published-bundle-observer.mjs',
+ '--repo-root',
+ 'C:/repo',
+ '--repo',
+ 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ '--tag',
+ 'v0.6.4-rc.1',
+ '--output',
+ 'custom/published-bundle.json',
+ '--results-dir',
+ 'custom/results'
+ ]);
+
+ assert.equal(parsed.repoRoot, 'C:/repo');
+ assert.equal(parsed.repo, 'LabVIEW-Community-CI-CD/compare-vi-cli-action');
+ assert.equal(parsed.tag, 'v0.6.4-rc.1');
+ assert.equal(parsed.outputPath, 'custom/published-bundle.json');
+ assert.equal(parsed.resultsDir, 'custom/results');
+ assert.equal(DEFAULT_OUTPUT_PATH, path.join('tests', 'results', '_agent', 'release', 'release-published-bundle-observer.json'));
+ assert.equal(DEFAULT_RESULTS_DIR, path.join('tests', 'results', '_agent', 'release', 'published-bundle-observer'));
+});
+
+test('runReleasePublishedBundleObserver reports release-unobserved when no published releases exist', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'published-bundle-observer-empty-'));
+
+ const result = await runReleasePublishedBundleObserver(
+ {
+ repoRoot,
+ repo: 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ },
+ {
+ now: new Date('2026-03-23T19:15:00Z'),
+ runGhJsonFn: () => []
+ }
+ );
+
+ assert.equal(result.exitCode, 1);
+ assert.equal(result.report.selection.status, 'release-unobserved');
+ assert.equal(result.report.summary.status, 'release-unobserved');
+});
+
+test('runReleasePublishedBundleObserver reports asset-missing when the release lacks CompareVI.Tools bundle', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'published-bundle-observer-asset-missing-'));
+
+ const result = await runReleasePublishedBundleObserver(
+ {
+ repoRoot,
+ repo: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ tag: 'v0.6.4-rc.1'
+ },
+ {
+ now: new Date('2026-03-23T19:16:00Z'),
+ runGhJsonFn: () => [
+ {
+ tag_name: 'v0.6.4-rc.1',
+ published_at: '2026-03-23T19:10:00Z',
+ assets: [{ name: 'comparevi-cli-v0.6.4-rc.1.zip', id: 11 }]
+ }
+ ]
+ }
+ );
+
+ assert.equal(result.exitCode, 1);
+ assert.equal(result.report.selection.status, 'asset-missing');
+ assert.equal(result.report.summary.status, 'asset-missing');
+ assert.equal(result.report.selection.releaseTag, 'v0.6.4-rc.1');
+});
+
+test('runReleasePublishedBundleObserver certifies producer-native-ready bundle metadata from the published asset', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'published-bundle-observer-pass-'));
+ const bundleRoot = path.join(repoRoot, 'tmp', 'bundle', 'CompareVI.Tools-v0.6.4-rc.1');
+ const archivePath = path.join(repoRoot, 'tmp', 'download', 'CompareVI.Tools-v0.6.4-rc.1.zip');
+ fs.mkdirSync(path.join(bundleRoot, 'tools', 'CompareVI.Tools'), { recursive: true });
+ fs.mkdirSync(path.dirname(archivePath), { recursive: true });
+ fs.writeFileSync(archivePath, 'zip-placeholder', 'utf8');
+ fs.writeFileSync(path.join(bundleRoot, 'tools', 'CompareVI.Tools', 'CompareVI.Tools.psd1'), '@{}', 'utf8');
+ writeJson(path.join(bundleRoot, 'comparevi-tools-release.json'), {
+ schema: 'comparevi-tools-release-manifest@v1',
+ versionContract: {
+ authoritativeConsumerPin: '0.6.4-rc.1',
+ authoritativeConsumerPinKind: 'release-version'
+ },
+ consumerContract: {
+ historyFacade: { schema: 'comparevi-tools/history-facade@v1' },
+ localRuntimeProfiles: { schema: 'comparevi-tools/runtime-profiles@v1' },
+ localOperatorSession: { schema: 'comparevi-tools/local-operator-session@v1' },
+ diagnosticsCommentRenderer: { schema: 'comparevi-tools/diagnostics-comment-renderer@v1' },
+ hostedNiLinuxRunner: { schema: 'comparevi-tools/hosted-ni-linux-runner@v1' },
+ dockerImageContract: {
+ schema: 'comparevi-tools/docker-image-contract@v1',
+ images: {
+ hostedNiLinuxRunner: {
+ imageRef: 'nationalinstruments/labview:2026q1-linux'
+ }
+ }
+ },
+ capabilities: {
+ viHistory: {
+ schema: 'comparevi-tools/vi-history-capability@v1',
+ capabilityId: 'vi-history',
+ distributionRole: 'upstream-producer',
+ distributionModel: 'release-bundle',
+ bundleImportPath: 'tools/CompareVI.Tools/CompareVI.Tools.psd1',
+ releaseAssetPattern: 'CompareVI.Tools-v.zip',
+ contractPaths: {
+ historyFacade: 'consumerContract.historyFacade',
+ localRuntimeProfiles: 'consumerContract.localRuntimeProfiles',
+ localOperatorSession: 'consumerContract.localOperatorSession',
+ diagnosticsCommentRenderer: 'consumerContract.diagnosticsCommentRenderer',
+ hostedNiLinuxRunner: 'consumerContract.hostedNiLinuxRunner'
+ }
+ },
+ dockerProfile: {
+ schema: 'comparevi-tools/docker-profile-capability@v1',
+ capabilityId: 'docker-profile',
+ distributionRole: 'upstream-producer',
+ distributionModel: 'release-bundle',
+ bundleImportPath: 'tools/CompareVI.Tools/CompareVI.Tools.psd1',
+ releaseAssetPattern: 'CompareVI.Tools-v.zip',
+ authoritativeImageContractSource: 'consumerContract.dockerImageContract'
+ }
+ }
+ }
+ });
+
+ const result = await runReleasePublishedBundleObserver(
+ {
+ repoRoot,
+ repo: 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ },
+ {
+ now: new Date('2026-03-23T19:17:00Z'),
+ runGhJsonFn: () => [
+ {
+ id: 55,
+ tag_name: 'v0.6.4-rc.1',
+ name: 'v0.6.4-rc.1',
+ draft: false,
+ prerelease: true,
+ published_at: '2026-03-23T19:12:00Z',
+ assets: [{ name: 'CompareVI.Tools-v0.6.4-rc.1.zip', id: 77 }]
+ }
+ ],
+ downloadAssetFn: () => archivePath,
+ extractArchiveFn: () => bundleRoot
+ }
+ );
+
+ assert.equal(result.exitCode, 0);
+ assert.equal(result.report.selection.status, 'selected');
+ assert.equal(result.report.bundle.status, 'extracted');
+ assert.equal(result.report.bundleContract.status, 'producer-native-ready');
+ assert.equal(result.report.bundleContract.authoritativeConsumerPin, '0.6.4-rc.1');
+ assert.equal(result.report.bundleContract.viHistoryCapabilityPresent, true);
+ assert.equal(result.report.bundleContract.dockerProfileCapabilityPresent, true);
+ assert.equal(result.report.bundleContract.authoritativeImageContractSource, 'consumerContract.dockerImageContract');
+ assert.equal(result.report.bundleContract.authoritativeImageContractSourceResolved, true);
+ assert.equal(result.report.bundleContract.dockerImageContractSchema, 'comparevi-tools/docker-image-contract@v1');
+ assert.equal(result.report.summary.status, 'producer-native-ready');
+});
+
+test('runReleasePublishedBundleObserver reports producer-native-incomplete when vi-history capability is missing from published metadata', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'published-bundle-observer-incomplete-'));
+ const bundleRoot = path.join(repoRoot, 'tmp', 'bundle', 'CompareVI.Tools-v0.6.3-tools.14');
+ const archivePath = path.join(repoRoot, 'tmp', 'download', 'CompareVI.Tools-v0.6.3-tools.14.zip');
+ fs.mkdirSync(bundleRoot, { recursive: true });
+ fs.mkdirSync(path.dirname(archivePath), { recursive: true });
+ fs.writeFileSync(archivePath, 'zip-placeholder', 'utf8');
+ writeJson(path.join(bundleRoot, 'comparevi-tools-release.json'), {
+ schema: 'comparevi-tools-release-manifest@v1',
+ versionContract: {
+ authoritativeConsumerPin: 'v0.6.3-tools.14',
+ authoritativeConsumerPinKind: 'release-tag'
+ },
+ consumerContract: {
+ historyFacade: { schema: 'comparevi-tools/history-facade@v1' },
+ capabilities: {}
+ }
+ });
+
+ const result = await runReleasePublishedBundleObserver(
+ {
+ repoRoot,
+ repo: 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ },
+ {
+ now: new Date('2026-03-23T19:18:00Z'),
+ runGhJsonFn: () => [
+ {
+ id: 56,
+ tag_name: 'v0.6.3',
+ draft: false,
+ prerelease: false,
+ published_at: '2026-03-21T19:12:00Z',
+ assets: [{ name: 'CompareVI.Tools-v0.6.3-tools.14.zip', id: 88 }]
+ }
+ ],
+ downloadAssetFn: () => archivePath,
+ extractArchiveFn: () => bundleRoot
+ }
+ );
+
+ assert.equal(result.exitCode, 1);
+ assert.equal(result.report.bundleContract.status, 'producer-native-incomplete');
+ assert.equal(result.report.bundleContract.viHistoryCapabilityPresent, false);
+ assert.equal(result.report.summary.status, 'producer-native-incomplete');
+});
diff --git a/tools/priority/__tests__/release-signing-readiness-schema.test.mjs b/tools/priority/__tests__/release-signing-readiness-schema.test.mjs
new file mode 100644
index 000000000..e4328a285
--- /dev/null
+++ b/tools/priority/__tests__/release-signing-readiness-schema.test.mjs
@@ -0,0 +1,101 @@
+import assert from 'node:assert/strict';
+import { execFileSync } from 'node:child_process';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { fileURLToPath } from 'node:url';
+
+import { runReleaseSigningReadiness } from '../release-signing-readiness.mjs';
+
+function toGlobPath(filePath) {
+ return path.resolve(filePath).replace(/\\/g, '/');
+}
+
+function resolveValidatorRepoRoot(repoRoot) {
+ const localValidatorOk =
+ fs.existsSync(path.join(repoRoot, 'dist', 'tools', 'schemas', 'validate-json.js')) &&
+ fs.existsSync(path.join(repoRoot, 'node_modules', 'ajv', 'package.json')) &&
+ fs.existsSync(path.join(repoRoot, 'node_modules', 'argparse', 'package.json'));
+ if (localValidatorOk) {
+ return repoRoot;
+ }
+ const candidates = [
+ path.resolve(repoRoot, '..', 'compare-monitoring-canonical'),
+ path.resolve(repoRoot, '..', '1843-wake-lifecycle-state-machine')
+ ];
+ return (
+ candidates.find(
+ (candidate) =>
+ fs.existsSync(path.join(candidate, 'dist', 'tools', 'schemas', 'validate-json.js')) &&
+ fs.existsSync(path.join(candidate, 'node_modules', 'ajv', 'package.json')) &&
+ fs.existsSync(path.join(candidate, 'node_modules', 'argparse', 'package.json'))
+ ) || repoRoot
+ );
+}
+
+function runSchemaValidate(repoRoot, schemaPath, dataPath) {
+ const validatorRepoRoot = resolveValidatorRepoRoot(repoRoot);
+ execFileSync('node', ['dist/tools/schemas/validate-json.js', '--schema', toGlobPath(schemaPath), '--data', toGlobPath(dataPath)], {
+ cwd: validatorRepoRoot,
+ stdio: 'pipe'
+ });
+}
+
+function writeText(filePath, content) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, content, 'utf8');
+}
+
+test('release signing readiness report matches schema', async () => {
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'release-signing-readiness-schema-'));
+
+ writeText(
+ path.join(tmpDir, '.github', 'workflows', 'release-conductor.yml'),
+ [
+ 'name: release-conductor',
+ 'jobs:',
+ ' release:',
+ ' steps:',
+ ' - name: Configure release tag signing material',
+ ' run: |',
+ ' echo RELEASE_TAG_SIGNING_PRIVATE_KEY',
+ ' echo RELEASE_TAG_SIGNING_IDENTITY_NAME',
+ ' echo RELEASE_TAG_SIGNING_IDENTITY_EMAIL',
+ " signing_login=\"$(gh api user --jq '.login')\"",
+ ' git config gpg.format ssh',
+ ' git config user.signingkey "$public_key_path"',
+ ' git config user.name "$signing_name"',
+ ' git config user.email "$signing_email"'
+ ].join('\n')
+ );
+
+ const outputPath = path.join(tmpDir, 'tests', 'results', '_agent', 'release', 'release-signing-readiness.json');
+ const { report } = await runReleaseSigningReadiness(
+ {
+ repoRoot: tmpDir,
+ repo: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ outputPath
+ },
+ {
+ now: new Date('2026-03-23T17:30:00Z'),
+ runGhJsonFn: (args) => {
+ const endpoint = args[1] ?? '';
+ if (endpoint.includes('/actions/secrets')) {
+ return { secrets: [{ name: 'RELEASE_TAG_SIGNING_PRIVATE_KEY' }] };
+ }
+ if (endpoint.includes('/actions/variables')) {
+ return { variables: [{ name: 'RELEASE_CONDUCTOR_ENABLED', value: '1' }] };
+ }
+ if (endpoint.startsWith('user/ssh_signing_keys')) {
+ return [{ id: 1, title: 'compare-release-signing' }];
+ }
+ throw new Error(`Unexpected endpoint: ${endpoint}`);
+ }
+ }
+ );
+
+ runSchemaValidate(repoRoot, path.join(repoRoot, 'docs', 'schemas', 'release-signing-readiness-report-v1.schema.json'), outputPath);
+ assert.equal(report.schema, 'priority/release-signing-readiness-report@v1');
+});
diff --git a/tools/priority/__tests__/release-signing-readiness.test.mjs b/tools/priority/__tests__/release-signing-readiness.test.mjs
new file mode 100644
index 000000000..3e89cf875
--- /dev/null
+++ b/tools/priority/__tests__/release-signing-readiness.test.mjs
@@ -0,0 +1,259 @@
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import {
+ DEFAULT_OUTPUT_PATH,
+ DEFAULT_RELEASE_CONDUCTOR_REPORT_PATH,
+ DEFAULT_RELEASE_PUBLISHED_BUNDLE_OBSERVER_PATH,
+ parseArgs,
+ REQUIRED_SIGNING_SECRET,
+ OPTIONAL_SIGNING_SECRET,
+ runReleaseSigningReadiness
+} from '../release-signing-readiness.mjs';
+
+function writeText(filePath, content) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, content, 'utf8');
+}
+
+function writeJson(filePath, payload) {
+ writeText(filePath, `${JSON.stringify(payload, null, 2)}\n`);
+}
+
+function createPublishedBundleObserver(overrides = {}) {
+ return {
+ schema: 'priority/release-published-bundle-observer-report@v1',
+ generatedAt: '2026-03-23T17:19:30Z',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ inputs: {
+ requestedTag: null,
+ resultsDir: 'tests/results/_agent/release/published-bundle-observer'
+ },
+ selection: {
+ status: 'selected',
+ releaseTag: 'v0.6.4-rc.1-tools.1',
+ publishedAt: '2026-03-23T17:19:00Z',
+ releaseName: 'v0.6.4-rc.1-tools.1',
+ releaseId: 123,
+ prerelease: true,
+ draft: false,
+ assetName: 'CompareVI.Tools-v0.6.4-rc.1-tools.1.zip',
+ assetId: 456
+ },
+ bundle: {
+ status: 'extracted',
+ archivePath: 'tests/results/_agent/release/published-bundle-observer/download/CompareVI.Tools-v0.6.4-rc.1-tools.1.zip',
+ extractionRoot: 'tests/results/_agent/release/published-bundle-observer/bundle/CompareVI.Tools-v0.6.4-rc.1-tools.1',
+ downloadDirectory: 'tests/results/_agent/release/published-bundle-observer/download'
+ },
+ bundleContract: {
+ status: 'producer-native-ready',
+ metadataPath:
+ 'tests/results/_agent/release/published-bundle-observer/bundle/CompareVI.Tools-v0.6.4-rc.1-tools.1/comparevi-tools-release.json',
+ schema: 'comparevi-tools-release-manifest@v1',
+ authoritativeConsumerPin: 'v0.6.4-rc.1-tools.1',
+ authoritativeConsumerPinKind: 'release-tag',
+ capabilityId: 'vi-history',
+ distributionRole: 'upstream-producer',
+ distributionModel: 'release-bundle',
+ bundleImportPath: '.github/workflows/vi-history.yml',
+ bundleImportPathExists: true,
+ releaseAssetPattern: 'CompareVI.Tools-v*.zip',
+ contractPathResolutions: [],
+ metadataPresent: true,
+ metadataSchemaMatches: true,
+ viHistoryCapabilityPresent: true,
+ viHistoryCapabilityProducerNative: true,
+ bundleContractPinResolved: true,
+ bundleContractPathsResolved: true
+ },
+ summary: {
+ status: 'producer-native-ready',
+ releaseTag: 'v0.6.4-rc.1-tools.1',
+ assetName: 'CompareVI.Tools-v0.6.4-rc.1-tools.1.zip',
+ publishedAt: '2026-03-23T17:19:00Z',
+ authoritativeConsumerPin: 'v0.6.4-rc.1-tools.1'
+ },
+ ...overrides
+ };
+}
+
+function seedWorkflowContract(repoRoot) {
+ writeText(
+ path.join(repoRoot, '.github', 'workflows', 'release-conductor.yml'),
+ [
+ 'name: release-conductor',
+ 'jobs:',
+ ' release:',
+ ' steps:',
+ ' - name: Configure release tag signing material',
+ ' run: |',
+ ' echo RELEASE_TAG_SIGNING_PRIVATE_KEY',
+ ' echo RELEASE_TAG_SIGNING_IDENTITY_NAME',
+ ' echo RELEASE_TAG_SIGNING_IDENTITY_EMAIL',
+ " signing_login=\"$(gh api user --jq '.login')\"",
+ ' git config gpg.format ssh',
+ ' git config user.signingkey "$public_key_path"',
+ ' git config user.name "$signing_name"',
+ ' git config user.email "$signing_email"'
+ ].join('\n')
+ );
+}
+
+test('parseArgs keeps defaults and accepts overrides', () => {
+ const parsed = parseArgs([
+ 'node',
+ 'release-signing-readiness.mjs',
+ '--repo-root',
+ 'C:/repo',
+ '--repo',
+ 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ '--output',
+ 'custom/release-signing-readiness.json'
+ ]);
+
+ assert.equal(parsed.repoRoot, 'C:/repo');
+ assert.equal(parsed.repo, 'LabVIEW-Community-CI-CD/compare-vi-cli-action');
+ assert.equal(parsed.outputPath, 'custom/release-signing-readiness.json');
+ assert.equal(
+ DEFAULT_OUTPUT_PATH,
+ path.join('tests', 'results', '_agent', 'release', 'release-signing-readiness.json')
+ );
+ assert.equal(
+ DEFAULT_RELEASE_CONDUCTOR_REPORT_PATH,
+ path.join('tests', 'results', '_agent', 'release', 'release-conductor-report.json')
+ );
+ assert.equal(
+ DEFAULT_RELEASE_PUBLISHED_BUNDLE_OBSERVER_PATH,
+ path.join('tests', 'results', '_agent', 'release', 'release-published-bundle-observer.json')
+ );
+});
+
+test('runReleaseSigningReadiness reports explicit external blocker when workflow secret is missing', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'release-signing-readiness-missing-'));
+ seedWorkflowContract(repoRoot);
+ writeJson(path.join(repoRoot, DEFAULT_RELEASE_PUBLISHED_BUNDLE_OBSERVER_PATH), createPublishedBundleObserver({
+ bundleContract: {
+ ...createPublishedBundleObserver().bundleContract,
+ status: 'producer-native-incomplete',
+ authoritativeConsumerPin: null,
+ authoritativeConsumerPinKind: null,
+ capabilityId: null,
+ distributionRole: null,
+ distributionModel: null,
+ bundleImportPath: null,
+ bundleImportPathExists: false,
+ releaseAssetPattern: null,
+ viHistoryCapabilityPresent: false,
+ viHistoryCapabilityProducerNative: false,
+ bundleContractPinResolved: false
+ },
+ summary: {
+ ...createPublishedBundleObserver().summary,
+ status: 'producer-native-incomplete',
+ authoritativeConsumerPin: null
+ }
+ }));
+
+ const result = await runReleaseSigningReadiness(
+ {
+ repoRoot,
+ repo: 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ },
+ {
+ now: new Date('2026-03-23T17:20:00Z'),
+ runGhJsonFn: (args) => {
+ const endpoint = args[1] ?? '';
+ if (endpoint.includes('/actions/secrets')) {
+ return { secrets: [{ name: 'GH_TOKEN' }] };
+ }
+ if (endpoint.includes('/actions/variables')) {
+ return { variables: [] };
+ }
+ if (endpoint.startsWith('user/ssh_signing_keys')) {
+ throw new Error('This API operation needs the "admin:ssh_signing_key" scope.');
+ }
+ throw new Error(`Unexpected endpoint: ${endpoint}`);
+ }
+ }
+ );
+
+ assert.equal(result.exitCode, 1);
+ assert.equal(result.report.summary.status, 'warn');
+ assert.equal(result.report.summary.codePathState, 'ready');
+ assert.equal(result.report.summary.signingCapabilityState, 'missing');
+ assert.equal(result.report.summary.signingAuthorityState, 'scope-missing');
+ assert.equal(result.report.summary.releaseConductorApplyState, 'disabled');
+ assert.equal(result.report.summary.publicationState, 'unobserved');
+ assert.equal(result.report.summary.publishedBundleState, 'producer-native-incomplete');
+ assert.equal(result.report.summary.publishedBundleReleaseTag, 'v0.6.4-rc.1-tools.1');
+ assert.equal(result.report.summary.publishedBundleAuthoritativeConsumerPin, null);
+ assert.equal(result.report.summary.externalBlocker, 'workflow-signing-secret-missing');
+ assert.equal(result.report.secretInventory.requiredSecretPresent, false);
+ assert.equal(result.report.releaseConductorApply.status, 'disabled');
+ assert.equal(result.report.signingAuthority.status, 'scope-missing');
+ assert.equal(result.report.publishedBundleObserver.status, 'producer-native-incomplete');
+ assert.deepEqual(result.report.blockers.map((entry) => entry.code), [
+ 'workflow-signing-secret-missing',
+ 'release-conductor-apply-disabled',
+ 'workflow-signing-admin-scope-missing',
+ 'published-bundle-producer-native-incomplete'
+ ]);
+});
+
+test('runReleaseSigningReadiness reports publication success when signing capability is configured', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'release-signing-readiness-pass-'));
+ seedWorkflowContract(repoRoot);
+ writeJson(path.join(repoRoot, DEFAULT_RELEASE_CONDUCTOR_REPORT_PATH), {
+ release: {
+ tagCreated: true,
+ tagPushed: true,
+ targetTag: 'v0.6.4-rc.1'
+ }
+ });
+ writeJson(path.join(repoRoot, DEFAULT_RELEASE_PUBLISHED_BUNDLE_OBSERVER_PATH), createPublishedBundleObserver());
+
+ const result = await runReleaseSigningReadiness(
+ {
+ repoRoot,
+ repo: 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ },
+ {
+ now: new Date('2026-03-23T17:21:00Z'),
+ runGhJsonFn: (args) => {
+ const endpoint = args[1] ?? '';
+ if (endpoint.includes('/actions/secrets')) {
+ return { secrets: [{ name: REQUIRED_SIGNING_SECRET }, { name: OPTIONAL_SIGNING_SECRET }] };
+ }
+ if (endpoint.includes('/actions/variables')) {
+ return { variables: [{ name: 'RELEASE_CONDUCTOR_ENABLED', value: '1' }] };
+ }
+ if (endpoint.startsWith('user/ssh_signing_keys')) {
+ return [{ id: 1, title: 'compare-release-signing' }];
+ }
+ throw new Error(`Unexpected endpoint: ${endpoint}`);
+ }
+ }
+ );
+
+ assert.equal(result.exitCode, 0);
+ assert.equal(result.report.summary.status, 'pass');
+ assert.equal(result.report.summary.codePathState, 'ready');
+ assert.equal(result.report.summary.signingCapabilityState, 'configured');
+ assert.equal(result.report.summary.signingAuthorityState, 'ready');
+ assert.equal(result.report.summary.releaseConductorApplyState, 'enabled');
+ assert.equal(result.report.summary.publicationState, 'authoritative-publication-successful');
+ assert.equal(result.report.summary.publishedBundleState, 'producer-native-ready');
+ assert.equal(result.report.summary.publishedBundleReleaseTag, 'v0.6.4-rc.1-tools.1');
+ assert.equal(result.report.summary.publishedBundleAuthoritativeConsumerPin, 'v0.6.4-rc.1-tools.1');
+ assert.equal(result.report.summary.externalBlocker, null);
+ assert.equal(result.report.secretInventory.requiredSecretPresent, true);
+ assert.equal(result.report.releaseConductorApply.enabled, true);
+ assert.equal(result.report.signingAuthority.listedKeyCount, 1);
+ assert.equal(result.report.publication.targetTag, 'v0.6.4-rc.1');
+ assert.equal(result.report.publishedBundleObserver.status, 'producer-native-ready');
+ assert.deepEqual(result.report.blockers, []);
+});
diff --git a/tools/priority/__tests__/release-trust-remediation.test.mjs b/tools/priority/__tests__/release-trust-remediation.test.mjs
new file mode 100644
index 000000000..4e50551cb
--- /dev/null
+++ b/tools/priority/__tests__/release-trust-remediation.test.mjs
@@ -0,0 +1,74 @@
+#!/usr/bin/env node
+
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { readFile, mkdtemp, writeFile } from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+
+import { buildReleaseTrustRemediationMarkdown, runReleaseTrustRemediation } from '../release-trust-remediation.mjs';
+
+test('buildReleaseTrustRemediationMarkdown emits repair guidance for unsigned or lightweight tags', () => {
+ const markdown = buildReleaseTrustRemediationMarkdown({
+ tagRef: 'v0.6.4-rc.1',
+ trustReport: {
+ failures: [{ code: 'tag-signature-unverified' }],
+ tagSignature: {
+ refName: 'v0.6.4-rc.1'
+ }
+ }
+ });
+
+ assert.match(markdown, /repair-eligible tag failures/);
+ assert.match(markdown, /`version = 0\.6\.4-rc\.1`/);
+ assert.match(markdown, /`repair_existing_tag = true`/);
+ assert.match(markdown, /Preserve tag identity and asset names/);
+});
+
+test('buildReleaseTrustRemediationMarkdown reports not-needed when no repair failures exist', () => {
+ const markdown = buildReleaseTrustRemediationMarkdown({
+ tagRef: 'v0.6.4-rc.1',
+ trustReport: {
+ failures: [{ code: 'checksum-mismatch' }]
+ }
+ });
+
+ assert.match(markdown, /No repair-mode remediation is required/);
+ assert.doesNotMatch(markdown, /repair_existing_tag/);
+});
+
+test('runReleaseTrustRemediation writes markdown artifact and appends to workflow summary', async () => {
+ const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'release-trust-remediation-'));
+ const trustPath = path.join(tempRoot, 'release-trust-gate.json');
+ const outputPath = path.join(tempRoot, 'release-trust-remediation.md');
+ const summaryPath = path.join(tempRoot, 'step-summary.md');
+
+ await writeFile(
+ trustPath,
+ JSON.stringify(
+ {
+ failures: [{ code: 'tag-not-annotated' }],
+ tagSignature: {
+ refName: 'v0.6.4-rc.1'
+ }
+ },
+ null,
+ 2
+ )
+ );
+
+ const result = await runReleaseTrustRemediation({
+ args: {
+ trustReportPath: trustPath,
+ outputPath,
+ summaryPath,
+ tagRef: 'v0.6.4-rc.1'
+ }
+ });
+
+ assert.equal(result.wroteSummary, true);
+ const output = await readFile(outputPath, 'utf8');
+ const summary = await readFile(summaryPath, 'utf8');
+ assert.match(output, /`repair_existing_tag = true`/);
+ assert.match(summary, /`repair_existing_tag = true`/);
+});
diff --git a/tools/priority/__tests__/remote-utils.test.mjs b/tools/priority/__tests__/remote-utils.test.mjs
index d8d349742..7bf9635f7 100644
--- a/tools/priority/__tests__/remote-utils.test.mjs
+++ b/tools/priority/__tests__/remote-utils.test.mjs
@@ -13,6 +13,7 @@ import {
loadRepositoryGraphMetadata,
ensureOriginFork,
pushBranch,
+ buildGraphqlArgs,
buildGhPrCreateArgs,
buildGhPrEditArgs,
buildGhPrListArgs,
@@ -461,6 +462,36 @@ test('graphql PR helpers expose the same-owner fork mutation contract', () => {
assert.equal(request.variables.draft, true);
});
+test('buildGraphqlArgs preserves string variables and sends booleans as typed GraphQL fields', () => {
+ const args = buildGraphqlArgs('mutation Test { noop }', {
+ repositoryId: 'R_upstream',
+ headRepositoryId: 'R_fork',
+ headRefName: 'issue/963-org-owned-fork-pr-helper',
+ baseRefName: 'develop',
+ draft: false,
+ retryCount: 2
+ });
+
+ assert.deepEqual(args, [
+ 'api',
+ 'graphql',
+ '-f',
+ 'query=mutation Test { noop }',
+ '-f',
+ 'repositoryId=R_upstream',
+ '-f',
+ 'headRepositoryId=R_fork',
+ '-f',
+ 'headRefName=issue/963-org-owned-fork-pr-helper',
+ '-f',
+ 'baseRefName=develop',
+ '-F',
+ 'draft=false',
+ '-F',
+ 'retryCount=2'
+ ]);
+});
+
test('findExistingPullRequest matches the branch/base pair and same-owner cross-repo head', () => {
const calls = [];
const pullRequest = findExistingPullRequest(
diff --git a/tools/priority/__tests__/runtime-supervisor-monitoring-work-injection.test.mjs b/tools/priority/__tests__/runtime-supervisor-monitoring-work-injection.test.mjs
index ae543cd3c..151541cf9 100644
--- a/tools/priority/__tests__/runtime-supervisor-monitoring-work-injection.test.mjs
+++ b/tools/priority/__tests__/runtime-supervisor-monitoring-work-injection.test.mjs
@@ -8,7 +8,10 @@ function createGovernorPortfolioSummary({
nextOwnerRepository = 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
nextAction = 'continue-compare-governance-work',
ownerDecisionSource = 'compare-governor-summary',
- governorMode = 'compare-governance-work'
+ governorMode = 'compare-governance-work',
+ viHistoryDistributorDependencyStatus = 'unknown',
+ viHistoryDistributorDependencyExternalBlocker = null,
+ viHistoryDistributorDependencyPublicationState = null
} = {}) {
return {
schema: 'priority/autonomous-governor-portfolio-summary-report@v1',
@@ -25,11 +28,30 @@ function createGovernorPortfolioSummary({
monitoringStatus: 'active',
futureAgentAction: 'future-agent-may-pivot',
governorMode,
- nextAction
+ nextAction,
+ queueHandoffStatus: null,
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: null
},
portfolio: {
repositoryCount: 4,
repositories: [],
+ dependencies: [
+ {
+ id: 'vi-history-producer-native-distributor',
+ status: viHistoryDistributorDependencyStatus,
+ ownerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ dependentRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ requiredCapability: 'vi-history',
+ source: 'compare-release-signing-readiness',
+ releaseSigningStatus: null,
+ releasePublicationState: viHistoryDistributorDependencyPublicationState,
+ signingCapabilityState: null,
+ externalBlocker: viHistoryDistributorDependencyExternalBlocker,
+ detail: 'fixture'
+ }
+ ],
unsupportedPaths: []
},
summary: {
@@ -42,6 +64,14 @@ function createGovernorPortfolioSummary({
templateMonitoringStatus: 'pass',
supportedProofStatus: 'pass',
repoGraphStatus: 'pass',
+ queueHandoffStatus: null,
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: null,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
portfolioWakeConditionCount: 0,
triggeredWakeConditions: []
}
@@ -167,6 +197,44 @@ test('planCompareviRuntimeStep keeps queue-empty compare ownership as idle with
);
});
+test('planCompareviRuntimeStep explains blocked vi-history distributor dependency during queue-empty compare ownership', async () => {
+ const decision = await compareviRuntimeTest.planCompareviRuntimeStep({
+ repoRoot: '/tmp/repo',
+ env: { GITHUB_REPOSITORY: 'LabVIEW-Community-CI-CD/compare-vi-cli-action' },
+ options: {},
+ deps: {
+ loadDeliveryAgentPolicyFn: async () => ({ implementationRemote: 'origin' }),
+ runMonitoringWorkInjectionFn: async () => ({
+ issueNumber: null,
+ outputPath: '/tmp/repo/tests/results/_agent/issue/monitoring-work-injection.json',
+ ledgerPath: '/tmp/repo/tests/results/_agent/ops/ops-decision-ledger.json'
+ }),
+ classifyNoStandingPriorityConditionFn: async () => ({
+ status: 'classified',
+ reason: 'queue-empty',
+ openIssueCount: 0,
+ message: 'queue empty'
+ }),
+ resolveStandingPriorityForRepoFn: async () => ({ found: null }),
+ readGovernorPortfolioSummaryFn: async () =>
+ createGovernorPortfolioSummary({
+ nextAction: 'complete-compare-vi-history-producer-release',
+ ownerDecisionSource: 'compare-vi-history-distributor-dependency',
+ governorMode: 'monitoring-active',
+ viHistoryDistributorDependencyStatus: 'blocked',
+ viHistoryDistributorDependencyExternalBlocker: 'workflow-signing-secret-missing',
+ viHistoryDistributorDependencyPublicationState: 'unobserved'
+ })
+ }
+ });
+
+ assert.equal(decision.outcome, 'idle');
+ assert.match(decision.reason, /vi-history distributor dependency/i);
+ assert.match(decision.reason, /workflow-signing-secret-missing/i);
+ assert.equal(decision.artifacts.governorPortfolioHandoff.status, 'owner-match');
+ assert.equal(decision.artifacts.governorPortfolioHandoff.viHistoryDistributorDependencyStatus, 'blocked');
+});
+
test('planCompareviRuntimeStep describes repo-context pivot preparation when compare remains current owner but template is next', async () => {
const decision = await compareviRuntimeTest.planCompareviRuntimeStep({
repoRoot: '/tmp/repo',
diff --git a/tools/priority/__tests__/runtime-supervisor.test.mjs b/tools/priority/__tests__/runtime-supervisor.test.mjs
index 6184e4a9c..41f1fe297 100644
--- a/tools/priority/__tests__/runtime-supervisor.test.mjs
+++ b/tools/priority/__tests__/runtime-supervisor.test.mjs
@@ -561,6 +561,26 @@ test('buildCompareviTaskPacket projects concurrent lane status receipts from the
},
error: null
},
+ executionBundle: {
+ path: 'tests/results/_agent/runtime/execution-cell-bundle.json',
+ schema: 'priority/execution-cell-bundle-report@v1',
+ status: 'committed',
+ cellId: 'cell-sagan-kernel',
+ laneId: 'docker-lane-01',
+ cellClass: 'kernel-coordinator',
+ suiteClass: 'dual-plane-parity',
+ executionCellLeaseId: 'exec-lease-123',
+ dockerLaneLeaseId: 'docker-lease-456',
+ harnessKind: 'teststand-compare-harness',
+ harnessInstanceId: 'ts-harness-01',
+ planeBinding: 'dual-plane-parity',
+ premiumSaganMode: true,
+ reciprocalLinkReady: true,
+ effectiveBillableRateUsdPerHour: 375,
+ operatorAuthorizationRef: 'budget-auth://operator/session-2026-03-24',
+ isolatedLaneGroupId: 'host-os-fingerprint:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
+ fingerprintSha256: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+ },
laneStatuses: [
{
id: 'hosted-linux-proof',
@@ -595,6 +615,9 @@ test('buildCompareviTaskPacket projects concurrent lane status receipts from the
deferredLaneCount: 1,
manualLaneCount: 1,
shadowLaneCount: 0,
+ executionBundleStatus: 'committed',
+ executionBundleReciprocalLinkReady: true,
+ executionBundlePremiumSaganMode: true,
pullRequestStatus: 'not-requested',
orchestratorDisposition: 'wait-hosted-run'
}
@@ -763,7 +786,40 @@ test('buildCompareviTaskPacket projects concurrent lane status receipts from the
assert.equal(packet.status, 'waiting-ci');
assert.equal(packet.evidence.delivery.laneLifecycle, 'waiting-ci');
+ assert.equal(packet.evidence.delivery.executionTopology.status, 'bundle-committed');
+ assert.equal(packet.evidence.delivery.executionTopology.executionPlane, 'hosted');
+ assert.equal(packet.evidence.delivery.executionTopology.providerId, 'hosted-github-workflow');
+ assert.equal(packet.evidence.delivery.executionTopology.workerSlotId, 'worker-slot-2');
+ assert.equal(packet.evidence.delivery.executionTopology.cellId, 'cell-sagan-kernel');
+ assert.equal(packet.evidence.delivery.executionTopology.laneId, 'docker-lane-01');
+ assert.equal(packet.evidence.delivery.executionTopology.cellClass, 'kernel-coordinator');
+ assert.equal(packet.evidence.delivery.executionTopology.suiteClass, 'dual-plane-parity');
+ assert.equal(packet.evidence.delivery.executionTopology.planeBinding, 'dual-plane-parity');
+ assert.equal(packet.evidence.delivery.executionTopology.harnessKind, 'teststand-compare-harness');
+ assert.equal(packet.evidence.delivery.executionTopology.harnessInstanceId, 'ts-harness-01');
+ assert.equal(packet.evidence.delivery.executionTopology.executionCellLeaseId, 'exec-lease-123');
+ assert.equal(packet.evidence.delivery.executionTopology.dockerLaneLeaseId, 'docker-lease-456');
+ assert.equal(packet.evidence.delivery.executionTopology.premiumSaganMode, true);
+ assert.equal(packet.evidence.delivery.executionTopology.reciprocalLinkReady, true);
+ assert.equal(
+ packet.evidence.delivery.executionTopology.operatorAuthorizationRef,
+ 'budget-auth://operator/session-2026-03-24'
+ );
+ assert.equal(packet.evidence.delivery.executionTopology.runtimeSurface, 'windows-native-teststand');
+ assert.equal(packet.evidence.delivery.executionTopology.processModelClass, 'parallel-process-model');
+ assert.equal(packet.evidence.delivery.executionTopology.windowsOnly, true);
+ assert.equal(packet.evidence.delivery.executionTopology.requestedSimultaneous, true);
+ assert.equal(packet.evidence.delivery.concurrentLaneStatus.executionBundle.status, 'committed');
+ assert.equal(packet.evidence.delivery.concurrentLaneStatus.executionBundle.cellClass, 'kernel-coordinator');
+ assert.equal(packet.evidence.delivery.concurrentLaneStatus.executionBundle.suiteClass, 'dual-plane-parity');
+ assert.equal(packet.evidence.delivery.concurrentLaneStatus.executionBundle.harnessKind, 'teststand-compare-harness');
+ assert.equal(packet.evidence.delivery.concurrentLaneStatus.executionBundle.reciprocalLinkReady, true);
+ assert.equal(
+ packet.evidence.delivery.concurrentLaneStatus.executionBundle.operatorAuthorizationRef,
+ 'budget-auth://operator/session-2026-03-24'
+ );
assert.equal(packet.evidence.delivery.concurrentLaneStatus.summary.orchestratorDisposition, 'wait-hosted-run');
+ assert.equal(packet.evidence.delivery.concurrentLaneStatus.summary.executionBundleStatus, 'committed');
assert.equal(packet.evidence.delivery.concurrentLaneStatus.summary.deferredLaneCount, 1);
assert.equal(packet.evidence.delivery.workerProviderSelection.selectedAssignmentMode, 'async-validation');
assert.equal(
@@ -7487,6 +7543,28 @@ test('persistDeliveryAgentRuntimeState keeps deferred concurrent lane obligation
'release-with-deferred-local'
);
assert.equal(persistedState.activeLane.concurrentLaneStatus.summary.shadowLaneCount, 1);
+ assert.equal(persistedState.activeLane.executionTopology.status, 'logical-lanes-tracked');
+ assert.equal(persistedState.activeLane.executionTopology.executionPlane, null);
+ assert.equal(persistedState.activeLane.executionTopology.providerId, null);
+ assert.equal(persistedState.activeLane.executionTopology.workerSlotId, null);
+ assert.equal(persistedState.activeLane.executionTopology.cellId, null);
+ assert.equal(persistedState.activeLane.executionTopology.laneId, null);
+ assert.equal(persistedState.activeLane.executionTopology.cellClass, null);
+ assert.equal(persistedState.activeLane.executionTopology.suiteClass, null);
+ assert.equal(persistedState.activeLane.executionTopology.planeBinding, null);
+ assert.equal(persistedState.activeLane.executionTopology.harnessKind, null);
+ assert.equal(persistedState.activeLane.executionTopology.harnessInstanceId, null);
+ assert.equal(persistedState.activeLane.executionTopology.executionCellLeaseId, null);
+ assert.equal(persistedState.activeLane.executionTopology.dockerLaneLeaseId, null);
+ assert.equal(persistedState.activeLane.executionTopology.premiumSaganMode, false);
+ assert.equal(persistedState.activeLane.executionTopology.reciprocalLinkReady, false);
+ assert.equal(persistedState.activeLane.executionTopology.operatorAuthorizationRef, null);
+ assert.equal(persistedState.activeLane.executionTopology.activeLogicalLaneCount, 4);
+ assert.equal(persistedState.activeLane.executionTopology.seededLogicalLaneCount, 4);
+ assert.equal(persistedState.activeLane.executionTopology.runtimeSurface, null);
+ assert.equal(persistedState.activeLane.executionTopology.processModelClass, null);
+ assert.equal(persistedState.activeLane.executionTopology.windowsOnly, false);
+ assert.equal(persistedState.activeLane.executionTopology.requestedSimultaneous, false);
assert.equal(
persistedState.artifacts.concurrentLaneApplyReceiptPath,
'tests/results/_agent/runtime/concurrent-lane-apply-receipt.json'
diff --git a/tools/priority/__tests__/sagan-context-concentrator-schema.test.mjs b/tools/priority/__tests__/sagan-context-concentrator-schema.test.mjs
new file mode 100644
index 000000000..127d4c6c2
--- /dev/null
+++ b/tools/priority/__tests__/sagan-context-concentrator-schema.test.mjs
@@ -0,0 +1,175 @@
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import { Ajv2020 } from 'ajv/dist/2020.js';
+import addFormats from 'ajv-formats';
+
+import { runSaganContextConcentrator } from '../sagan-context-concentrator.mjs';
+
+const repoRoot = path.resolve(process.cwd());
+
+function writeJson(filePath, payload) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+function readJson(filePath) {
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
+}
+
+test('sagan context concentrator report matches schema', async () => {
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sagan-context-concentrator-schema-'));
+ writeJson(path.join(tmpDir, '.agent_priority_cache.json'), {
+ number: 1909,
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ title: '[governor]: build Sagan context concentrator for durable subagent memory',
+ url: 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/issues/1909',
+ state: 'OPEN'
+ });
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'autonomous-governor-summary.json'), {
+ schema: 'priority/autonomous-governor-summary-report@v1',
+ generatedAt: '2026-03-23T23:00:00Z',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ inputs: {
+ queueEmptyReportPath: 'tests/results/_agent/issue/no-standing-priority.json',
+ continuitySummaryPath: 'tests/results/_agent/handoff/continuity-summary.json',
+ monitoringModePath: 'tests/results/_agent/handoff/monitoring-mode.json',
+ wakeLifecyclePath: 'tests/results/_agent/issue/wake-lifecycle.json',
+ wakeInvestmentAccountingPath: 'tests/results/_agent/capital/wake-investment-accounting.json',
+ deliveryRuntimeStatePath: 'tests/results/_agent/runtime/delivery-agent-state.json',
+ releaseSigningReadinessPath: 'tests/results/_agent/release/release-signing-readiness.json'
+ },
+ compare: {},
+ wake: {},
+ funding: {},
+ summary: {
+ governorMode: 'compare-governance-work',
+ currentOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextAction: 'keep-building-concentrator',
+ queueState: 'active',
+ monitoringStatus: 'active',
+ releaseSigningStatus: 'missing'
+ }
+ });
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'autonomous-governor-portfolio-summary.json'), {
+ schema: 'priority/autonomous-governor-portfolio-summary-report@v1',
+ generatedAt: '2026-03-23T23:00:10Z',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ inputs: {
+ compareGovernorSummaryPath: 'tests/results/_agent/handoff/autonomous-governor-summary.json',
+ monitoringModePath: 'tests/results/_agent/handoff/monitoring-mode.json',
+ repoGraphTruthPath: 'tests/results/_agent/handoff/downstream-repo-graph-truth.json'
+ },
+ compare: {},
+ portfolio: {
+ repositoryCount: 1,
+ repositories: [],
+ dependencies: [],
+ unsupportedPaths: []
+ },
+ summary: {
+ status: 'active',
+ governorMode: 'compare-governance-work',
+ currentOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextAction: 'keep-building-concentrator',
+ ownerDecisionSource: 'compare-governor-summary',
+ templateMonitoringStatus: 'pass',
+ supportedProofStatus: 'pass',
+ repoGraphStatus: 'pass',
+ queueHandoffStatus: 'none',
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: 'none',
+ viHistoryDistributorDependencyStatus: 'unknown',
+ viHistoryDistributorDependencyTargetRepository: null,
+ viHistoryDistributorDependencyExternalBlocker: null,
+ viHistoryDistributorDependencyPublicationState: null,
+ viHistoryDistributorDependencyPublishedBundleState: null,
+ viHistoryDistributorDependencyPublishedBundleReleaseTag: null,
+ viHistoryDistributorDependencyAuthoritativeConsumerPin: null,
+ viHistoryDistributorDependencySigningAuthorityState: null
+ }
+ });
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'handoff', 'monitoring-mode.json'), {
+ schema: 'agent-handoff/monitoring-mode-v1',
+ generatedAt: '2026-03-23T23:00:20Z',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ policy: {
+ compareRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ },
+ summary: {
+ status: 'active',
+ futureAgentAction: 'continue-compare-governance-work',
+ wakeConditionCount: 0
+ }
+ });
+ writeJson(path.join(tmpDir, 'tests', 'results', '_agent', 'memory', 'subagent-episodes', 'episode.json'), {
+ schema: 'priority/subagent-episode-report@v1',
+ generatedAt: '2026-03-23T22:59:00Z',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ inputs: {
+ sourcePath: 'tmp/episode.json'
+ },
+ episodeId: 'episode-1',
+ agent: {
+ id: 'euler-id',
+ name: 'Euler',
+ role: 'explorer',
+ model: 'gpt-5.4-mini'
+ },
+ task: {
+ summary: 'Inspect concentrator seams',
+ class: 'exploration',
+ issueNumber: 1909,
+ issueUrl: 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/issues/1909'
+ },
+ execution: {
+ status: 'completed',
+ lane: '1909-sagan-context-concentrator',
+ branch: 'issue/upstream-1909-sagan-context-concentrator',
+ executionPlane: 'windows-host',
+ dockerLaneId: 'docker-euler-001',
+ hostCapabilityLeaseId: 'lease-euler-001'
+ },
+ summary: {
+ status: 'reported',
+ outcome: 'seams-found',
+ blocker: null,
+ nextAction: 'patch handoff',
+ detail: null
+ },
+ evidence: {
+ filesTouched: [],
+ receipts: [],
+ commands: [],
+ notes: []
+ },
+ cost: {
+ observedDurationSeconds: 30,
+ tokenUsd: 0.02,
+ operatorLaborUsd: 2.083333,
+ blendedLowerBoundUsd: 2.103333
+ }
+ });
+
+ const { report } = await runSaganContextConcentrator(
+ {
+ repoRoot: tmpDir
+ },
+ {
+ now: new Date('2026-03-23T23:01:00Z')
+ }
+ );
+
+ const schema = readJson(path.join(repoRoot, 'docs', 'schemas', 'sagan-context-concentrator-report-v1.schema.json'));
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
+ addFormats(ajv);
+ const validate = ajv.compile(schema);
+ const valid = validate(report);
+ assert.equal(valid, true, JSON.stringify(validate.errors, null, 2));
+});
diff --git a/tools/priority/__tests__/sagan-context-concentrator.test.mjs b/tools/priority/__tests__/sagan-context-concentrator.test.mjs
new file mode 100644
index 000000000..0c86f3776
--- /dev/null
+++ b/tools/priority/__tests__/sagan-context-concentrator.test.mjs
@@ -0,0 +1,259 @@
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import { runSaganContextConcentrator } from '../sagan-context-concentrator.mjs';
+
+function writeJson(filePath, payload) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+function createGovernorSummary() {
+ return {
+ schema: 'priority/autonomous-governor-summary-report@v1',
+ generatedAt: '2026-03-23T22:30:00Z',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ inputs: {
+ queueEmptyReportPath: 'tests/results/_agent/issue/no-standing-priority.json',
+ continuitySummaryPath: 'tests/results/_agent/handoff/continuity-summary.json',
+ monitoringModePath: 'tests/results/_agent/handoff/monitoring-mode.json',
+ wakeLifecyclePath: 'tests/results/_agent/issue/wake-lifecycle.json',
+ wakeInvestmentAccountingPath: 'tests/results/_agent/capital/wake-investment-accounting.json',
+ deliveryRuntimeStatePath: 'tests/results/_agent/runtime/delivery-agent-state.json',
+ releaseSigningReadinessPath: 'tests/results/_agent/release/release-signing-readiness.json'
+ },
+ compare: {},
+ wake: {},
+ funding: {},
+ summary: {
+ governorMode: 'compare-governance-work',
+ currentOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextAction: 'publish-producer-native-vi-history-bundle',
+ queueState: 'active',
+ monitoringStatus: 'active',
+ releaseSigningStatus: 'warn',
+ releaseSigningExternalBlocker: 'tag-signature-unverified',
+ releasePublicationState: 'tag-created-not-published',
+ releasePublishedBundleState: 'producer-native-incomplete',
+ releasePublishedBundleReleaseTag: 'v0.6.3-tools.14'
+ }
+ };
+}
+
+function createGovernorPortfolioSummary() {
+ return {
+ schema: 'priority/autonomous-governor-portfolio-summary-report@v1',
+ generatedAt: '2026-03-23T22:31:00Z',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ inputs: {
+ compareGovernorSummaryPath: 'tests/results/_agent/handoff/autonomous-governor-summary.json',
+ monitoringModePath: 'tests/results/_agent/handoff/monitoring-mode.json',
+ repoGraphTruthPath: 'tests/results/_agent/handoff/downstream-repo-graph-truth.json'
+ },
+ compare: {},
+ portfolio: {
+ repositoryCount: 4,
+ repositories: [],
+ dependencies: [],
+ unsupportedPaths: []
+ },
+ summary: {
+ status: 'active',
+ governorMode: 'compare-governance-work',
+ currentOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextOwnerRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ nextAction: 'publish-producer-native-vi-history-bundle',
+ ownerDecisionSource: 'compare-governor-summary',
+ templateMonitoringStatus: 'pass',
+ supportedProofStatus: 'pass',
+ repoGraphStatus: 'pass',
+ queueHandoffStatus: 'none',
+ queueHandoffNextWakeCondition: null,
+ queueHandoffPrUrl: null,
+ queueAuthoritySource: 'none',
+ viHistoryDistributorDependencyStatus: 'blocked',
+ viHistoryDistributorDependencyTargetRepository: 'LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate',
+ viHistoryDistributorDependencyExternalBlocker: 'producer-native-incomplete',
+ viHistoryDistributorDependencyPublicationState: 'tag-created-not-published',
+ viHistoryDistributorDependencyPublishedBundleState: 'producer-native-incomplete',
+ viHistoryDistributorDependencyPublishedBundleReleaseTag: 'v0.6.3-tools.14',
+ viHistoryDistributorDependencyAuthoritativeConsumerPin: null,
+ viHistoryDistributorDependencySigningAuthorityState: 'configured'
+ }
+ };
+}
+
+function createMonitoringMode() {
+ return {
+ schema: 'agent-handoff/monitoring-mode-v1',
+ generatedAt: '2026-03-23T22:32:00Z',
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ policy: {
+ compareRepository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action'
+ },
+ summary: {
+ status: 'active',
+ futureAgentAction: 'remain-in-monitoring',
+ wakeConditionCount: 0
+ }
+ };
+}
+
+function createEpisode(agentName, status, generatedAt, extra = {}) {
+ return {
+ schema: 'priority/subagent-episode-report@v1',
+ generatedAt,
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ inputs: {
+ sourcePath: `tmp/${agentName}.json`
+ },
+ episodeId: `${agentName}-${generatedAt.replace(/[:.]/g, '-')}`,
+ agent: {
+ id: `${agentName.toLowerCase()}-id`,
+ name: agentName,
+ role: 'explorer',
+ model: 'gpt-5.4-mini'
+ },
+ task: {
+ summary: extra.taskSummary || `Task from ${agentName}`,
+ class: 'exploration',
+ issueNumber: 1909,
+ issueUrl: 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/issues/1909'
+ },
+ execution: {
+ status: 'completed',
+ lane: '1909-sagan-context-concentrator',
+ branch: 'issue/upstream-1909-sagan-context-concentrator',
+ executionPlane: extra.executionPlane || 'windows-host',
+ dockerLaneId: extra.dockerLaneId || null,
+ hostCapabilityLeaseId: null
+ },
+ summary: {
+ status,
+ outcome: extra.outcome || null,
+ blocker: extra.blocker || null,
+ nextAction: extra.nextAction || null,
+ detail: extra.detail || null
+ },
+ evidence: {
+ filesTouched: extra.filesTouched || [],
+ receipts: extra.receipts || [],
+ commands: [],
+ notes: []
+ },
+ cost: {
+ observedDurationSeconds: extra.durationSeconds || 60,
+ tokenUsd: extra.tokenUsd || 0.05,
+ operatorLaborUsd: extra.operatorLaborUsd || 4.166667,
+ blendedLowerBoundUsd: extra.blendedLowerBoundUsd || 4.216667
+ }
+ };
+}
+
+test('runSaganContextConcentrator builds hot and warm memory from episodes and governor state', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sagan-context-concentrator-'));
+ writeJson(path.join(repoRoot, '.agent_priority_cache.json'), {
+ number: 1877,
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ title: '[release]: publish CompareVI.Tools bundle with native vi-history capability contract',
+ url: 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/issues/1877',
+ state: 'OPEN'
+ });
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'handoff', 'autonomous-governor-summary.json'),
+ createGovernorSummary()
+ );
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'handoff', 'autonomous-governor-portfolio-summary.json'),
+ createGovernorPortfolioSummary()
+ );
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'handoff', 'monitoring-mode.json'),
+ createMonitoringMode()
+ );
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'memory', 'subagent-episodes', 'euler.json'),
+ createEpisode('Euler', 'reported', '2026-03-23T22:20:00Z', {
+ blocker: 'handoff-seam-open',
+ nextAction: 'patch Print-AgentHandoff',
+ dockerLaneId: 'docker-euler-001',
+ tokenUsd: 0.08,
+ operatorLaborUsd: 6.25,
+ blendedLowerBoundUsd: 6.33
+ })
+ );
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'memory', 'subagent-episodes', 'euclid.json'),
+ createEpisode('Euclid', 'reported', '2026-03-23T22:25:00Z', {
+ nextAction: 'reuse governor schema style',
+ tokenUsd: 0.05,
+ operatorLaborUsd: 4.166667,
+ blendedLowerBoundUsd: 4.216667
+ })
+ );
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'memory', 'subagent-episodes', 'hooke.json'),
+ createEpisode('Hooke', 'completed', '2026-03-23T22:10:00Z', {
+ outcome: 'template-blocker-confirmed',
+ nextAction: 'hold template #18 until compare publication',
+ executionPlane: 'docker-lane',
+ dockerLaneId: 'docker-hooke-001'
+ })
+ );
+
+ const { report, outputPath } = await runSaganContextConcentrator(
+ {
+ repoRoot
+ },
+ {
+ now: new Date('2026-03-23T22:35:00Z')
+ }
+ );
+
+ assert.equal(report.schema, 'priority/sagan-context-concentrator-report@v1');
+ assert.equal(report.focus.activeIssue.number, 1877);
+ assert.equal(report.summary.currentOwnerRepository, 'LabVIEW-Community-CI-CD/compare-vi-cli-action');
+ assert.equal(report.summary.nextAction, 'publish-producer-native-vi-history-bundle');
+ assert.equal(report.summary.hotWorkingSetCount, report.memory.hotWorkingSet.length);
+ assert.equal(report.episodes.validCount, 3);
+ assert.ok(report.episodes.byAgent.some((entry) => entry.agentName === 'Euler'));
+ assert.equal(report.cost.tokenUsd, 0.18);
+ assert.equal(report.cost.blendedLowerBoundUsd, 14.763334);
+ assert.ok(report.memory.hotWorkingSet.some((entry) => entry.kind === 'dependency'));
+ assert.ok(report.memory.hotWorkingSet.some((entry) => entry.agentName === 'Euler'));
+ assert.ok(report.memory.warmMemory.some((entry) => entry.agentName === 'Hooke'));
+ assert.ok(fs.existsSync(outputPath));
+});
+
+test('runSaganContextConcentrator tolerates missing optional episode directory', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sagan-context-concentrator-empty-'));
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'handoff', 'autonomous-governor-summary.json'),
+ createGovernorSummary()
+ );
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'handoff', 'autonomous-governor-portfolio-summary.json'),
+ createGovernorPortfolioSummary()
+ );
+ writeJson(
+ path.join(repoRoot, 'tests', 'results', '_agent', 'handoff', 'monitoring-mode.json'),
+ createMonitoringMode()
+ );
+
+ const { report } = await runSaganContextConcentrator(
+ {
+ repoRoot
+ },
+ {
+ now: new Date('2026-03-23T22:40:00Z')
+ }
+ );
+
+ assert.equal(report.episodes.totalCount, 0);
+ assert.equal(report.summary.concentrationStatus, 'pass');
+ assert.equal(report.summary.hotWorkingSetCount >= 2, true);
+});
diff --git a/tools/priority/__tests__/subagent-episode-schema.test.mjs b/tools/priority/__tests__/subagent-episode-schema.test.mjs
new file mode 100644
index 000000000..0e61c3a86
--- /dev/null
+++ b/tools/priority/__tests__/subagent-episode-schema.test.mjs
@@ -0,0 +1,85 @@
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import { Ajv2020 } from 'ajv/dist/2020.js';
+import addFormats from 'ajv-formats';
+
+import { runSubagentEpisode } from '../subagent-episode.mjs';
+
+const repoRoot = path.resolve(process.cwd());
+
+function readJson(filePath) {
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
+}
+
+test('subagent episode report matches schema', async () => {
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subagent-episode-schema-'));
+ const inputPath = path.join(tmpDir, 'episode-input.json');
+ const outputPath = path.join(tmpDir, 'subagent-episode.json');
+
+ fs.writeFileSync(
+ inputPath,
+ `${JSON.stringify(
+ {
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ generatedAt: '2026-03-23T22:10:00Z',
+ agent: {
+ id: '019d1ba6-746c-72a2-b73c-3ebc239843f1',
+ name: 'Hooke',
+ role: 'explorer',
+ model: 'gpt-5.4-mini'
+ },
+ task: {
+ summary: 'Verify template blocker state',
+ class: 'verification',
+ issueNumber: 18,
+ issueUrl: 'https://github.com/LabVIEW-Community-CI-CD/LabviewGitHubCiTemplate/issues/18'
+ },
+ execution: {
+ status: 'completed',
+ lane: 'LabviewGitHubCiTemplate-18-producer-native-consumer',
+ executionPlane: 'windows-host'
+ },
+ summary: {
+ status: 'reported',
+ outcome: 'template-blocker-confirmed',
+ blocker: 'compare-publication-pending',
+ nextAction: 'wait for producer-native release publication'
+ },
+ evidence: {
+ receipts: ['tests/results/_agent/release/release-published-bundle-observer.json']
+ },
+ cost: {
+ observedDurationSeconds: 120,
+ tokenUsd: 0.08,
+ operatorLaborUsd: 8.333333,
+ blendedLowerBoundUsd: 8.413333
+ }
+ },
+ null,
+ 2
+ )}\n`,
+ 'utf8'
+ );
+
+ const { report } = await runSubagentEpisode(
+ {
+ repoRoot: tmpDir,
+ inputPath,
+ outputPath
+ },
+ {
+ now: new Date('2026-03-23T22:10:30Z')
+ }
+ );
+
+ const schema = readJson(path.join(repoRoot, 'docs', 'schemas', 'subagent-episode-report-v1.schema.json'));
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
+ addFormats(ajv);
+ const validate = ajv.compile(schema);
+ const valid = validate(report);
+ assert.equal(valid, true, JSON.stringify(validate.errors, null, 2));
+});
diff --git a/tools/priority/__tests__/subagent-episode.test.mjs b/tools/priority/__tests__/subagent-episode.test.mjs
new file mode 100644
index 000000000..28f790aa9
--- /dev/null
+++ b/tools/priority/__tests__/subagent-episode.test.mjs
@@ -0,0 +1,133 @@
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import {
+ REPORT_SCHEMA,
+ buildSubagentEpisodeReport,
+ parseArgs,
+ runSubagentEpisode
+} from '../subagent-episode.mjs';
+
+function writeJson(filePath, payload) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+}
+
+test('parseArgs requires input and keeps defaults', () => {
+ const parsed = parseArgs([
+ 'node',
+ 'subagent-episode.mjs',
+ '--input',
+ 'tmp/episode.json'
+ ]);
+
+ assert.equal(parsed.inputPath, 'tmp/episode.json');
+ assert.equal(parsed.outputPath, null);
+});
+
+test('buildSubagentEpisodeReport normalizes source payload', () => {
+ const report = buildSubagentEpisodeReport(
+ {
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ generatedAt: '2026-03-23T21:00:00Z',
+ agent: {
+ id: '019d11a9-3e6b-7073-b602-7a0a2085f106',
+ name: 'Euler',
+ role: 'explorer',
+ model: 'gpt-5.4-mini'
+ },
+ task: {
+ summary: 'Inspect handoff seams',
+ class: 'exploration',
+ issueNumber: 1909,
+ issueUrl: 'https://github.com/LabVIEW-Community-CI-CD/compare-vi-cli-action/issues/1909'
+ },
+ execution: {
+ status: 'completed',
+ lane: '1909-sagan-context-concentrator',
+ branch: 'issue/upstream-1909-sagan-context-concentrator',
+ executionPlane: 'windows-host',
+ dockerLaneId: 'docker-euler-001',
+ hostCapabilityLeaseId: 'lease-euler-001'
+ },
+ summary: {
+ status: 'reported',
+ outcome: 'handoff-seams-identified',
+ blocker: null,
+ nextAction: 'wire concentrator into Print-AgentHandoff',
+ detail: 'Print-AgentHandoff and Import-HandoffState are the right seams.'
+ },
+ evidence: {
+ filesTouched: ['tools/Print-AgentHandoff.ps1'],
+ receipts: ['tests/results/_agent/handoff/autonomous-governor-summary.json'],
+ commands: ['rg -n governor tools/Print-AgentHandoff.ps1'],
+ notes: ['Focus on handoff refresh and render path.']
+ },
+ cost: {
+ observedDurationSeconds: 90,
+ tokenUsd: 0.14,
+ operatorLaborUsd: 6.25,
+ blendedLowerBoundUsd: 6.39
+ }
+ },
+ {
+ repoRoot: 'E:/comparevi-lanes/1909-sagan-context-concentrator',
+ inputPath: 'tmp/subagent-input.json',
+ now: new Date('2026-03-23T21:05:00Z')
+ }
+ );
+
+ assert.equal(report.schema, REPORT_SCHEMA);
+ assert.equal(report.agent.name, 'Euler');
+ assert.equal(report.task.issueNumber, 1909);
+ assert.equal(report.execution.dockerLaneId, 'docker-euler-001');
+ assert.equal(report.summary.nextAction, 'wire concentrator into Print-AgentHandoff');
+ assert.equal(report.cost.blendedLowerBoundUsd, 6.39);
+});
+
+test('runSubagentEpisode writes a normalized episode report', async () => {
+ const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'subagent-episode-'));
+ const inputPath = path.join(repoRoot, 'tmp', 'episode-input.json');
+ writeJson(inputPath, {
+ repository: 'LabVIEW-Community-CI-CD/compare-vi-cli-action',
+ agent: {
+ id: '019d11a9-3e7f-7331-a692-63a1c6c78904',
+ name: 'Euclid',
+ role: 'explorer',
+ model: 'gpt-5.4-mini'
+ },
+ task: {
+ summary: 'Catalog analogous receipt patterns',
+ class: 'exploration',
+ issueNumber: 1909
+ },
+ summary: {
+ status: 'reported',
+ outcome: 'receipt-templates-found',
+ nextAction: 'reuse governor summary schema style'
+ },
+ evidence: {
+ notes: ['Use autonomous-governor-summary as the main receipt template.']
+ }
+ });
+
+ const { report, outputPath } = await runSubagentEpisode(
+ {
+ repoRoot,
+ inputPath
+ },
+ {
+ now: new Date('2026-03-23T22:00:00Z')
+ }
+ );
+
+ assert.ok(outputPath.includes('subagent-episodes'));
+ assert.equal(report.schema, REPORT_SCHEMA);
+ assert.equal(report.agent.name, 'Euclid');
+ assert.equal(report.summary.status, 'reported');
+ assert.equal(report.execution.status, 'completed');
+ assert.ok(fs.existsSync(outputPath));
+});
diff --git a/tools/priority/__tests__/supply-chain-trust-gate.test.mjs b/tools/priority/__tests__/supply-chain-trust-gate.test.mjs
index 821b7338f..72d039704 100644
--- a/tools/priority/__tests__/supply-chain-trust-gate.test.mjs
+++ b/tools/priority/__tests__/supply-chain-trust-gate.test.mjs
@@ -349,6 +349,14 @@ test('verifyReleaseTagSignature fails for unsigned tag', async () => {
});
assert.ok(result.failures.some((failure) => failure.code === 'tag-signature-unverified'));
+ assert.ok(
+ result.failures.some(
+ (failure) =>
+ failure.code === 'tag-signature-unverified' &&
+ String(failure.hint).includes('priority:release:signing:readiness') &&
+ String(failure.hint).includes('repair_existing_tag = true')
+ )
+ );
assert.equal(result.status.verified, false);
assert.equal(result.status.reason, 'unsigned');
});
@@ -380,6 +388,14 @@ test('verifyReleaseTagSignature fails for lightweight tag', async () => {
});
assert.ok(result.failures.some((failure) => failure.code === 'tag-not-annotated'));
+ assert.ok(
+ result.failures.some(
+ (failure) =>
+ failure.code === 'tag-not-annotated' &&
+ String(failure.hint).includes('priority:release:signing:readiness') &&
+ String(failure.hint).includes('repair_existing_tag = true')
+ )
+ );
assert.equal(result.status.annotated, false);
assert.equal(result.status.reason, 'not-annotated');
});
diff --git a/tools/priority/__tests__/workflow-pwsh-continuation-contract.test.mjs b/tools/priority/__tests__/workflow-pwsh-continuation-contract.test.mjs
index 53446fbd4..4f82289cf 100644
--- a/tools/priority/__tests__/workflow-pwsh-continuation-contract.test.mjs
+++ b/tools/priority/__tests__/workflow-pwsh-continuation-contract.test.mjs
@@ -80,7 +80,7 @@ test('release workflow explicitly dispatches publish-tools-image with actions wr
assert.ok(dispatchStep, 'release workflow should dispatch publish-tools-image explicitly');
assert.equal(dispatchStep.uses, 'actions/github-script@v8');
assert.match(dispatchStep.with.script, /workflow_id:\s*'publish-tools-image\.yml'/);
- assert.match(dispatchStep.with.script, /ref:\s*'\$\{\{\s*github\.ref_name\s*\}\}'/);
+ assert.match(dispatchStep.with.script, /ref:\s*'develop'/);
assert.match(
dispatchStep.with.script,
/const releaseVersion = '\$\{\{\s*steps\.comparevi_tools\.outputs\.comparevi_tools_release_version\s*\}\}';/
@@ -88,6 +88,23 @@ test('release workflow explicitly dispatches publish-tools-image with actions wr
assert.match(dispatchStep.with.script, /const releaseChannel = releaseVersion\.includes\('-rc\.'\) \? 'rc' : 'stable';/);
});
+test('release workflow remains tag-triggered and also supports workflow_dispatch replay for repaired tags', () => {
+ const workflowPath = path.join(workflowsRoot, 'release.yml');
+ const workflowRaw = readFileSync(workflowPath, 'utf8');
+ const workflow = yaml.load(workflowRaw);
+
+ assert.deepEqual(workflow?.on?.push?.tags, ['v*']);
+ assert.ok(Object.prototype.hasOwnProperty.call(workflow?.on ?? {}, 'workflow_dispatch'));
+ assert.equal(workflow?.on?.workflow_dispatch?.inputs?.release_tag?.required, true);
+ assert.equal(workflow?.on?.workflow_dispatch?.inputs?.release_tag?.type, 'string');
+ assert.match(workflowRaw, /name: Resolve release target tag/);
+ assert.match(workflowRaw, /tag='\$\{\{\s*inputs\.release_tag\s*\}\}'/);
+ assert.match(workflowRaw, /target_tag:\s*\$\{\{\s*steps\.release_target\.outputs\.tag\s*\}\}/);
+ assert.match(workflowRaw, /ref:\s*\$\{\{\s*steps\.release_target\.outputs\.tag\s*\}\}/);
+ assert.match(workflowRaw, /RELEASE_TAG:\s*\$\{\{\s*needs\.certification-matrix\.outputs\.target_tag\s*\}\}/);
+ assert.match(workflowRaw, /tag_name:\s*\$\{\{\s*env\.RELEASE_TAG\s*\}\}/);
+});
+
test('release workflow resolves downloaded artifacts through the shared helper before validation', () => {
const workflowPath = path.join(workflowsRoot, 'release.yml');
const workflowRaw = readFileSync(workflowPath, 'utf8');
@@ -125,7 +142,8 @@ test('release workflow resolves downloaded artifacts through the shared helper b
assert.match(workflowRaw, /name: Download release-review scenario artifacts/);
assert.match(workflowRaw, /merge-multiple:\s*true/);
assert.match(workflowRaw, /name: Resolve release source commit/);
- assert.match(workflowRaw, /git rev-parse "\$\{\{\s*github\.ref_name\s*\}\}\^\{commit\}"/);
+ assert.match(workflowRaw, /git fetch --force --tags origin "refs\/tags\/\$\{RELEASE_TAG\}:refs\/tags\/\$\{RELEASE_TAG\}"/);
+ assert.match(workflowRaw, /git rev-parse "\$\{RELEASE_TAG\}\^\{commit\}"/);
assert.match(workflowRaw, /name: Resolve downstream proving artifact selection/);
assert.match(workflowRaw, /resolve-downstream-proving-artifact\.mjs/);
assert.match(workflowRaw, /--workflow downstream-promotion\.yml/);
@@ -155,6 +173,19 @@ test('release workflow resolves downloaded artifacts through the shared helper b
assert.doesNotMatch(workflowRaw, /steps\.contract_artifacts\.outputs\.linux_tarball_path/);
});
+test('release workflow appends repair-mode guidance for unsigned or lightweight tags', () => {
+ const workflowPath = path.join(workflowsRoot, 'release.yml');
+ const workflowRaw = readFileSync(workflowPath, 'utf8');
+
+ assert.match(workflowRaw, /name: Append release trust remediation guidance/);
+ assert.match(workflowRaw, /node tools\/priority\/release-trust-remediation\.mjs/);
+ assert.match(workflowRaw, /--trust-report tests\/results\/_agent\/supply-chain\/release-trust-gate\.json/);
+ assert.match(workflowRaw, /--tag-ref "\$\{RELEASE_TAG\}"/);
+ assert.match(workflowRaw, /--output tests\/results\/_agent\/release\/release-trust-remediation\.md/);
+ assert.match(workflowRaw, /--summary "\$GITHUB_STEP_SUMMARY"/);
+ assert.match(workflowRaw, /tests\/results\/_agent\/release\/release-trust-remediation\.md/);
+});
+
test('monthly release workflow marks itself as the SLO remediation candidate', () => {
const workflowPath = path.join(workflowsRoot, 'monthly-stability-release.yml');
const workflowRaw = readFileSync(workflowPath, 'utf8');
diff --git a/tools/priority/autonomous-governor-portfolio-summary.mjs b/tools/priority/autonomous-governor-portfolio-summary.mjs
index d711f73ab..79d0fb8a3 100644
--- a/tools/priority/autonomous-governor-portfolio-summary.mjs
+++ b/tools/priority/autonomous-governor-portfolio-summary.mjs
@@ -140,6 +140,79 @@ function createWakeConditionsByRepository(triggeredWakeConditions) {
};
}
+function deriveViHistoryDistributorDependency(compareGovernorSummary, monitoringMode) {
+ const compareRepository =
+ asOptional(compareGovernorSummary?.summary?.currentOwnerRepository) ||
+ asOptional(monitoringMode?.policy?.compareRepository) ||
+ asOptional(compareGovernorSummary?.repository);
+ const dependentRepository = asOptional(monitoringMode?.policy?.pivotTargetRepository);
+ const releaseSigningReadiness = compareGovernorSummary?.compare?.releaseSigningReadiness;
+ const releaseSigningStatus =
+ asOptional(compareGovernorSummary?.summary?.releaseSigningStatus) || asOptional(releaseSigningReadiness?.status);
+ const releasePublicationState =
+ asOptional(compareGovernorSummary?.summary?.releasePublicationState) ||
+ asOptional(releaseSigningReadiness?.publicationState);
+ const publishedBundleState =
+ asOptional(compareGovernorSummary?.summary?.releasePublishedBundleState) ||
+ asOptional(releaseSigningReadiness?.publishedBundleState);
+ const publishedBundleReleaseTag =
+ asOptional(compareGovernorSummary?.summary?.releasePublishedBundleReleaseTag) ||
+ asOptional(releaseSigningReadiness?.publishedBundleReleaseTag);
+ const publishedBundleAuthoritativeConsumerPin =
+ asOptional(compareGovernorSummary?.summary?.releasePublishedBundleAuthoritativeConsumerPin) ||
+ asOptional(releaseSigningReadiness?.publishedBundleAuthoritativeConsumerPin);
+ const signingCapabilityState = asOptional(releaseSigningReadiness?.signingCapabilityState);
+ const signingAuthorityState =
+ asOptional(compareGovernorSummary?.summary?.releaseSigningAuthorityState) ||
+ asOptional(releaseSigningReadiness?.signingAuthorityState);
+ const releaseConductorApplyState =
+ asOptional(compareGovernorSummary?.summary?.releaseConductorApplyState) ||
+ asOptional(releaseSigningReadiness?.releaseConductorApplyState);
+ const externalBlocker =
+ asOptional(compareGovernorSummary?.summary?.releaseSigningExternalBlocker) ||
+ asOptional(releaseSigningReadiness?.externalBlocker);
+
+ let status = 'unknown';
+ let detail = 'missing-release-signing-readiness';
+ if (publishedBundleState === 'producer-native-ready' || releasePublicationState === 'producer-native-ready') {
+ status = 'ready';
+ detail = 'producer-native-release-ready';
+ } else if (
+ publishedBundleState ||
+ releaseSigningStatus ||
+ releasePublicationState ||
+ signingCapabilityState ||
+ externalBlocker
+ ) {
+ status = 'blocked';
+ detail =
+ publishedBundleState && publishedBundleState !== 'unobserved'
+ ? 'awaiting-producer-native-bundle-publication'
+ : externalBlocker
+ ? 'awaiting-compare-release-signing-blocker-clear'
+ : 'awaiting-producer-native-release-publication';
+ }
+
+ return {
+ id: 'vi-history-producer-native-distributor',
+ status,
+ ownerRepository: compareRepository,
+ dependentRepository,
+ requiredCapability: 'vi-history',
+ source: 'compare-release-signing-readiness',
+ releaseSigningStatus,
+ releasePublicationState,
+ publishedBundleState,
+ publishedBundleReleaseTag,
+ publishedBundleAuthoritativeConsumerPin,
+ signingCapabilityState,
+ signingAuthorityState,
+ releaseConductorApplyState,
+ externalBlocker,
+ detail
+ };
+}
+
function derivePortfolioMode(compareGovernorSummary, monitoringMode) {
const compareMode = asOptional(compareGovernorSummary?.summary?.governorMode);
const futureAgentAction = asOptional(monitoringMode?.summary?.futureAgentAction);
@@ -151,7 +224,136 @@ function derivePortfolioMode(compareGovernorSummary, monitoringMode) {
return compareMode || 'attention-required';
}
-function deriveOwners(compareGovernorSummary, monitoringMode, portfolioMode) {
+function deriveExecutionTopology(compareGovernorSummary) {
+ const executionTopology = compareGovernorSummary?.compare?.deliveryRuntime?.executionTopology;
+ if (executionTopology && typeof executionTopology === 'object' && !Array.isArray(executionTopology)) {
+ return {
+ status: asOptional(executionTopology.status),
+ executionPlane: asOptional(executionTopology.executionPlane),
+ providerId: asOptional(executionTopology.providerId),
+ workerSlotId: asOptional(executionTopology.workerSlotId),
+ activeLogicalLaneCount: Number.isInteger(executionTopology.activeLogicalLaneCount)
+ ? executionTopology.activeLogicalLaneCount
+ : null,
+ seededLogicalLaneCount: Number.isInteger(executionTopology.seededLogicalLaneCount)
+ ? executionTopology.seededLogicalLaneCount
+ : null,
+ catalogCount: Number.isInteger(executionTopology.catalogCount) ? executionTopology.catalogCount : 0,
+ runtimeSurface: asOptional(executionTopology.runtimeSurface),
+ processModelClass: asOptional(executionTopology.processModelClass),
+ windowsOnly: executionTopology.windowsOnly === true,
+ requestedSimultaneous: executionTopology.requestedSimultaneous === true,
+ cellClass: asOptional(executionTopology.cellClass),
+ suiteClass: asOptional(executionTopology.suiteClass),
+ operatorAuthorizationRef: asOptional(executionTopology.operatorAuthorizationRef),
+ premiumSaganMode: executionTopology.premiumSaganMode === true,
+ reciprocalLinkReady: executionTopology.reciprocalLinkReady === true,
+ logicalLaneActivation: {
+ activeLaneCount: Number.isInteger(executionTopology?.logicalLaneActivation?.activeLaneCount)
+ ? executionTopology.logicalLaneActivation.activeLaneCount
+ : null,
+ seededLaneCount: Number.isInteger(executionTopology?.logicalLaneActivation?.seededLaneCount)
+ ? executionTopology.logicalLaneActivation.seededLaneCount
+ : null,
+ catalogCount: Number.isInteger(executionTopology?.logicalLaneActivation?.catalogCount)
+ ? executionTopology.logicalLaneActivation.catalogCount
+ : 0
+ },
+ providerDispatch: {
+ providerId: asOptional(executionTopology?.providerDispatch?.providerId),
+ providerKind: asOptional(executionTopology?.providerDispatch?.providerKind),
+ executionPlane: asOptional(executionTopology?.providerDispatch?.executionPlane),
+ assignmentMode: asOptional(executionTopology?.providerDispatch?.assignmentMode),
+ dispatchSurface: asOptional(executionTopology?.providerDispatch?.dispatchSurface),
+ completionMode: asOptional(executionTopology?.providerDispatch?.completionMode),
+ workerSlotId: asOptional(executionTopology?.providerDispatch?.workerSlotId),
+ dispatchStatus: asOptional(executionTopology?.providerDispatch?.dispatchStatus),
+ completionStatus: asOptional(executionTopology?.providerDispatch?.completionStatus),
+ failureClass: asOptional(executionTopology?.providerDispatch?.failureClass)
+ },
+ executionBundle: {
+ status: asOptional(executionTopology?.executionBundle?.status),
+ planeBinding: asOptional(executionTopology?.executionBundle?.planeBinding),
+ cellClass: asOptional(executionTopology?.executionBundle?.cellClass),
+ suiteClass: asOptional(executionTopology?.executionBundle?.suiteClass),
+ premiumSaganMode: executionTopology?.executionBundle?.premiumSaganMode === true,
+ reciprocalLinkReady: executionTopology?.executionBundle?.reciprocalLinkReady === true,
+ effectiveBillableRateUsdPerHour: Number.isFinite(executionTopology?.executionBundle?.effectiveBillableRateUsdPerHour)
+ ? executionTopology.executionBundle.effectiveBillableRateUsdPerHour
+ : null,
+ executionCellLeaseId: asOptional(executionTopology?.executionBundle?.executionCellLeaseId),
+ dockerLaneLeaseId: asOptional(executionTopology?.executionBundle?.dockerLaneLeaseId),
+ harnessKind: asOptional(executionTopology?.executionBundle?.harnessKind),
+ harnessInstanceId: asOptional(executionTopology?.executionBundle?.harnessInstanceId),
+ operatorAuthorizationRef: asOptional(executionTopology?.executionBundle?.operatorAuthorizationRef),
+ cellId: asOptional(executionTopology?.executionBundle?.cellId),
+ laneId: asOptional(executionTopology?.executionBundle?.laneId),
+ isolatedLaneGroupId: asOptional(executionTopology?.executionBundle?.isolatedLaneGroupId),
+ fingerprintSha256: asOptional(executionTopology?.executionBundle?.fingerprintSha256)
+ }
+ };
+ }
+
+ return {
+ status: asOptional(compareGovernorSummary?.summary?.executionBundleStatus),
+ executionPlane: asOptional(compareGovernorSummary?.summary?.executionBundlePlaneBinding),
+ providerId: null,
+ workerSlotId: null,
+ activeLogicalLaneCount: null,
+ seededLogicalLaneCount: null,
+ catalogCount: 0,
+ runtimeSurface: asOptional(compareGovernorSummary?.summary?.executionTopologyRuntimeSurface),
+ processModelClass: asOptional(compareGovernorSummary?.summary?.executionTopologyProcessModelClass),
+ windowsOnly: compareGovernorSummary?.summary?.executionTopologyWindowsOnly === true,
+ requestedSimultaneous: compareGovernorSummary?.summary?.executionTopologyRequestedSimultaneous === true,
+ cellClass: asOptional(compareGovernorSummary?.summary?.executionTopologyCellClass),
+ suiteClass: asOptional(compareGovernorSummary?.summary?.executionTopologySuiteClass),
+ operatorAuthorizationRef: asOptional(compareGovernorSummary?.summary?.executionTopologyOperatorAuthorizationRef),
+ premiumSaganMode: compareGovernorSummary?.summary?.executionBundlePremiumSaganMode === true,
+ reciprocalLinkReady: compareGovernorSummary?.summary?.executionBundleReciprocalLinkReady === true,
+ logicalLaneActivation: {
+ activeLaneCount: null,
+ seededLaneCount: null,
+ catalogCount: 0
+ },
+ providerDispatch: {
+ providerId: null,
+ providerKind: null,
+ executionPlane: null,
+ assignmentMode: null,
+ dispatchSurface: null,
+ completionMode: null,
+ workerSlotId: null,
+ dispatchStatus: null,
+ completionStatus: null,
+ failureClass: null
+ },
+ executionBundle: {
+ status: asOptional(compareGovernorSummary?.summary?.executionBundleStatus),
+ planeBinding: asOptional(compareGovernorSummary?.summary?.executionBundlePlaneBinding),
+ cellClass: null,
+ suiteClass: null,
+ premiumSaganMode: compareGovernorSummary?.summary?.executionBundlePremiumSaganMode === true,
+ reciprocalLinkReady: compareGovernorSummary?.summary?.executionBundleReciprocalLinkReady === true,
+ effectiveBillableRateUsdPerHour: Number.isFinite(
+ compareGovernorSummary?.summary?.executionBundleEffectiveBillableRateUsdPerHour
+ )
+ ? compareGovernorSummary.summary.executionBundleEffectiveBillableRateUsdPerHour
+ : null,
+ executionCellLeaseId: null,
+ dockerLaneLeaseId: null,
+ harnessKind: null,
+ harnessInstanceId: null,
+ operatorAuthorizationRef: null,
+ cellId: null,
+ laneId: null,
+ isolatedLaneGroupId: null,
+ fingerprintSha256: null
+ }
+ };
+}
+
+function deriveOwners(compareGovernorSummary, monitoringMode, portfolioMode, viHistoryDistributorDependency) {
const compareRepository =
asOptional(compareGovernorSummary?.summary?.currentOwnerRepository) ||
asOptional(monitoringMode?.policy?.compareRepository) ||
@@ -170,6 +372,22 @@ function deriveOwners(compareGovernorSummary, monitoringMode, portfolioMode) {
}
if (portfolioMode === 'monitoring-active') {
+ if (
+ futureAgentAction === 'future-agent-may-pivot' &&
+ viHistoryDistributorDependency?.status !== 'ready' &&
+ viHistoryDistributorDependency?.dependentRepository === pivotTargetRepository
+ ) {
+ return {
+ currentOwnerRepository: compareRepository,
+ nextOwnerRepository: compareRepository,
+ nextAction:
+ viHistoryDistributorDependency.status === 'unknown'
+ ? 'refresh-compare-vi-history-distributor-dependency'
+ : 'complete-compare-vi-history-producer-release',
+ ownerDecisionSource: 'compare-vi-history-distributor-dependency'
+ };
+ }
+
return {
currentOwnerRepository: compareRepository,
nextOwnerRepository: futureAgentAction === 'future-agent-may-pivot' ? pivotTargetRepository : compareRepository,
@@ -295,13 +513,20 @@ function buildReport({
now
}) {
const portfolioMode = derivePortfolioMode(compareGovernorSummary, monitoringMode);
- const ownerDecision = deriveOwners(compareGovernorSummary, monitoringMode, portfolioMode);
+ const viHistoryDistributorDependency = deriveViHistoryDistributorDependency(compareGovernorSummary, monitoringMode);
+ const ownerDecision = deriveOwners(
+ compareGovernorSummary,
+ monitoringMode,
+ portfolioMode,
+ viHistoryDistributorDependency
+ );
const repositoryEntries = deriveRepositoryEntries(repoGraphTruth, monitoringMode, compareGovernorSummary);
const templateMonitoringStatus = deriveTemplateMonitoringStatus(repositoryEntries);
const supportedProofStatus = deriveSupportedProofStatus(repositoryEntries);
const triggeredWakeConditions = Array.isArray(monitoringMode?.summary?.triggeredWakeConditions)
? monitoringMode.summary.triggeredWakeConditions
: [];
+ const executionTopology = deriveExecutionTopology(compareGovernorSummary);
return {
schema: 'priority/autonomous-governor-portfolio-summary-report@v1',
@@ -324,11 +549,23 @@ function buildReport({
queueHandoffStatus: asOptional(compareGovernorSummary?.summary?.queueHandoffStatus),
queueHandoffNextWakeCondition: asOptional(compareGovernorSummary?.summary?.queueHandoffNextWakeCondition),
queueHandoffPrUrl: asOptional(compareGovernorSummary?.summary?.queueHandoffPrUrl),
- queueAuthoritySource: asOptional(compareGovernorSummary?.summary?.queueAuthoritySource)
+ queueAuthoritySource: asOptional(compareGovernorSummary?.summary?.queueAuthoritySource),
+ executionTopology,
+ executionBundleStatus: asOptional(compareGovernorSummary?.summary?.executionBundleStatus),
+ executionBundlePlaneBinding: asOptional(compareGovernorSummary?.summary?.executionBundlePlaneBinding),
+ executionBundlePremiumSaganMode: compareGovernorSummary?.summary?.executionBundlePremiumSaganMode === true,
+ executionBundleReciprocalLinkReady:
+ compareGovernorSummary?.summary?.executionBundleReciprocalLinkReady === true,
+ executionBundleEffectiveBillableRateUsdPerHour: Number.isFinite(
+ compareGovernorSummary?.summary?.executionBundleEffectiveBillableRateUsdPerHour
+ )
+ ? compareGovernorSummary.summary.executionBundleEffectiveBillableRateUsdPerHour
+ : null
},
portfolio: {
repositoryCount: repositoryEntries.length,
repositories: repositoryEntries,
+ dependencies: [viHistoryDistributorDependency],
unsupportedPaths: Array.isArray(monitoringMode?.templateMonitoring?.unsupportedPaths)
? monitoringMode.templateMonitoring.unsupportedPaths.map((entry) => ({
name: asOptional(entry?.name),
@@ -351,6 +588,39 @@ function buildReport({
queueHandoffNextWakeCondition: asOptional(compareGovernorSummary?.summary?.queueHandoffNextWakeCondition),
queueHandoffPrUrl: asOptional(compareGovernorSummary?.summary?.queueHandoffPrUrl),
queueAuthoritySource: asOptional(compareGovernorSummary?.summary?.queueAuthoritySource),
+ executionTopologyStatus: executionTopology.status,
+ executionTopologyExecutionPlane: executionTopology.executionPlane,
+ executionTopologyProviderId: executionTopology.providerId,
+ executionTopologyWorkerSlotId: executionTopology.workerSlotId,
+ executionTopologyActiveLogicalLaneCount: executionTopology.activeLogicalLaneCount,
+ executionTopologySeededLogicalLaneCount: executionTopology.seededLogicalLaneCount,
+ executionTopologyRuntimeSurface: executionTopology.runtimeSurface,
+ executionTopologyProcessModelClass: executionTopology.processModelClass,
+ executionTopologyWindowsOnly: executionTopology.windowsOnly,
+ executionTopologyRequestedSimultaneous: executionTopology.requestedSimultaneous,
+ executionTopologyCellClass: executionTopology.cellClass,
+ executionTopologySuiteClass: executionTopology.suiteClass,
+ executionTopologyOperatorAuthorizationRef: executionTopology.operatorAuthorizationRef,
+ executionBundleStatus: asOptional(compareGovernorSummary?.summary?.executionBundleStatus),
+ executionBundlePlaneBinding: asOptional(compareGovernorSummary?.summary?.executionBundlePlaneBinding),
+ executionBundlePremiumSaganMode: compareGovernorSummary?.summary?.executionBundlePremiumSaganMode === true,
+ executionBundleReciprocalLinkReady:
+ compareGovernorSummary?.summary?.executionBundleReciprocalLinkReady === true,
+ executionBundleEffectiveBillableRateUsdPerHour: Number.isFinite(
+ compareGovernorSummary?.summary?.executionBundleEffectiveBillableRateUsdPerHour
+ )
+ ? compareGovernorSummary.summary.executionBundleEffectiveBillableRateUsdPerHour
+ : null,
+ viHistoryDistributorDependencyStatus: viHistoryDistributorDependency.status,
+ viHistoryDistributorDependencyTargetRepository: viHistoryDistributorDependency.dependentRepository,
+ viHistoryDistributorDependencyExternalBlocker: viHistoryDistributorDependency.externalBlocker,
+ viHistoryDistributorDependencyPublicationState: viHistoryDistributorDependency.releasePublicationState,
+ viHistoryDistributorDependencyPublishedBundleState: viHistoryDistributorDependency.publishedBundleState,
+ viHistoryDistributorDependencyPublishedBundleReleaseTag: viHistoryDistributorDependency.publishedBundleReleaseTag,
+ viHistoryDistributorDependencyAuthoritativeConsumerPin:
+ viHistoryDistributorDependency.publishedBundleAuthoritativeConsumerPin,
+ viHistoryDistributorDependencySigningAuthorityState: viHistoryDistributorDependency.signingAuthorityState,
+ viHistoryDistributorDependencyReleaseConductorApplyState: viHistoryDistributorDependency.releaseConductorApplyState,
portfolioWakeConditionCount: triggeredWakeConditions.length,
triggeredWakeConditions
}
diff --git a/tools/priority/autonomous-governor-summary.mjs b/tools/priority/autonomous-governor-summary.mjs
index e8d432739..0742d148b 100644
--- a/tools/priority/autonomous-governor-summary.mjs
+++ b/tools/priority/autonomous-governor-summary.mjs
@@ -56,6 +56,13 @@ export const DEFAULT_DELIVERY_RUNTIME_STATE_PATH = path.join(
'runtime',
'delivery-agent-state.json'
);
+export const DEFAULT_RELEASE_SIGNING_READINESS_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'release',
+ 'release-signing-readiness.json'
+);
function asOptional(value) {
if (value == null) {
@@ -179,6 +186,310 @@ function parseBoolean(value) {
return value === true;
}
+function coalesceBoolean(...values) {
+ for (const value of values) {
+ if (typeof value === 'boolean') {
+ return value;
+ }
+ }
+ return false;
+}
+
+function normalizeLower(value) {
+ return typeof value === 'string' ? value.trim().toLowerCase() : '';
+}
+
+function deriveExecutionTopologyProcessModel(executionBundle) {
+ const planeBinding = asOptional(executionBundle?.planeBinding);
+ const normalizedPlaneBinding = normalizeLower(planeBinding);
+ const harnessKind = asOptional(executionBundle?.harnessKind);
+ const requestedSimultaneous = normalizedPlaneBinding === 'dual-plane-parity';
+ const windowsNativeTestStand =
+ (!harnessKind || harnessKind === 'teststand-compare-harness') &&
+ (requestedSimultaneous || normalizedPlaneBinding.startsWith('native-labview-'));
+ const runtimeSurface = windowsNativeTestStand ? 'windows-native-teststand' : null;
+ const processModelClass = !runtimeSurface
+ ? null
+ : requestedSimultaneous
+ ? 'parallel-process-model'
+ : 'sequential-process-model';
+
+ return {
+ runtimeSurface,
+ processModelClass,
+ windowsOnly: runtimeSurface === 'windows-native-teststand',
+ requestedSimultaneous
+ };
+}
+
+function deriveExecutionTopologyStatus({ activeLogicalLaneCount, seededLogicalLaneCount, providerDispatch, executionBundle }) {
+ const bundleStatus = asOptional(executionBundle?.status);
+ if (bundleStatus) {
+ return `bundle-${bundleStatus}`;
+ }
+
+ const completionStatus = asOptional(providerDispatch?.completionStatus);
+ if (completionStatus) {
+ return `provider-${completionStatus}`;
+ }
+
+ const dispatchStatus = asOptional(providerDispatch?.dispatchStatus);
+ if (dispatchStatus) {
+ return `provider-${dispatchStatus}`;
+ }
+
+ if ((activeLogicalLaneCount ?? 0) > 0 || (seededLogicalLaneCount ?? 0) > 0) {
+ return 'logical-lanes-tracked';
+ }
+
+ return 'none';
+}
+
+function deriveExecutionTopology({ deliveryRuntimeState, activeLane, executionBundle }) {
+ const logicalLaneActivation = normalizeOptionalObject(deliveryRuntimeState?.logicalLaneActivation);
+ const logicalLaneCatalog = Array.isArray(logicalLaneActivation?.catalog) ? logicalLaneActivation.catalog : [];
+ const providerDispatch =
+ normalizeOptionalObject(activeLane?.providerDispatch) ??
+ normalizeOptionalObject(deliveryRuntimeState?.artifacts?.providerDispatch);
+ const activeLaneExecutionTopology = normalizeOptionalObject(activeLane?.executionTopology);
+ const activeLogicalLaneCountFallback = Number.isInteger(logicalLaneActivation?.activeLaneCount)
+ ? logicalLaneActivation.activeLaneCount
+ : null;
+ const seededLogicalLaneCountFallback = Number.isInteger(logicalLaneActivation?.seededLaneCount)
+ ? logicalLaneActivation.seededLaneCount
+ : null;
+
+ if (activeLaneExecutionTopology) {
+ const topologyLogicalLaneActivation = normalizeOptionalObject(activeLaneExecutionTopology.logicalLaneActivation);
+ const topologyProviderDispatch = normalizeOptionalObject(activeLaneExecutionTopology.providerDispatch);
+ const topologyExecutionBundle = normalizeOptionalObject(activeLaneExecutionTopology.executionBundle);
+ const effectiveProviderDispatch = topologyProviderDispatch ?? providerDispatch;
+ const effectiveExecutionBundle = topologyExecutionBundle ?? executionBundle;
+ const processModel = deriveExecutionTopologyProcessModel(effectiveExecutionBundle);
+ const activeLogicalLaneCount = Number.isInteger(activeLaneExecutionTopology.activeLogicalLaneCount)
+ ? activeLaneExecutionTopology.activeLogicalLaneCount
+ : Number.isInteger(topologyLogicalLaneActivation?.activeLaneCount)
+ ? topologyLogicalLaneActivation.activeLaneCount
+ : activeLogicalLaneCountFallback;
+ const seededLogicalLaneCount = Number.isInteger(activeLaneExecutionTopology.seededLogicalLaneCount)
+ ? activeLaneExecutionTopology.seededLogicalLaneCount
+ : Number.isInteger(topologyLogicalLaneActivation?.seededLaneCount)
+ ? topologyLogicalLaneActivation.seededLaneCount
+ : seededLogicalLaneCountFallback;
+ const catalogCount = Number.isInteger(activeLaneExecutionTopology.catalogCount)
+ ? activeLaneExecutionTopology.catalogCount
+ : Number.isInteger(topologyLogicalLaneActivation?.catalogCount)
+ ? topologyLogicalLaneActivation.catalogCount
+ : logicalLaneCatalog.length;
+ const executionPlane =
+ asOptional(activeLaneExecutionTopology.executionPlane) ||
+ asOptional(topologyProviderDispatch?.executionPlane) ||
+ asOptional(providerDispatch?.executionPlane) ||
+ asOptional(activeLaneExecutionTopology.planeBinding) ||
+ asOptional(topologyExecutionBundle?.planeBinding) ||
+ asOptional(executionBundle?.planeBinding);
+
+ return {
+ status:
+ asOptional(activeLaneExecutionTopology.status) ||
+ deriveExecutionTopologyStatus({
+ activeLogicalLaneCount,
+ seededLogicalLaneCount,
+ providerDispatch: effectiveProviderDispatch,
+ executionBundle: effectiveExecutionBundle
+ }),
+ executionPlane,
+ providerId:
+ asOptional(activeLaneExecutionTopology.providerId) ||
+ asOptional(topologyProviderDispatch?.providerId) ||
+ asOptional(providerDispatch?.providerId),
+ workerSlotId:
+ asOptional(activeLaneExecutionTopology.workerSlotId) ||
+ asOptional(topologyProviderDispatch?.workerSlotId) ||
+ asOptional(providerDispatch?.workerSlotId),
+ activeLogicalLaneCount,
+ seededLogicalLaneCount,
+ catalogCount,
+ runtimeSurface: asOptional(activeLaneExecutionTopology.runtimeSurface) || processModel.runtimeSurface,
+ processModelClass: asOptional(activeLaneExecutionTopology.processModelClass) || processModel.processModelClass,
+ windowsOnly: coalesceBoolean(activeLaneExecutionTopology.windowsOnly, processModel.windowsOnly),
+ requestedSimultaneous: coalesceBoolean(
+ activeLaneExecutionTopology.requestedSimultaneous,
+ processModel.requestedSimultaneous
+ ),
+ cellClass:
+ asOptional(activeLaneExecutionTopology.cellClass) ||
+ asOptional(topologyExecutionBundle?.cellClass) ||
+ asOptional(executionBundle?.cellClass),
+ suiteClass:
+ asOptional(activeLaneExecutionTopology.suiteClass) ||
+ asOptional(topologyExecutionBundle?.suiteClass) ||
+ asOptional(executionBundle?.suiteClass),
+ operatorAuthorizationRef:
+ asOptional(activeLaneExecutionTopology.operatorAuthorizationRef) ||
+ asOptional(topologyExecutionBundle?.operatorAuthorizationRef) ||
+ asOptional(executionBundle?.operatorAuthorizationRef),
+ premiumSaganMode: coalesceBoolean(
+ activeLaneExecutionTopology.premiumSaganMode,
+ topologyExecutionBundle?.premiumSaganMode,
+ executionBundle?.premiumSaganMode
+ ),
+ reciprocalLinkReady: coalesceBoolean(
+ activeLaneExecutionTopology.reciprocalLinkReady,
+ topologyExecutionBundle?.reciprocalLinkReady,
+ executionBundle?.reciprocalLinkReady
+ ),
+ logicalLaneActivation: {
+ activeLaneCount: activeLogicalLaneCount,
+ seededLaneCount: seededLogicalLaneCount,
+ catalogCount
+ },
+ providerDispatch: {
+ providerId: asOptional(topologyProviderDispatch?.providerId) || asOptional(providerDispatch?.providerId),
+ providerKind: asOptional(topologyProviderDispatch?.providerKind) || asOptional(providerDispatch?.providerKind),
+ executionPlane,
+ assignmentMode:
+ asOptional(topologyProviderDispatch?.assignmentMode) || asOptional(providerDispatch?.assignmentMode),
+ dispatchSurface:
+ asOptional(topologyProviderDispatch?.dispatchSurface) || asOptional(providerDispatch?.dispatchSurface),
+ completionMode:
+ asOptional(topologyProviderDispatch?.completionMode) || asOptional(providerDispatch?.completionMode),
+ workerSlotId:
+ asOptional(topologyProviderDispatch?.workerSlotId) || asOptional(providerDispatch?.workerSlotId),
+ dispatchStatus:
+ asOptional(topologyProviderDispatch?.dispatchStatus) || asOptional(providerDispatch?.dispatchStatus),
+ completionStatus:
+ asOptional(topologyProviderDispatch?.completionStatus) || asOptional(providerDispatch?.completionStatus),
+ failureClass:
+ asOptional(topologyProviderDispatch?.failureClass) || asOptional(providerDispatch?.failureClass)
+ },
+ executionBundle: {
+ status: asOptional(topologyExecutionBundle?.status) || asOptional(executionBundle?.status),
+ planeBinding:
+ asOptional(activeLaneExecutionTopology.planeBinding) ||
+ asOptional(topologyExecutionBundle?.planeBinding) ||
+ asOptional(executionBundle?.planeBinding),
+ cellClass:
+ asOptional(topologyExecutionBundle?.cellClass) || asOptional(executionBundle?.cellClass),
+ suiteClass:
+ asOptional(topologyExecutionBundle?.suiteClass) || asOptional(executionBundle?.suiteClass),
+ premiumSaganMode: coalesceBoolean(
+ topologyExecutionBundle?.premiumSaganMode,
+ executionBundle?.premiumSaganMode
+ ),
+ reciprocalLinkReady: coalesceBoolean(
+ topologyExecutionBundle?.reciprocalLinkReady,
+ executionBundle?.reciprocalLinkReady
+ ),
+ effectiveBillableRateUsdPerHour: Number.isFinite(topologyExecutionBundle?.effectiveBillableRateUsdPerHour)
+ ? topologyExecutionBundle.effectiveBillableRateUsdPerHour
+ : Number.isFinite(executionBundle?.effectiveBillableRateUsdPerHour)
+ ? executionBundle.effectiveBillableRateUsdPerHour
+ : null,
+ executionCellLeaseId:
+ asOptional(activeLaneExecutionTopology.executionCellLeaseId) ||
+ asOptional(topologyExecutionBundle?.executionCellLeaseId) ||
+ asOptional(executionBundle?.executionCellLeaseId),
+ dockerLaneLeaseId:
+ asOptional(activeLaneExecutionTopology.dockerLaneLeaseId) ||
+ asOptional(topologyExecutionBundle?.dockerLaneLeaseId) ||
+ asOptional(executionBundle?.dockerLaneLeaseId),
+ harnessKind:
+ asOptional(activeLaneExecutionTopology.harnessKind) ||
+ asOptional(topologyExecutionBundle?.harnessKind) ||
+ asOptional(executionBundle?.harnessKind),
+ harnessInstanceId:
+ asOptional(activeLaneExecutionTopology.harnessInstanceId) ||
+ asOptional(topologyExecutionBundle?.harnessInstanceId) ||
+ asOptional(executionBundle?.harnessInstanceId),
+ operatorAuthorizationRef:
+ asOptional(topologyExecutionBundle?.operatorAuthorizationRef) ||
+ asOptional(executionBundle?.operatorAuthorizationRef),
+ cellId:
+ asOptional(activeLaneExecutionTopology.cellId) ||
+ asOptional(topologyExecutionBundle?.cellId) ||
+ asOptional(executionBundle?.cellId),
+ laneId:
+ asOptional(activeLaneExecutionTopology.laneId) ||
+ asOptional(topologyExecutionBundle?.laneId) ||
+ asOptional(executionBundle?.laneId),
+ isolatedLaneGroupId:
+ asOptional(topologyExecutionBundle?.isolatedLaneGroupId) ||
+ asOptional(executionBundle?.isolatedLaneGroupId),
+ fingerprintSha256:
+ asOptional(topologyExecutionBundle?.fingerprintSha256) ||
+ asOptional(executionBundle?.fingerprintSha256)
+ }
+ };
+ }
+
+ const processModel = deriveExecutionTopologyProcessModel(executionBundle);
+ const activeLogicalLaneCount = activeLogicalLaneCountFallback;
+ const seededLogicalLaneCount = seededLogicalLaneCountFallback;
+ const executionPlane = asOptional(providerDispatch?.executionPlane) || asOptional(executionBundle?.planeBinding);
+
+ return {
+ status: deriveExecutionTopologyStatus({
+ activeLogicalLaneCount,
+ seededLogicalLaneCount,
+ providerDispatch,
+ executionBundle
+ }),
+ executionPlane,
+ providerId: asOptional(providerDispatch?.providerId),
+ workerSlotId: asOptional(providerDispatch?.workerSlotId),
+ activeLogicalLaneCount,
+ seededLogicalLaneCount,
+ catalogCount: logicalLaneCatalog.length,
+ runtimeSurface: processModel.runtimeSurface,
+ processModelClass: processModel.processModelClass,
+ windowsOnly: processModel.windowsOnly,
+ requestedSimultaneous: processModel.requestedSimultaneous,
+ cellClass: asOptional(executionBundle?.cellClass),
+ suiteClass: asOptional(executionBundle?.suiteClass),
+ operatorAuthorizationRef: asOptional(executionBundle?.operatorAuthorizationRef),
+ premiumSaganMode: parseBoolean(executionBundle?.premiumSaganMode),
+ reciprocalLinkReady: parseBoolean(executionBundle?.reciprocalLinkReady),
+ logicalLaneActivation: {
+ activeLaneCount: activeLogicalLaneCount,
+ seededLaneCount: seededLogicalLaneCount,
+ catalogCount: logicalLaneCatalog.length
+ },
+ providerDispatch: {
+ providerId: asOptional(providerDispatch?.providerId),
+ providerKind: asOptional(providerDispatch?.providerKind),
+ executionPlane,
+ assignmentMode: asOptional(providerDispatch?.assignmentMode),
+ dispatchSurface: asOptional(providerDispatch?.dispatchSurface),
+ completionMode: asOptional(providerDispatch?.completionMode),
+ workerSlotId: asOptional(providerDispatch?.workerSlotId),
+ dispatchStatus: asOptional(providerDispatch?.dispatchStatus),
+ completionStatus: asOptional(providerDispatch?.completionStatus),
+ failureClass: asOptional(providerDispatch?.failureClass)
+ },
+ executionBundle: {
+ status: asOptional(executionBundle?.status),
+ planeBinding: asOptional(executionBundle?.planeBinding),
+ cellClass: asOptional(executionBundle?.cellClass),
+ suiteClass: asOptional(executionBundle?.suiteClass),
+ premiumSaganMode: parseBoolean(executionBundle?.premiumSaganMode),
+ reciprocalLinkReady: parseBoolean(executionBundle?.reciprocalLinkReady),
+ effectiveBillableRateUsdPerHour: Number.isFinite(executionBundle?.effectiveBillableRateUsdPerHour)
+ ? executionBundle.effectiveBillableRateUsdPerHour
+ : null,
+ executionCellLeaseId: asOptional(executionBundle?.executionCellLeaseId),
+ dockerLaneLeaseId: asOptional(executionBundle?.dockerLaneLeaseId),
+ harnessKind: asOptional(executionBundle?.harnessKind),
+ harnessInstanceId: asOptional(executionBundle?.harnessInstanceId),
+ operatorAuthorizationRef: asOptional(executionBundle?.operatorAuthorizationRef),
+ cellId: asOptional(executionBundle?.cellId),
+ laneId: asOptional(executionBundle?.laneId),
+ isolatedLaneGroupId: asOptional(executionBundle?.isolatedLaneGroupId),
+ fingerprintSha256: asOptional(executionBundle?.fingerprintSha256)
+ }
+ };
+}
+
export function parseArgs(argv = process.argv) {
const args = argv.slice(2);
const options = {
@@ -189,6 +500,7 @@ export function parseArgs(argv = process.argv) {
wakeLifecyclePath: DEFAULT_WAKE_LIFECYCLE_PATH,
wakeInvestmentAccountingPath: DEFAULT_WAKE_INVESTMENT_ACCOUNTING_PATH,
deliveryRuntimeStatePath: DEFAULT_DELIVERY_RUNTIME_STATE_PATH,
+ releaseSigningReadinessPath: DEFAULT_RELEASE_SIGNING_READINESS_PATH,
outputPath: DEFAULT_OUTPUT_PATH,
help: false
};
@@ -201,6 +513,7 @@ export function parseArgs(argv = process.argv) {
['--wake-lifecycle', 'wakeLifecyclePath'],
['--wake-investment-accounting', 'wakeInvestmentAccountingPath'],
['--delivery-runtime-state', 'deliveryRuntimeStatePath'],
+ ['--release-signing-readiness', 'releaseSigningReadinessPath'],
['--output', 'outputPath']
]);
@@ -237,6 +550,7 @@ function printHelp() {
` --wake-lifecycle Wake lifecycle path (default: ${DEFAULT_WAKE_LIFECYCLE_PATH}).`,
` --wake-investment-accounting Wake investment accounting path (default: ${DEFAULT_WAKE_INVESTMENT_ACCOUNTING_PATH}).`,
` --delivery-runtime-state Delivery runtime state path (default: ${DEFAULT_DELIVERY_RUNTIME_STATE_PATH}).`,
+ ` --release-signing-readiness Release signing readiness path (default: ${DEFAULT_RELEASE_SIGNING_READINESS_PATH}).`,
` --output Output path (default: ${DEFAULT_OUTPUT_PATH}).`,
' -h, --help Show help.'
].forEach((line) => console.log(line));
@@ -328,6 +642,42 @@ function deriveFunding(wakeInvestmentAccounting) {
};
}
+function deriveReleaseSigningReadiness(releaseSigningReadinessReport) {
+ if (releaseSigningReadinessReport?.schema !== 'priority/release-signing-readiness-report@v1') {
+ return {
+ status: 'missing',
+ codePathState: null,
+ signingCapabilityState: null,
+ signingAuthorityState: null,
+ releaseConductorApplyState: null,
+ publicationState: null,
+ publishedBundleState: null,
+ publishedBundleReleaseTag: null,
+ publishedBundleAuthoritativeConsumerPin: null,
+ externalBlocker: null,
+ blockerCount: 0
+ };
+ }
+
+ return {
+ status: asOptional(releaseSigningReadinessReport?.summary?.status) || 'missing',
+ codePathState: asOptional(releaseSigningReadinessReport?.summary?.codePathState),
+ signingCapabilityState: asOptional(releaseSigningReadinessReport?.summary?.signingCapabilityState),
+ signingAuthorityState: asOptional(releaseSigningReadinessReport?.summary?.signingAuthorityState),
+ releaseConductorApplyState: asOptional(releaseSigningReadinessReport?.summary?.releaseConductorApplyState),
+ publicationState: asOptional(releaseSigningReadinessReport?.summary?.publicationState),
+ publishedBundleState: asOptional(releaseSigningReadinessReport?.summary?.publishedBundleState),
+ publishedBundleReleaseTag: asOptional(releaseSigningReadinessReport?.summary?.publishedBundleReleaseTag),
+ publishedBundleAuthoritativeConsumerPin: asOptional(
+ releaseSigningReadinessReport?.summary?.publishedBundleAuthoritativeConsumerPin
+ ),
+ externalBlocker: asOptional(releaseSigningReadinessReport?.summary?.externalBlocker),
+ blockerCount: Number.isInteger(releaseSigningReadinessReport?.summary?.blockerCount)
+ ? releaseSigningReadinessReport.summary.blockerCount
+ : 0
+ };
+}
+
function deriveDeliveryRuntime(deliveryRuntimeState) {
const activeLane = deliveryRuntimeState?.activeLane || {};
const prUrl = asOptional(activeLane?.prUrl);
@@ -337,6 +687,9 @@ function deriveDeliveryRuntime(deliveryRuntimeState) {
const queueAuthorityRefresh =
normalizeOptionalObject(activeLane?.queueAuthorityRefresh) ??
normalizeOptionalObject(deliveryRuntimeState?.queueAuthorityRefresh);
+ const concurrentLaneStatus = normalizeOptionalObject(activeLane?.concurrentLaneStatus);
+ const executionBundle = normalizeOptionalObject(concurrentLaneStatus?.executionBundle);
+ const executionTopology = deriveExecutionTopology({ deliveryRuntimeState, activeLane, executionBundle });
let status = 'none';
if (prUrl) {
@@ -359,6 +712,27 @@ function deriveDeliveryRuntime(deliveryRuntimeState) {
outcome,
blockerClass,
nextWakeCondition: asOptional(activeLane?.nextWakeCondition),
+ executionTopology,
+ executionBundle: {
+ status: asOptional(executionBundle?.status),
+ planeBinding: asOptional(executionBundle?.planeBinding),
+ cellClass: asOptional(executionBundle?.cellClass),
+ suiteClass: asOptional(executionBundle?.suiteClass),
+ premiumSaganMode: parseBoolean(executionBundle?.premiumSaganMode),
+ reciprocalLinkReady: parseBoolean(executionBundle?.reciprocalLinkReady),
+ effectiveBillableRateUsdPerHour: Number.isFinite(executionBundle?.effectiveBillableRateUsdPerHour)
+ ? executionBundle.effectiveBillableRateUsdPerHour
+ : null,
+ executionCellLeaseId: asOptional(executionBundle?.executionCellLeaseId),
+ dockerLaneLeaseId: asOptional(executionBundle?.dockerLaneLeaseId),
+ harnessKind: asOptional(executionBundle?.harnessKind),
+ harnessInstanceId: asOptional(executionBundle?.harnessInstanceId),
+ operatorAuthorizationRef: asOptional(executionBundle?.operatorAuthorizationRef),
+ cellId: asOptional(executionBundle?.cellId),
+ laneId: asOptional(executionBundle?.laneId),
+ isolatedLaneGroupId: asOptional(executionBundle?.isolatedLaneGroupId),
+ fingerprintSha256: asOptional(executionBundle?.fingerprintSha256)
+ },
queueAuthorityRefresh: {
attempted: queueAuthorityRefresh?.attempted === true,
status: asOptional(queueAuthorityRefresh?.status),
@@ -607,6 +981,8 @@ function buildReport({
wakeInvestmentAccounting,
deliveryRuntimeStatePath,
deliveryRuntimeState,
+ releaseSigningReadinessPath,
+ releaseSigningReadinessReport,
readOptionalJsonFn,
now
}) {
@@ -620,6 +996,7 @@ function buildReport({
const continuity = deriveContinuity(continuitySummary, monitoringMode);
const wake = deriveWake(wakeLifecycle);
const funding = deriveFunding(wakeInvestmentAccounting);
+ const releaseSigningReadiness = deriveReleaseSigningReadiness(releaseSigningReadinessReport);
const deliveryRuntime = deriveDeliveryRuntime(deliveryRuntimeState);
const queueAuthority = deriveQueueAuthority({
repoRoot,
@@ -642,7 +1019,8 @@ function buildReport({
monitoringModePath: toRelative(repoRoot, monitoringModePath),
wakeLifecyclePath: toRelative(repoRoot, wakeLifecyclePath),
wakeInvestmentAccountingPath: toRelative(repoRoot, wakeInvestmentAccountingPath),
- deliveryRuntimeStatePath: toRelative(repoRoot, deliveryRuntimeStatePath)
+ deliveryRuntimeStatePath: toRelative(repoRoot, deliveryRuntimeStatePath),
+ releaseSigningReadinessPath: toRelative(repoRoot, releaseSigningReadinessPath)
},
compare: {
queueState,
@@ -654,6 +1032,7 @@ function buildReport({
? monitoringMode.summary.wakeConditionCount
: null
},
+ releaseSigningReadiness,
deliveryRuntime,
queueAuthority
},
@@ -670,6 +1049,32 @@ function buildReport({
wakeTerminalState: wake.terminalState,
monitoringStatus: asOptional(monitoringMode?.summary?.status),
futureAgentAction: asOptional(monitoringMode?.summary?.futureAgentAction),
+ releaseSigningStatus: releaseSigningReadiness.status,
+ releaseSigningAuthorityState: releaseSigningReadiness.signingAuthorityState,
+ releaseConductorApplyState: releaseSigningReadiness.releaseConductorApplyState,
+ releaseSigningExternalBlocker: releaseSigningReadiness.externalBlocker,
+ releasePublicationState: releaseSigningReadiness.publicationState,
+ releasePublishedBundleState: releaseSigningReadiness.publishedBundleState,
+ releasePublishedBundleReleaseTag: releaseSigningReadiness.publishedBundleReleaseTag,
+ releasePublishedBundleAuthoritativeConsumerPin: releaseSigningReadiness.publishedBundleAuthoritativeConsumerPin,
+ executionTopologyStatus: deliveryRuntime.executionTopology.status,
+ executionTopologyExecutionPlane: deliveryRuntime.executionTopology.executionPlane,
+ executionTopologyProviderId: deliveryRuntime.executionTopology.providerId,
+ executionTopologyWorkerSlotId: deliveryRuntime.executionTopology.workerSlotId,
+ executionTopologyActiveLogicalLaneCount: deliveryRuntime.executionTopology.activeLogicalLaneCount,
+ executionTopologySeededLogicalLaneCount: deliveryRuntime.executionTopology.seededLogicalLaneCount,
+ executionTopologyRuntimeSurface: deliveryRuntime.executionTopology.runtimeSurface,
+ executionTopologyProcessModelClass: deliveryRuntime.executionTopology.processModelClass,
+ executionTopologyWindowsOnly: deliveryRuntime.executionTopology.windowsOnly,
+ executionTopologyRequestedSimultaneous: deliveryRuntime.executionTopology.requestedSimultaneous,
+ executionTopologyCellClass: deliveryRuntime.executionTopology.cellClass,
+ executionTopologySuiteClass: deliveryRuntime.executionTopology.suiteClass,
+ executionTopologyOperatorAuthorizationRef: deliveryRuntime.executionTopology.operatorAuthorizationRef,
+ executionBundleStatus: deliveryRuntime.executionBundle.status,
+ executionBundlePlaneBinding: deliveryRuntime.executionBundle.planeBinding,
+ executionBundlePremiumSaganMode: deliveryRuntime.executionBundle.premiumSaganMode,
+ executionBundleReciprocalLinkReady: deliveryRuntime.executionBundle.reciprocalLinkReady,
+ executionBundleEffectiveBillableRateUsdPerHour: deliveryRuntime.executionBundle.effectiveBillableRateUsdPerHour,
queueHandoffStatus: queueAuthority.status,
queueHandoffNextWakeCondition: queueAuthority.nextWakeCondition,
queueHandoffPrUrl: queueAuthority.prUrl,
@@ -692,6 +1097,10 @@ export async function runAutonomousGovernorSummary(options = {}, deps = {}) {
repoRoot,
options.deliveryRuntimeStatePath || DEFAULT_DELIVERY_RUNTIME_STATE_PATH
);
+ const releaseSigningReadinessPath = path.resolve(
+ repoRoot,
+ options.releaseSigningReadinessPath || DEFAULT_RELEASE_SIGNING_READINESS_PATH
+ );
const outputPath = path.resolve(repoRoot, options.outputPath || DEFAULT_OUTPUT_PATH);
const readOptionalJsonFn = deps.readOptionalJsonFn || readOptionalJson;
@@ -704,6 +1113,7 @@ export async function runAutonomousGovernorSummary(options = {}, deps = {}) {
const wakeLifecycle = readOptionalJsonFn(wakeLifecyclePath);
const wakeInvestmentAccounting = readOptionalJsonFn(wakeInvestmentAccountingPath);
const deliveryRuntimeState = readOptionalJsonFn(deliveryRuntimeStatePath);
+ const releaseSigningReadinessReport = readOptionalJsonFn(releaseSigningReadinessPath);
if (queueEmptyReport) {
ensureSchema(queueEmptyReport, queueEmptyReportPath, 'standing-priority/no-standing@v1');
@@ -723,6 +1133,13 @@ export async function runAutonomousGovernorSummary(options = {}, deps = {}) {
if (deliveryRuntimeState) {
ensureSchema(deliveryRuntimeState, deliveryRuntimeStatePath, 'priority/delivery-agent-runtime-state@v1');
}
+ if (releaseSigningReadinessReport) {
+ ensureSchema(
+ releaseSigningReadinessReport,
+ releaseSigningReadinessPath,
+ 'priority/release-signing-readiness-report@v1'
+ );
+ }
const report = buildReport({
repoRoot,
@@ -738,6 +1155,8 @@ export async function runAutonomousGovernorSummary(options = {}, deps = {}) {
wakeInvestmentAccounting,
deliveryRuntimeStatePath,
deliveryRuntimeState,
+ releaseSigningReadinessPath,
+ releaseSigningReadinessReport,
readOptionalJsonFn,
now
});
diff --git a/tools/priority/concurrent-lane-status.mjs b/tools/priority/concurrent-lane-status.mjs
index 651d412f1..99540e136 100644
--- a/tools/priority/concurrent-lane-status.mjs
+++ b/tools/priority/concurrent-lane-status.mjs
@@ -8,6 +8,10 @@ import {
CONCURRENT_LANE_APPLY_RECEIPT_SCHEMA,
DEFAULT_OUTPUT_PATH as DEFAULT_APPLY_RECEIPT_PATH
} from './concurrent-lane-apply.mjs';
+import {
+ DEFAULT_OUTPUT_PATH as DEFAULT_EXECUTION_BUNDLE_RECEIPT_PATH,
+ EXECUTION_CELL_BUNDLE_REPORT_SCHEMA
+} from './execution-cell-bundle.mjs';
import { ensureGhCli, resolveUpstream, runGhGraphql, runGhJson } from './lib/remote-utils.mjs';
import { getRepoRoot } from './lib/branch-utils.mjs';
@@ -54,6 +58,17 @@ async function readJsonRequired(filePath) {
return JSON.parse(await fs.readFile(filePath, 'utf8'));
}
+async function readJsonIfPresent(filePath) {
+ try {
+ return JSON.parse(await fs.readFile(filePath, 'utf8'));
+ } catch (error) {
+ if (error?.code === 'ENOENT') {
+ return null;
+ }
+ throw error;
+ }
+}
+
async function writeReceipt(outputPath, receipt) {
const resolved = path.resolve(process.cwd(), outputPath);
await fs.mkdir(path.dirname(resolved), { recursive: true });
@@ -187,6 +202,36 @@ function determineReceiptStatus({ applyReceipt, hostedObservationStatus, pullReq
return 'settled';
}
+function projectExecutionBundleReceipt(receiptPath, receipt) {
+ if (!receipt || receipt.schema !== EXECUTION_CELL_BUNDLE_REPORT_SCHEMA) {
+ return null;
+ }
+
+ const summary = receipt.summary && typeof receipt.summary === 'object' ? receipt.summary : {};
+ return {
+ path: toOptionalText(receiptPath),
+ schema: toOptionalText(receipt.schema),
+ status: toOptionalText(receipt.status),
+ cellId: toOptionalText(receipt.cellId),
+ laneId: toOptionalText(receipt.laneId),
+ cellClass: toOptionalText(summary.cellClass),
+ suiteClass: toOptionalText(summary.suiteClass),
+ executionCellLeaseId: toOptionalText(summary.executionCellLeaseId),
+ dockerLaneLeaseId: toOptionalText(summary.dockerLaneLeaseId),
+ harnessKind: toOptionalText(summary.harnessKind),
+ harnessInstanceId: toOptionalText(summary.harnessInstanceId),
+ planeBinding: toOptionalText(summary.planeBinding),
+ premiumSaganMode: summary.premiumSaganMode === true,
+ reciprocalLinkReady: summary.reciprocalLinkReady === true,
+ effectiveBillableRateUsdPerHour: Number.isFinite(summary.effectiveBillableRateUsdPerHour)
+ ? summary.effectiveBillableRateUsdPerHour
+ : null,
+ operatorAuthorizationRef: toOptionalText(summary.operatorAuthorizationRef),
+ isolatedLaneGroupId: toOptionalText(summary.isolatedLaneGroupId),
+ fingerprintSha256: toOptionalText(summary.fingerprintSha256)
+ };
+}
+
const IDLE_CLASSIFICATION_STATES = Object.freeze([
'waiting-hosted',
'waiting-merge',
@@ -367,6 +412,7 @@ export function parseArgs(argv = process.argv) {
const args = argv.slice(2);
const options = {
applyReceiptPath: DEFAULT_APPLY_RECEIPT_PATH,
+ executionBundleReceiptPath: DEFAULT_EXECUTION_BUNDLE_RECEIPT_PATH,
outputPath: DEFAULT_STATUS_OUTPUT_PATH,
repo: null,
pr: null,
@@ -381,12 +427,20 @@ export function parseArgs(argv = process.argv) {
options.help = true;
continue;
}
- if (token === '--apply-receipt' || token === '--output' || token === '--repo' || token === '--pr' || token === '--ref') {
+ if (
+ token === '--apply-receipt' ||
+ token === '--execution-bundle-receipt' ||
+ token === '--output' ||
+ token === '--repo' ||
+ token === '--pr' ||
+ token === '--ref'
+ ) {
if (!next || next.startsWith('-')) {
throw new Error(`Missing value for ${token}.`);
}
index += 1;
if (token === '--apply-receipt') options.applyReceiptPath = next;
+ if (token === '--execution-bundle-receipt') options.executionBundleReceiptPath = next;
if (token === '--output') options.outputPath = next;
if (token === '--repo') options.repo = next;
if (token === '--pr') options.pr = next;
@@ -690,6 +744,7 @@ function observePullRequest({
export function buildConcurrentLaneStatusReceipt({
applyReceiptPath,
applyReceipt,
+ executionBundle,
hostedRun,
pullRequest,
laneStatuses,
@@ -727,6 +782,7 @@ export function buildConcurrentLaneStatusReceipt({
recommendedBundleId: toOptionalText(applyReceipt?.plan?.recommendedBundleId),
selectedBundleId: toOptionalText(applyReceipt?.plan?.selectedBundle?.id)
},
+ executionBundle: executionBundle ?? null,
hostedRun,
pullRequest,
laneStatuses: enrichedLaneStatuses,
@@ -742,6 +798,9 @@ export function buildConcurrentLaneStatusReceipt({
deferredLaneCount,
manualLaneCount: laneStatuses.filter((entry) => entry.executionPlane === 'local').length,
shadowLaneCount: laneStatuses.filter((entry) => entry.executionPlane === 'local-shadow').length,
+ executionBundleStatus: toOptionalText(executionBundle?.status),
+ executionBundleReciprocalLinkReady: executionBundle?.reciprocalLinkReady === true,
+ executionBundlePremiumSaganMode: executionBundle?.premiumSaganMode === true,
pullRequestStatus: pullRequest?.observationStatus ?? 'not-requested',
idleClassificationCoverage,
orchestratorDisposition: determineOrchestratorDisposition({
@@ -766,6 +825,7 @@ export async function observeConcurrentLaneStatus(
) {
const repoRoot = getRepoRootFn();
const applyReceiptPath = path.resolve(repoRoot, options.applyReceiptPath);
+ const executionBundleReceiptPath = path.resolve(repoRoot, options.executionBundleReceiptPath);
const applyReceipt = await readJsonRequired(applyReceiptPath);
if (applyReceipt?.schema !== CONCURRENT_LANE_APPLY_RECEIPT_SCHEMA) {
throw new Error(
@@ -773,6 +833,11 @@ export async function observeConcurrentLaneStatus(
);
}
+ const executionBundle = projectExecutionBundleReceipt(
+ executionBundleReceiptPath,
+ await readJsonIfPresent(executionBundleReceiptPath)
+ );
+
const repository =
toOptionalText(options.repo) ??
toOptionalText(applyReceipt?.repository) ??
@@ -835,6 +900,7 @@ export async function observeConcurrentLaneStatus(
const receipt = buildConcurrentLaneStatusReceipt({
applyReceiptPath,
applyReceipt,
+ executionBundle,
hostedRun,
pullRequest,
laneStatuses,
@@ -850,6 +916,9 @@ function printUsage() {
console.log('');
console.log('Options:');
console.log(` --apply-receipt Concurrent lane apply receipt path (default: ${DEFAULT_APPLY_RECEIPT_PATH})`);
+ console.log(
+ ` --execution-bundle-receipt Execution bundle receipt path (default: ${DEFAULT_EXECUTION_BUNDLE_RECEIPT_PATH})`
+ );
console.log(` --output Status receipt path (default: ${DEFAULT_STATUS_OUTPUT_PATH})`);
console.log(' --repo Repository override for hosted run and PR observation.');
console.log(' --pr Pull request number override for merge-queue observation.');
diff --git a/tools/priority/delivery-agent.mjs b/tools/priority/delivery-agent.mjs
index 20bcedbe8..d07ab0db4 100644
--- a/tools/priority/delivery-agent.mjs
+++ b/tools/priority/delivery-agent.mjs
@@ -956,6 +956,120 @@ function buildWorkerProviderDispatchReceipt(providerSelection, {
};
}
+function coerceNonNegativeInteger(value) {
+ const parsed = Number(value);
+ if (!Number.isInteger(parsed) || parsed < 0) {
+ return null;
+ }
+ return parsed;
+}
+
+function deriveExecutionTopologyProcessModel(executionBundle = null) {
+ const planeBinding = normalizeText(executionBundle?.planeBinding).toLowerCase();
+ const harnessKind = normalizeText(executionBundle?.harnessKind);
+ const requestedSimultaneous = planeBinding === 'dual-plane-parity';
+ const windowsNativeTestStand =
+ (!harnessKind || harnessKind === 'teststand-compare-harness') &&
+ (requestedSimultaneous || planeBinding.startsWith('native-labview-'));
+ const runtimeSurface = windowsNativeTestStand ? 'windows-native-teststand' : null;
+ const processModelClass = !runtimeSurface
+ ? null
+ : requestedSimultaneous
+ ? 'parallel-process-model'
+ : 'sequential-process-model';
+
+ return {
+ runtimeSurface,
+ processModelClass,
+ windowsOnly: runtimeSurface === 'windows-native-teststand',
+ requestedSimultaneous
+ };
+}
+
+function deriveExecutionTopologyStatus({
+ activeLogicalLaneCount = null,
+ seededLogicalLaneCount = null,
+ providerDispatch = null,
+ executionBundle = null
+} = {}) {
+ const bundleStatus = normalizeText(executionBundle?.status);
+ if (bundleStatus) {
+ return `bundle-${bundleStatus}`;
+ }
+
+ const completionStatus = normalizeText(providerDispatch?.completionStatus);
+ if (completionStatus) {
+ return `provider-${completionStatus}`;
+ }
+
+ const dispatchStatus = normalizeText(providerDispatch?.dispatchStatus);
+ if (dispatchStatus) {
+ return `provider-${dispatchStatus}`;
+ }
+
+ if ((activeLogicalLaneCount ?? 0) > 0 || (seededLogicalLaneCount ?? 0) > 0) {
+ return 'logical-lanes-tracked';
+ }
+
+ return 'none';
+}
+
+export function buildExecutionTopologyRuntimeState({
+ logicalLaneActivation = null,
+ providerDispatch = null,
+ providerSelection = null,
+ workerSlotId = null,
+ concurrentLaneStatus = null
+} = {}) {
+ const logicalLaneState = normalizeOptionalObject(logicalLaneActivation);
+ const executionBundle = normalizeOptionalObject(concurrentLaneStatus?.executionBundle);
+ const effectiveProviderDispatch =
+ normalizeOptionalObject(providerDispatch) ??
+ buildWorkerProviderDispatchReceipt(providerSelection, { workerSlotId });
+
+ const activeLogicalLaneCount = coerceNonNegativeInteger(logicalLaneState?.activeLaneCount);
+ const seededLogicalLaneCount = coerceNonNegativeInteger(logicalLaneState?.seededLaneCount);
+
+ if (!executionBundle && !effectiveProviderDispatch && activeLogicalLaneCount == null && seededLogicalLaneCount == null) {
+ return null;
+ }
+
+ const processModel = deriveExecutionTopologyProcessModel(executionBundle);
+
+ return {
+ status: deriveExecutionTopologyStatus({
+ activeLogicalLaneCount,
+ seededLogicalLaneCount,
+ providerDispatch: effectiveProviderDispatch,
+ executionBundle
+ }),
+ executionPlane:
+ normalizeText(effectiveProviderDispatch?.executionPlane) ||
+ normalizeText(executionBundle?.planeBinding) ||
+ null,
+ providerId: normalizeText(effectiveProviderDispatch?.providerId) || null,
+ workerSlotId: normalizeText(effectiveProviderDispatch?.workerSlotId) || null,
+ cellId: normalizeText(executionBundle?.cellId) || null,
+ laneId: normalizeText(executionBundle?.laneId) || null,
+ cellClass: normalizeText(executionBundle?.cellClass) || null,
+ suiteClass: normalizeText(executionBundle?.suiteClass) || null,
+ planeBinding: normalizeText(executionBundle?.planeBinding) || null,
+ harnessKind: normalizeText(executionBundle?.harnessKind) || null,
+ harnessInstanceId: normalizeText(executionBundle?.harnessInstanceId) || null,
+ executionCellLeaseId: normalizeText(executionBundle?.executionCellLeaseId) || null,
+ dockerLaneLeaseId: normalizeText(executionBundle?.dockerLaneLeaseId) || null,
+ premiumSaganMode: executionBundle?.premiumSaganMode === true,
+ reciprocalLinkReady: executionBundle?.reciprocalLinkReady === true,
+ operatorAuthorizationRef: normalizeText(executionBundle?.operatorAuthorizationRef) || null,
+ activeLogicalLaneCount,
+ seededLogicalLaneCount,
+ runtimeSurface: processModel.runtimeSurface,
+ processModelClass: processModel.processModelClass,
+ windowsOnly: processModel.windowsOnly,
+ requestedSimultaneous: processModel.requestedSimultaneous
+ };
+}
+
function commandUsesLocalCollabOrchestrator(command = []) {
return Array.isArray(command)
? command.some((entry) => normalizeText(entry).replace(/\\/g, '/').includes('tools/local-collab/orchestrator/run-phase.mjs'))
@@ -2643,6 +2757,7 @@ function buildConcurrentLaneStatusRuntimeState({ taskPacket, executionReceipt })
const hostedRun = normalizeOptionalObject(concurrentLaneStatus.hostedRun);
const pullRequest = normalizeOptionalObject(concurrentLaneStatus.pullRequest);
const mergeQueue = normalizeOptionalObject(pullRequest?.mergeQueue);
+ const executionBundle = normalizeOptionalObject(concurrentLaneStatus.executionBundle);
return {
receiptPath: normalizeText(concurrentLaneStatus.receiptPath) || null,
@@ -2671,6 +2786,28 @@ function buildConcurrentLaneStatusRuntimeState({ taskPacket, executionReceipt })
: null
}
: null,
+ executionBundle: executionBundle
+ ? {
+ status: normalizeText(executionBundle.status) || null,
+ cellId: normalizeText(executionBundle.cellId) || null,
+ laneId: normalizeText(executionBundle.laneId) || null,
+ cellClass: normalizeText(executionBundle.cellClass) || null,
+ suiteClass: normalizeText(executionBundle.suiteClass) || null,
+ executionCellLeaseId: normalizeText(executionBundle.executionCellLeaseId) || null,
+ dockerLaneLeaseId: normalizeText(executionBundle.dockerLaneLeaseId) || null,
+ harnessKind: normalizeText(executionBundle.harnessKind) || null,
+ harnessInstanceId: normalizeText(executionBundle.harnessInstanceId) || null,
+ planeBinding: normalizeText(executionBundle.planeBinding) || null,
+ premiumSaganMode: executionBundle.premiumSaganMode === true,
+ reciprocalLinkReady: executionBundle.reciprocalLinkReady === true,
+ effectiveBillableRateUsdPerHour: Number.isFinite(executionBundle.effectiveBillableRateUsdPerHour)
+ ? executionBundle.effectiveBillableRateUsdPerHour
+ : null,
+ operatorAuthorizationRef: normalizeText(executionBundle.operatorAuthorizationRef) || null,
+ isolatedLaneGroupId: normalizeText(executionBundle.isolatedLaneGroupId) || null,
+ fingerprintSha256: normalizeText(executionBundle.fingerprintSha256) || null
+ }
+ : null,
summary: summary
? {
laneCount: coercePositiveInteger(summary.laneCount) ?? 0,
@@ -3369,6 +3506,13 @@ export function buildDeliveryAgentRuntimeRecord({
schedulerDecision,
taskPacket
});
+ const executionTopology = buildExecutionTopologyRuntimeState({
+ logicalLaneActivation,
+ providerDispatch,
+ providerSelection: workerProviderSelection,
+ workerSlotId: normalizeText(providerDispatch?.workerSlotId) || normalizeText(workerProviderSelection?.selectedSlotId) || null,
+ concurrentLaneStatus
+ });
const activeLane = {
schema: DELIVERY_AGENT_LANE_STATE_SCHEMA,
generatedAt: toIso(now),
@@ -3400,6 +3544,7 @@ export function buildDeliveryAgentRuntimeRecord({
readyValidationClearance,
concurrentLaneApply,
concurrentLaneStatus,
+ executionTopology,
liveAgentModelSelection,
workerProviderSelection,
providerDispatch
diff --git a/tools/priority/docker-lane-handshake.mjs b/tools/priority/docker-lane-handshake.mjs
new file mode 100644
index 000000000..e1c95804f
--- /dev/null
+++ b/tools/priority/docker-lane-handshake.mjs
@@ -0,0 +1,802 @@
+#!/usr/bin/env node
+
+import { spawnSync } from 'node:child_process';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import process from 'node:process';
+import { fileURLToPath } from 'node:url';
+
+import { defaultOwner } from './agent-writer-lease.mjs';
+import { resolveGitAdminPaths } from './lib/git-admin-paths.mjs';
+
+const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
+const REPO_ROOT = path.resolve(MODULE_DIR, '..', '..');
+
+export const DOCKER_LANE_HANDSHAKE_SCHEMA = 'priority/docker-lane-handshake@v1';
+export const DOCKER_LANE_HANDSHAKE_REPORT_SCHEMA = 'priority/docker-lane-handshake-report@v1';
+export const DEFAULT_OUTPUT_PATH = path.join('tests', 'results', '_agent', 'runtime', 'docker-lane-handshake.json');
+export const DEFAULT_HOST_PLANE_REPORT_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'host-planes',
+ 'labview-2026-host-plane-report.json'
+);
+export const DEFAULT_OPERATOR_COST_PROFILE_PATH = path.join('tools', 'policy', 'operator-cost-profile.json');
+export const DEFAULT_TTL_SECONDS = 1800;
+export const PREMIUM_RATE_MULTIPLIER = 1.5;
+export const ORDINARY_RATE_MULTIPLIER = 1.0;
+export const DOCKER_LANE_CAPABILITY = 'docker-lane';
+export const NATIVE_LV32_CAPABILITY = 'native-labview-2026-32';
+
+export const STATUS = Object.freeze({
+ requested: 'requested',
+ granted: 'granted',
+ committed: 'committed',
+ released: 'released',
+ renewed: 'renewed',
+ active: 'active',
+ busy: 'busy',
+ denied: 'denied',
+ notFound: 'not-found',
+ mismatch: 'mismatch',
+ invalidState: 'invalid-state',
+ stale: 'stale'
+});
+
+function normalizeText(value) {
+ if (value == null) {
+ return '';
+ }
+ return String(value).trim();
+}
+
+function toOptionalText(value) {
+ const normalized = normalizeText(value);
+ return normalized || null;
+}
+
+function normalizeAgentClass(value) {
+ const normalized = normalizeText(value).toLowerCase();
+ if (['sagan', 'subagent', 'other'].includes(normalized)) {
+ return normalized;
+ }
+ return 'subagent';
+}
+
+function nowIso(now = new Date()) {
+ return now.toISOString();
+}
+
+function uniqueId(prefix = 'id', now = Date.now()) {
+ return `${prefix}-${now}-${Math.random().toString(16).slice(2, 10)}`;
+}
+
+function sanitizeLaneId(laneId) {
+ return normalizeText(laneId).replace(/[^a-zA-Z0-9._-]+/g, '__');
+}
+
+function resolveDefaultHandshakeRoot(options = {}) {
+ try {
+ return path.join(
+ resolveGitAdminPaths({
+ cwd: options.repoRoot || REPO_ROOT,
+ env: options.env || process.env,
+ spawnSyncFn: options.spawnSyncFn || spawnSync
+ }).gitCommonDir,
+ 'docker-lane-handshakes'
+ );
+ } catch {
+ return path.join(options.repoRoot || REPO_ROOT, '.git', 'docker-lane-handshakes');
+ }
+}
+
+export function defaultHandshakeRoot(options = {}) {
+ return options.handshakeRoot || process.env.DOCKER_LANE_HANDSHAKE_ROOT || resolveDefaultHandshakeRoot(options);
+}
+
+export function handshakePathForLane(laneId, handshakeRoot = defaultHandshakeRoot()) {
+ return path.join(handshakeRoot, `${sanitizeLaneId(laneId)}.json`);
+}
+
+async function ensureParentDir(filePath) {
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
+}
+
+async function readJsonIfPresent(filePath) {
+ try {
+ return JSON.parse(await fs.readFile(filePath, 'utf8'));
+ } catch (error) {
+ if (error?.code === 'ENOENT') {
+ return null;
+ }
+ throw error;
+ }
+}
+
+async function writeJsonAtomic(filePath, payload) {
+ await ensureParentDir(filePath);
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
+ const body = `${JSON.stringify(payload, null, 2)}\n`;
+ await fs.writeFile(tempPath, body, 'utf8');
+ try {
+ await fs.rename(tempPath, filePath);
+ } finally {
+ await fs.rm(tempPath, { force: true });
+ }
+}
+
+function normalizeCapabilities(capabilities = []) {
+ const values = [];
+ for (const entry of capabilities) {
+ const normalized = normalizeText(entry);
+ if (normalized) {
+ values.push(normalized);
+ }
+ }
+ return [...new Set(values)];
+}
+
+function isPremiumDualLaneRequest(capabilities = []) {
+ const set = new Set(normalizeCapabilities(capabilities));
+ return set.has(DOCKER_LANE_CAPABILITY) && set.has(NATIVE_LV32_CAPABILITY);
+}
+
+function resolveHeartbeatTimestamp(handshake) {
+ return (
+ handshake?.heartbeatAt ||
+ handshake?.commit?.committedAt ||
+ handshake?.grant?.grantedAt ||
+ handshake?.request?.requestedAt ||
+ null
+ );
+}
+
+function handshakeAgeSeconds(handshake, nowMs = Date.now()) {
+ const timestamp = resolveHeartbeatTimestamp(handshake);
+ if (!timestamp) {
+ return Number.POSITIVE_INFINITY;
+ }
+ const parsed = Date.parse(timestamp);
+ if (!Number.isFinite(parsed)) {
+ return Number.POSITIVE_INFINITY;
+ }
+ return Math.max(0, (nowMs - parsed) / 1000);
+}
+
+function resolveTtlSeconds(handshake) {
+ return Number.isInteger(handshake?.grant?.ttlSeconds) ? handshake.grant.ttlSeconds : DEFAULT_TTL_SECONDS;
+}
+
+export function isHandshakeStale(handshake, nowMs = Date.now()) {
+ if (!handshake || handshake.state === 'released') {
+ return false;
+ }
+ return handshakeAgeSeconds(handshake, nowMs) > resolveTtlSeconds(handshake);
+}
+
+function buildHostContext(hostPlaneReport) {
+ const fingerprint = hostPlaneReport?.host?.osFingerprint;
+ if (!fingerprint || typeof fingerprint !== 'object') {
+ return {
+ context: null,
+ observations: ['host-os-fingerprint-missing']
+ };
+ }
+
+ return {
+ context: {
+ isolatedLaneGroupId: toOptionalText(fingerprint.isolatedLaneGroupId),
+ fingerprintSha256: toOptionalText(fingerprint.fingerprintSha256),
+ platform: toOptionalText(fingerprint.platform),
+ computerName: toOptionalText(hostPlaneReport?.host?.computerName),
+ canonical: {
+ version: toOptionalText(fingerprint?.canonical?.version),
+ buildNumber: toOptionalText(fingerprint?.canonical?.buildNumber),
+ ubr: Number.isInteger(fingerprint?.canonical?.ubr) ? fingerprint.canonical.ubr : null
+ }
+ },
+ observations: []
+ };
+}
+
+function resolveOperatorProfile(profile, explicitOperatorId) {
+ const operators = Array.isArray(profile?.operators) ? profile.operators : [];
+ const desiredId = toOptionalText(explicitOperatorId) || toOptionalText(profile?.defaultOperatorId);
+ const activeOperators = operators.filter((entry) => entry?.active !== false);
+ const resolved =
+ activeOperators.find((entry) => normalizeText(entry?.id) === normalizeText(desiredId)) ||
+ activeOperators[0] ||
+ null;
+
+ return {
+ operatorId: toOptionalText(resolved?.id) || desiredId,
+ currency: toOptionalText(profile?.currency) || 'USD',
+ laborRateUsdPerHour: Number.isFinite(resolved?.laborRateUsdPerHour)
+ ? Number(resolved.laborRateUsdPerHour)
+ : null
+ };
+}
+
+function buildGrantDecision(handshake, operatorProfile) {
+ const requestedCapabilities = normalizeCapabilities(handshake?.request?.capabilities);
+ const premiumDualLaneRequested = handshake?.request?.premiumDualLaneRequested === true;
+ const reasons = [];
+
+ if (!requestedCapabilities.includes(DOCKER_LANE_CAPABILITY)) {
+ reasons.push('docker-lane-capability-required');
+ }
+ if (premiumDualLaneRequested && handshake?.request?.agentClass !== 'sagan') {
+ reasons.push('premium-sagan-only');
+ }
+ if (premiumDualLaneRequested && !toOptionalText(handshake?.request?.operatorAuthorizationRef)) {
+ reasons.push('operator-authorization-required');
+ }
+ if (!Number.isFinite(operatorProfile?.laborRateUsdPerHour)) {
+ reasons.push('operator-cost-rate-unavailable');
+ }
+
+ const billableRateMultiplier = premiumDualLaneRequested ? PREMIUM_RATE_MULTIPLIER : ORDINARY_RATE_MULTIPLIER;
+ const billableRateUsdPerHour = Number.isFinite(operatorProfile?.laborRateUsdPerHour)
+ ? Number((operatorProfile.laborRateUsdPerHour * billableRateMultiplier).toFixed(3))
+ : null;
+
+ return {
+ allowed: reasons.length === 0,
+ reasons,
+ premiumDualLaneRequested,
+ premiumSaganMode: premiumDualLaneRequested,
+ policyDecision: premiumDualLaneRequested ? 'sagan-premium-dual-lane' : 'ordinary-docker-lane',
+ grantedCapabilities: requestedCapabilities,
+ billableRateMultiplier,
+ billableRateUsdPerHour
+ };
+}
+
+function buildBaseReport(action, laneId, handshakePath, generatedAt, handshake, extras = {}) {
+ const stale = isHandshakeStale(handshake, Date.parse(generatedAt));
+ return {
+ schema: DOCKER_LANE_HANDSHAKE_REPORT_SCHEMA,
+ generatedAt,
+ action,
+ laneId,
+ handshakePath,
+ handshake,
+ summary: {
+ handshakeState: handshake?.state ?? null,
+ leaseId: toOptionalText(handshake?.grant?.leaseId),
+ holder: toOptionalText(handshake?.request?.agentId),
+ premiumSaganMode:
+ handshake?.grant?.premiumSaganMode === true || handshake?.request?.premiumDualLaneRequested === true,
+ billableRateMultiplier: Number.isFinite(handshake?.grant?.billableRateMultiplier)
+ ? handshake.grant.billableRateMultiplier
+ : null,
+ billableRateUsdPerHour: Number.isFinite(handshake?.grant?.billableRateUsdPerHour)
+ ? handshake.grant.billableRateUsdPerHour
+ : null,
+ operatorAuthorizationRef: toOptionalText(handshake?.request?.operatorAuthorizationRef),
+ isolatedLaneGroupId: toOptionalText(handshake?.host?.isolatedLaneGroupId),
+ fingerprintSha256: toOptionalText(handshake?.host?.fingerprintSha256),
+ linkedExecutionCellId: toOptionalText(handshake?.commit?.executionCellId),
+ linkedExecutionCellLeaseId: toOptionalText(handshake?.commit?.executionCellLeaseId),
+ isStale: stale,
+ ageSeconds: Number.isFinite(handshakeAgeSeconds(handshake, Date.parse(generatedAt)))
+ ? Number(handshakeAgeSeconds(handshake, Date.parse(generatedAt)).toFixed(3))
+ : null,
+ ttlSeconds: handshake ? resolveTtlSeconds(handshake) : null,
+ denialReasons: [],
+ observations: []
+ },
+ ...extras
+ };
+}
+
+function isWindowsNativeExecutionCellLink(linkedExecutionCell) {
+ const harnessKind = normalizeText(linkedExecutionCell?.harnessKind);
+ const planeBinding = normalizeText(linkedExecutionCell?.planeBinding).toLowerCase();
+ if (!harnessKind || harnessKind !== 'teststand-compare-harness') {
+ return false;
+ }
+ if (!planeBinding) {
+ return true;
+ }
+ return planeBinding === 'dual-plane-parity' || planeBinding.startsWith('native-labview-');
+}
+
+function resolveExecutionCellLinkContext(report) {
+ if (!report || typeof report !== 'object') {
+ return null;
+ }
+ const lease = report.lease;
+ if (!lease || typeof lease !== 'object') {
+ return null;
+ }
+ return {
+ cellId: toOptionalText(report?.cellId) || toOptionalText(lease?.cellId),
+ leaseId: toOptionalText(report?.summary?.leaseId) || toOptionalText(lease?.grant?.leaseId),
+ holder: toOptionalText(report?.summary?.holder) || toOptionalText(lease?.request?.agentId),
+ isolatedLaneGroupId:
+ toOptionalText(report?.summary?.isolatedLaneGroupId) || toOptionalText(lease?.host?.isolatedLaneGroupId),
+ fingerprintSha256:
+ toOptionalText(report?.summary?.fingerprintSha256) || toOptionalText(lease?.host?.fingerprintSha256),
+ planeBinding: toOptionalText(report?.summary?.planeBinding) || toOptionalText(lease?.request?.planeBinding),
+ harnessKind: toOptionalText(report?.summary?.harnessKind) || toOptionalText(lease?.request?.harnessKind)
+ };
+}
+
+function validateExecutionCellLink(handshake, linkedExecutionCell) {
+ if (!linkedExecutionCell) {
+ return ['execution-cell-report-invalid'];
+ }
+
+ const reasons = [];
+ if (!linkedExecutionCell.cellId) {
+ reasons.push('execution-cell-id-missing');
+ }
+ if (!linkedExecutionCell.leaseId) {
+ reasons.push('execution-cell-lease-id-missing');
+ }
+ if (!linkedExecutionCell.holder) {
+ reasons.push('execution-cell-holder-missing');
+ }
+ if (!linkedExecutionCell.isolatedLaneGroupId || !linkedExecutionCell.fingerprintSha256) {
+ reasons.push('execution-cell-host-fingerprint-missing');
+ }
+ if (!isWindowsNativeExecutionCellLink(linkedExecutionCell)) {
+ reasons.push('execution-cell-not-windows-native-teststand');
+ }
+
+ const handshakeHolder = toOptionalText(handshake?.request?.agentId);
+ if (handshakeHolder && linkedExecutionCell.holder && linkedExecutionCell.holder !== handshakeHolder) {
+ reasons.push('execution-cell-owner-mismatch');
+ }
+
+ const handshakeIsolatedLaneGroupId = toOptionalText(handshake?.host?.isolatedLaneGroupId);
+ const handshakeFingerprintSha256 = toOptionalText(handshake?.host?.fingerprintSha256);
+ if (
+ handshakeIsolatedLaneGroupId &&
+ linkedExecutionCell.isolatedLaneGroupId &&
+ linkedExecutionCell.isolatedLaneGroupId !== handshakeIsolatedLaneGroupId
+ ) {
+ reasons.push('execution-cell-isolated-lane-group-mismatch');
+ }
+ if (
+ handshakeFingerprintSha256 &&
+ linkedExecutionCell.fingerprintSha256 &&
+ linkedExecutionCell.fingerprintSha256 !== handshakeFingerprintSha256
+ ) {
+ reasons.push('execution-cell-host-fingerprint-mismatch');
+ }
+
+ return reasons;
+}
+
+function buildRequestRecord({
+ laneId,
+ agentId,
+ agentClass,
+ capabilities,
+ operatorId,
+ operatorAuthorizationRef,
+ hostContext,
+ now,
+ requestId
+}) {
+ const requestedCapabilities = normalizeCapabilities(capabilities);
+ const generatedAt = nowIso(now);
+ return {
+ schema: DOCKER_LANE_HANDSHAKE_SCHEMA,
+ generatedAt,
+ laneId,
+ resourceKind: DOCKER_LANE_CAPABILITY,
+ state: 'requested',
+ sequence: 1,
+ heartbeatAt: generatedAt,
+ host: hostContext,
+ request: {
+ requestId,
+ requestedAt: generatedAt,
+ agentId,
+ agentClass,
+ capabilities: requestedCapabilities,
+ premiumDualLaneRequested: isPremiumDualLaneRequest(requestedCapabilities),
+ operatorId: toOptionalText(operatorId),
+ operatorAuthorizationRef: toOptionalText(operatorAuthorizationRef)
+ },
+ grant: null,
+ commit: null,
+ release: null
+ };
+}
+
+function cloneForTransition(handshake, now) {
+ return {
+ ...handshake,
+ generatedAt: nowIso(now),
+ sequence: Number.isInteger(handshake?.sequence) ? handshake.sequence + 1 : 1
+ };
+}
+
+function printUsage() {
+ console.log('Usage: node tools/priority/docker-lane-handshake.mjs --action --lane-id [options]');
+ console.log('');
+ console.log('Options:');
+ console.log(` --output Report output path (default: ${DEFAULT_OUTPUT_PATH}).`);
+ console.log(' --lane-id Logical isolated Docker lane id.');
+ console.log(' --action Handshake action (request|grant|commit|heartbeat|release|inspect).');
+ console.log(` --agent-id Request owner (default: ${defaultOwner()}).`);
+ console.log(' --agent-class Agent class (default: subagent).');
+ console.log(` --host-plane-report Host-plane report path (default: ${DEFAULT_HOST_PLANE_REPORT_PATH}).`);
+ console.log(` --operator-cost-profile Operator cost profile path (default: ${DEFAULT_OPERATOR_COST_PROFILE_PATH}).`);
+ console.log(' --operator-id Operator id for billable-rate resolution.');
+ console.log(' --operator-authorization-ref [ Authorization receipt/reference for premium Sagan mode.');
+ console.log(` --ttl-seconds Grant TTL in seconds (default: ${DEFAULT_TTL_SECONDS}).`);
+ console.log(' --grantor Grantor id recorded on grant (default: sagan-governor).');
+ console.log(' --lease-id Lease id matcher for commit/heartbeat/release.');
+ console.log(' --execution-cell-report Execution-cell report used to bind a committed Docker lane to a cell.');
+ console.log(' --capability Requested capability (repeatable).');
+ console.log(` --premium-dual-lane Shortcut for ${DOCKER_LANE_CAPABILITY} + ${NATIVE_LV32_CAPABILITY}.`);
+ console.log(' --final-status Release final status (default: succeeded).');
+ console.log(' --artifact-path Artifact path to attach on release (repeatable).');
+ console.log(' --handshake-root Override handshake state directory.');
+ console.log(' --help Show this help text and exit.');
+}
+
+export function parseArgs(argv = process.argv) {
+ const args = argv.slice(2);
+ const options = {
+ action: '',
+ laneId: '',
+ outputPath: DEFAULT_OUTPUT_PATH,
+ agentId: defaultOwner(),
+ agentClass: 'subagent',
+ hostPlaneReportPath: DEFAULT_HOST_PLANE_REPORT_PATH,
+ operatorCostProfilePath: DEFAULT_OPERATOR_COST_PROFILE_PATH,
+ operatorId: '',
+ operatorAuthorizationRef: '',
+ ttlSeconds: DEFAULT_TTL_SECONDS,
+ grantor: 'sagan-governor',
+ leaseId: '',
+ capabilities: [],
+ premiumDualLane: false,
+ finalStatus: 'succeeded',
+ artifactPaths: [],
+ handshakeRoot: '',
+ executionCellReportPath: '',
+ help: false
+ };
+
+ for (let index = 0; index < args.length; index += 1) {
+ const token = args[index];
+ const next = args[index + 1];
+
+ if (token === '--help' || token === '-h') {
+ options.help = true;
+ continue;
+ }
+
+ if (token === '--premium-dual-lane') {
+ options.premiumDualLane = true;
+ continue;
+ }
+
+ if (
+ token === '--action' ||
+ token === '--lane-id' ||
+ token === '--output' ||
+ token === '--agent-id' ||
+ token === '--agent-class' ||
+ token === '--host-plane-report' ||
+ token === '--operator-cost-profile' ||
+ token === '--operator-id' ||
+ token === '--operator-authorization-ref' ||
+ token === '--ttl-seconds' ||
+ token === '--grantor' ||
+ token === '--lease-id' ||
+ token === '--execution-cell-report' ||
+ token === '--final-status' ||
+ token === '--handshake-root'
+ ) {
+ if (!next || next.startsWith('-')) {
+ throw new Error(`Missing value for ${token}.`);
+ }
+ index += 1;
+ if (token === '--action') options.action = next;
+ if (token === '--lane-id') options.laneId = next;
+ if (token === '--output') options.outputPath = next;
+ if (token === '--agent-id') options.agentId = next;
+ if (token === '--agent-class') options.agentClass = normalizeAgentClass(next);
+ if (token === '--host-plane-report') options.hostPlaneReportPath = next;
+ if (token === '--operator-cost-profile') options.operatorCostProfilePath = next;
+ if (token === '--operator-id') options.operatorId = next;
+ if (token === '--operator-authorization-ref') options.operatorAuthorizationRef = next;
+ if (token === '--ttl-seconds') {
+ const ttl = Number.parseInt(next, 10);
+ if (!Number.isInteger(ttl) || ttl <= 0) {
+ throw new Error(`Invalid --ttl-seconds value '${next}'.`);
+ }
+ options.ttlSeconds = ttl;
+ }
+ if (token === '--grantor') options.grantor = next;
+ if (token === '--lease-id') options.leaseId = next;
+ if (token === '--execution-cell-report') options.executionCellReportPath = next;
+ if (token === '--final-status') options.finalStatus = next;
+ if (token === '--handshake-root') options.handshakeRoot = next;
+ continue;
+ }
+
+ if (token === '--capability' || token === '--artifact-path') {
+ if (!next || next.startsWith('-')) {
+ throw new Error(`Missing value for ${token}.`);
+ }
+ index += 1;
+ if (token === '--capability') options.capabilities.push(next);
+ if (token === '--artifact-path') options.artifactPaths.push(next);
+ continue;
+ }
+
+ throw new Error(`Unknown option: ${token}`);
+ }
+
+ if (options.premiumDualLane) {
+ options.capabilities.push(DOCKER_LANE_CAPABILITY, NATIVE_LV32_CAPABILITY);
+ }
+ options.capabilities = normalizeCapabilities(options.capabilities);
+
+ return options;
+}
+
+async function writeReport(outputPath, report, repoRoot = process.cwd()) {
+ const resolved = path.resolve(repoRoot, outputPath);
+ await ensureParentDir(resolved);
+ await fs.writeFile(resolved, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
+ return resolved;
+}
+
+function withObservations(report, observations = []) {
+ return {
+ ...report,
+ summary: {
+ ...report.summary,
+ observations: [...report.summary.observations, ...observations.filter(Boolean)]
+ }
+ };
+}
+
+function withDenialReasons(report, reasons = []) {
+ return {
+ ...report,
+ summary: {
+ ...report.summary,
+ denialReasons: [...report.summary.denialReasons, ...reasons.filter(Boolean)]
+ }
+ };
+}
+
+export async function runDockerLaneHandshake(options = {}) {
+ const action = normalizeText(options.action).toLowerCase();
+ const laneId = normalizeText(options.laneId);
+ const repoRoot = options.repoRoot || REPO_ROOT;
+ const agentId = toOptionalText(options.agentId) || defaultOwner();
+ const agentClass = normalizeAgentClass(options.agentClass);
+ const handshakeRoot = defaultHandshakeRoot({ repoRoot, handshakeRoot: options.handshakeRoot });
+ const handshakePath = handshakePathForLane(laneId, handshakeRoot);
+ const generatedAt = nowIso(options.now || new Date());
+ const current = await readJsonIfPresent(handshakePath);
+ const hostPlaneReport = options.hostPlaneReport ?? (await readJsonIfPresent(path.resolve(repoRoot, options.hostPlaneReportPath || DEFAULT_HOST_PLANE_REPORT_PATH)));
+ const operatorCostProfile =
+ options.operatorCostProfile ?? (await readJsonIfPresent(path.resolve(repoRoot, options.operatorCostProfilePath || DEFAULT_OPERATOR_COST_PROFILE_PATH)));
+ const { context: hostContext, observations: hostObservations } = buildHostContext(hostPlaneReport);
+ const operatorProfile = resolveOperatorProfile(operatorCostProfile, options.operatorId);
+ const base = buildBaseReport(action, laneId, handshakePath, generatedAt, current, {
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour,
+ premiumSaganRateMultiplier: PREMIUM_RATE_MULTIPLIER
+ }
+ });
+ const reportWithHost = withObservations(base, hostObservations);
+
+ if (!laneId) {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.invalidState }, ['lane-id-required']);
+ }
+
+ if (!['request', 'grant', 'commit', 'heartbeat', 'release', 'inspect'].includes(action)) {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.invalidState }, ['action-invalid']);
+ }
+
+ if (action === 'inspect') {
+ if (!current) {
+ return { ...reportWithHost, status: STATUS.notFound, handshake: null };
+ }
+ return { ...reportWithHost, status: isHandshakeStale(current, Date.parse(generatedAt)) ? STATUS.stale : STATUS.active };
+ }
+
+ if (action === 'request') {
+ if (current && current.state !== 'released') {
+ const status = isHandshakeStale(current, Date.parse(generatedAt)) ? STATUS.stale : STATUS.busy;
+ return withDenialReasons({ ...reportWithHost, status }, [status === STATUS.stale ? 'stale-handshake-present' : 'lane-already-held']);
+ }
+ if (normalizeCapabilities(options.capabilities).length === 0) {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.denied }, ['capabilities-required']);
+ }
+
+ const next = buildRequestRecord({
+ laneId,
+ agentId,
+ agentClass,
+ capabilities: options.capabilities,
+ operatorId: options.operatorId || operatorProfile.operatorId,
+ operatorAuthorizationRef: options.operatorAuthorizationRef,
+ hostContext,
+ now: options.now || new Date(),
+ requestId: options.requestId || uniqueId('request', Date.parse(generatedAt))
+ });
+ await writeJsonAtomic(handshakePath, next);
+ return buildResultReport(action, laneId, handshakePath, generatedAt, next, operatorProfile, hostObservations, STATUS.requested);
+ }
+
+ if (!current) {
+ return { ...reportWithHost, status: STATUS.notFound, handshake: null };
+ }
+
+ const sameAgent = normalizeText(current?.request?.agentId) === agentId;
+ if (!sameAgent) {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.mismatch }, ['request-owner-mismatch']);
+ }
+
+ if (action === 'grant') {
+ if (current.state !== 'requested') {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.invalidState }, ['grant-requires-requested-state']);
+ }
+ const decision = buildGrantDecision(current, operatorProfile);
+ if (!decision.allowed) {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.denied }, decision.reasons);
+ }
+
+ const next = cloneForTransition(current, options.now || new Date());
+ next.state = 'granted';
+ next.heartbeatAt = generatedAt;
+ next.host = hostContext || current.host || null;
+ next.grant = {
+ grantedAt: generatedAt,
+ grantor: toOptionalText(options.grantor) || 'sagan-governor',
+ leaseId: options.leaseId || uniqueId('lease', Date.parse(generatedAt)),
+ ttlSeconds: Number.isInteger(options.ttlSeconds) ? options.ttlSeconds : DEFAULT_TTL_SECONDS,
+ grantedCapabilities: decision.grantedCapabilities,
+ billableRateMultiplier: decision.billableRateMultiplier,
+ billableRateUsdPerHour: decision.billableRateUsdPerHour,
+ premiumSaganMode: decision.premiumSaganMode,
+ policyDecision: decision.policyDecision,
+ operatorAuthorizationRef: toOptionalText(current.request.operatorAuthorizationRef)
+ };
+ await writeJsonAtomic(handshakePath, next);
+ return buildResultReport(action, laneId, handshakePath, generatedAt, next, operatorProfile, hostObservations, STATUS.granted);
+ }
+
+ const leaseId = toOptionalText(options.leaseId);
+ const leaseIdMatches = !leaseId || normalizeText(current?.grant?.leaseId) === leaseId;
+ if (!leaseIdMatches) {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.mismatch }, ['lease-id-mismatch']);
+ }
+
+ if (action === 'commit') {
+ if (current.state !== 'granted') {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.invalidState }, ['commit-requires-granted-state']);
+ }
+
+ let linkedExecutionCell = null;
+ if (toOptionalText(options.executionCellReportPath)) {
+ linkedExecutionCell = resolveExecutionCellLinkContext(
+ await readJsonIfPresent(path.resolve(repoRoot, options.executionCellReportPath))
+ );
+ const linkReasons = validateExecutionCellLink(current, linkedExecutionCell);
+ if (linkReasons.length > 0) {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.mismatch }, linkReasons);
+ }
+ }
+
+ const next = cloneForTransition(current, options.now || new Date());
+ next.state = 'active';
+ next.heartbeatAt = generatedAt;
+ next.commit = {
+ committedAt: generatedAt,
+ executionCellId: linkedExecutionCell?.cellId || toOptionalText(current?.commit?.executionCellId),
+ executionCellLeaseId: linkedExecutionCell?.leaseId || toOptionalText(current?.commit?.executionCellLeaseId)
+ };
+ await writeJsonAtomic(handshakePath, next);
+ const report = buildResultReport(
+ action,
+ laneId,
+ handshakePath,
+ generatedAt,
+ next,
+ operatorProfile,
+ hostObservations,
+ STATUS.committed
+ );
+ if (linkedExecutionCell?.cellId) {
+ report.summary.observations.push('linked-execution-cell-commit');
+ }
+ return report;
+ }
+
+ if (action === 'heartbeat') {
+ if (current.state !== 'active') {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.invalidState }, ['heartbeat-requires-active-state']);
+ }
+ const next = cloneForTransition(current, options.now || new Date());
+ next.heartbeatAt = generatedAt;
+ await writeJsonAtomic(handshakePath, next);
+ return buildResultReport(action, laneId, handshakePath, generatedAt, next, operatorProfile, hostObservations, STATUS.renewed);
+ }
+
+ if (action === 'release') {
+ if (!['requested', 'granted', 'active'].includes(current.state)) {
+ return withDenialReasons({ ...reportWithHost, status: STATUS.invalidState }, ['release-requires-live-state']);
+ }
+ const next = cloneForTransition(current, options.now || new Date());
+ next.state = 'released';
+ next.heartbeatAt = generatedAt;
+ next.release = {
+ releasedAt: generatedAt,
+ finalStatus: toOptionalText(options.finalStatus) || 'succeeded',
+ artifactPaths: normalizeCapabilities(options.artifactPaths)
+ };
+ await writeJsonAtomic(handshakePath, next);
+ return buildResultReport(action, laneId, handshakePath, generatedAt, next, operatorProfile, hostObservations, STATUS.released);
+ }
+
+ return withDenialReasons({ ...reportWithHost, status: STATUS.invalidState }, ['action-unhandled']);
+}
+
+function exitCodeForStatus(status) {
+ if ([STATUS.requested, STATUS.granted, STATUS.committed, STATUS.released, STATUS.renewed, STATUS.active].includes(status)) {
+ return 0;
+ }
+ if (status === STATUS.notFound) {
+ return 0;
+ }
+ return 1;
+}
+
+function buildResultReport(action, laneId, handshakePath, generatedAt, handshake, operatorProfile, hostObservations, status) {
+ const base = buildBaseReport(action, laneId, handshakePath, generatedAt, handshake, {
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour,
+ premiumSaganRateMultiplier: PREMIUM_RATE_MULTIPLIER
+ }
+ });
+ return {
+ ...withObservations(base, hostObservations),
+ status,
+ handshake
+ };
+}
+
+export async function main(argv = process.argv) {
+ const options = parseArgs(argv);
+ if (options.help) {
+ printUsage();
+ return 0;
+ }
+
+ const report = await runDockerLaneHandshake({
+ ...options,
+ repoRoot: process.cwd()
+ });
+ const outputPath = await writeReport(options.outputPath, report, process.cwd());
+ console.log(
+ `[docker-lane-handshake] report: ${outputPath} status=${report.status} lane=${report.laneId} state=${report.summary.handshakeState ?? 'none'}`
+ );
+ return exitCodeForStatus(report.status);
+}
+
+const isEntrypoint = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
+if (isEntrypoint) {
+ const exitCode = await main(process.argv);
+ process.exitCode = exitCode;
+}
diff --git a/tools/priority/execution-cell-bundle.mjs b/tools/priority/execution-cell-bundle.mjs
new file mode 100644
index 000000000..7ae7a3a45
--- /dev/null
+++ b/tools/priority/execution-cell-bundle.mjs
@@ -0,0 +1,701 @@
+#!/usr/bin/env node
+
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import process from 'node:process';
+import { fileURLToPath } from 'node:url';
+
+import {
+ DEFAULT_OUTPUT_PATH as DEFAULT_DOCKER_REPORT_PATH,
+ DOCKER_LANE_CAPABILITY,
+ NATIVE_LV32_CAPABILITY,
+ runDockerLaneHandshake
+} from './docker-lane-handshake.mjs';
+import {
+ DEFAULT_HARNESS_KIND,
+ DEFAULT_OUTPUT_PATH as DEFAULT_EXECUTION_CELL_REPORT_PATH,
+ runExecutionCellLease
+} from './execution-cell-lease.mjs';
+
+const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
+const REPO_ROOT = path.resolve(MODULE_DIR, '..', '..');
+
+export const EXECUTION_CELL_BUNDLE_REPORT_SCHEMA = 'priority/execution-cell-bundle-report@v1';
+export const DEFAULT_OUTPUT_PATH = path.join('tests', 'results', '_agent', 'runtime', 'execution-cell-bundle.json');
+
+export const STATUS = Object.freeze({
+ requested: 'requested',
+ granted: 'granted',
+ committed: 'committed',
+ renewed: 'renewed',
+ released: 'released',
+ active: 'active',
+ busy: 'busy',
+ denied: 'denied',
+ notFound: 'not-found',
+ mismatch: 'mismatch',
+ invalidState: 'invalid-state',
+ stale: 'stale',
+ partial: 'partial'
+});
+
+const SUCCESS_STATUS = new Set([
+ STATUS.requested,
+ STATUS.granted,
+ STATUS.committed,
+ STATUS.renewed,
+ STATUS.released,
+ STATUS.active
+]);
+
+function normalizeText(value) {
+ if (value == null) {
+ return '';
+ }
+ return String(value).trim();
+}
+
+function toOptionalText(value) {
+ const normalized = normalizeText(value);
+ return normalized || null;
+}
+
+function normalizeCapabilities(capabilities = []) {
+ const values = [];
+ for (const entry of capabilities) {
+ const normalized = normalizeText(entry);
+ if (normalized) {
+ values.push(normalized);
+ }
+ }
+ return [...new Set(values)];
+}
+
+function wantsDockerLane(options = {}) {
+ return Boolean(toOptionalText(options.laneId)) || normalizeCapabilities(options.capabilities).includes(DOCKER_LANE_CAPABILITY);
+}
+
+function inferBundleCapabilities(capabilities = [], planeBinding, dockerRequested) {
+ const normalized = new Set(normalizeCapabilities(capabilities));
+ const normalizedPlaneBinding = normalizeText(planeBinding).toLowerCase();
+ if (dockerRequested) {
+ normalized.add(DOCKER_LANE_CAPABILITY);
+ }
+ if (normalizedPlaneBinding === 'native-labview-2026-32' || normalizedPlaneBinding === 'dual-plane-parity') {
+ normalized.add(NATIVE_LV32_CAPABILITY);
+ }
+ return [...normalized];
+}
+
+function isWindowsNativeTestStand(planeBinding, harnessKind) {
+ if (!toOptionalText(harnessKind)) {
+ return null;
+ }
+ if (normalizeText(harnessKind) !== DEFAULT_HARNESS_KIND) {
+ return null;
+ }
+ const normalizedPlaneBinding = normalizeText(planeBinding).toLowerCase();
+ if (!normalizedPlaneBinding) {
+ return true;
+ }
+ return normalizedPlaneBinding === 'dual-plane-parity' || normalizedPlaneBinding.startsWith('native-labview-');
+}
+
+function isSuccessfulStatus(status) {
+ return SUCCESS_STATUS.has(normalizeText(status));
+}
+
+function firstFailureStatus(...reports) {
+ for (const report of reports) {
+ const status = normalizeText(report?.status);
+ if (status && !isSuccessfulStatus(status)) {
+ return status;
+ }
+ }
+ return null;
+}
+
+function summarizeEffectiveRate(reports = []) {
+ const multipliers = reports
+ .map((report) => report?.summary?.billableRateMultiplier)
+ .filter((value) => Number.isFinite(value));
+ const rates = reports
+ .map((report) => report?.summary?.billableRateUsdPerHour)
+ .filter((value) => Number.isFinite(value));
+ return {
+ multiplier: multipliers.length > 0 ? Math.max(...multipliers) : null,
+ usdPerHour: rates.length > 0 ? Math.max(...rates) : null
+ };
+}
+
+function collectSummaryStrings(reports, field) {
+ const values = [];
+ for (const report of reports) {
+ const entries = report?.summary?.[field];
+ if (Array.isArray(entries)) {
+ values.push(...entries.filter(Boolean));
+ }
+ }
+ return [...new Set(values)];
+}
+
+function hasReciprocalBundleLink(executionCell, dockerLane, cellId, laneId) {
+ const executionSummary = executionCell?.summary ?? {};
+ const dockerSummary = dockerLane?.summary ?? {};
+ const executionLeaseId = normalizeText(executionSummary.leaseId);
+ const dockerLeaseId = normalizeText(dockerSummary.leaseId);
+ if (!executionLeaseId || !dockerLeaseId) {
+ return false;
+ }
+
+ return (
+ normalizeText(executionSummary.linkedDockerLaneId) === normalizeText(laneId) &&
+ normalizeText(executionSummary.linkedDockerLaneLeaseId) === dockerLeaseId &&
+ normalizeText(dockerSummary.linkedExecutionCellId) === normalizeText(cellId) &&
+ normalizeText(dockerSummary.linkedExecutionCellLeaseId) === executionLeaseId
+ );
+}
+
+function resolveBundleStatus(action, executionCell, dockerLane, rollbacks) {
+ const failure = firstFailureStatus(executionCell, dockerLane, rollbacks.executionCell, rollbacks.dockerLane);
+ if (failure) {
+ return failure;
+ }
+
+ if (!dockerLane) {
+ return normalizeText(executionCell?.status) || STATUS.notFound;
+ }
+
+ if (action === 'inspect') {
+ const executionStatus = normalizeText(executionCell?.status);
+ const dockerStatus = normalizeText(dockerLane?.status);
+ if (executionStatus === STATUS.stale || dockerStatus === STATUS.stale) {
+ return STATUS.stale;
+ }
+ if (executionStatus === STATUS.active || dockerStatus === STATUS.active) {
+ return STATUS.active;
+ }
+ if (executionStatus === STATUS.granted || dockerStatus === STATUS.granted) {
+ return STATUS.granted;
+ }
+ if (executionStatus === STATUS.requested || dockerStatus === STATUS.requested) {
+ return STATUS.requested;
+ }
+ if (executionStatus === STATUS.released || dockerStatus === STATUS.released) {
+ return STATUS.released;
+ }
+ if (executionStatus === STATUS.notFound && dockerStatus === STATUS.notFound) {
+ return STATUS.notFound;
+ }
+ return STATUS.partial;
+ }
+
+ if (normalizeText(executionCell?.status) === normalizeText(dockerLane?.status)) {
+ return normalizeText(executionCell?.status);
+ }
+
+ if (
+ action === 'release' &&
+ [STATUS.released, STATUS.notFound].includes(normalizeText(executionCell?.status)) &&
+ [STATUS.released, STATUS.notFound].includes(normalizeText(dockerLane?.status))
+ ) {
+ return STATUS.released;
+ }
+
+ return STATUS.partial;
+}
+
+async function writeReport(outputPath, report) {
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
+ await fs.writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
+}
+
+async function maybeReleaseExecutionCell(options, now, outputPath, leaseId) {
+ return runExecutionCellLease({
+ action: 'release',
+ cellId: options.cellId,
+ leaseId,
+ artifactPaths: [],
+ hostPlaneReportPath: options.hostPlaneReportPath,
+ operatorCostProfilePath: options.operatorCostProfilePath,
+ leaseRoot: options.leaseRoot,
+ repoRoot: options.repoRoot,
+ now,
+ outputPath
+ });
+}
+
+async function maybeReleaseDockerLane(options, now, outputPath) {
+ const inspect = await runDockerLaneHandshake({
+ action: 'inspect',
+ laneId: options.laneId,
+ agentId: options.agentId,
+ agentClass: options.agentClass,
+ hostPlaneReportPath: options.hostPlaneReportPath,
+ operatorCostProfilePath: options.operatorCostProfilePath,
+ handshakeRoot: options.handshakeRoot,
+ repoRoot: options.repoRoot,
+ now,
+ outputPath
+ });
+ if (!inspect?.handshake || [STATUS.notFound, STATUS.released].includes(normalizeText(inspect.status))) {
+ return inspect;
+ }
+ return runDockerLaneHandshake({
+ action: 'release',
+ laneId: options.laneId,
+ agentId: options.agentId,
+ agentClass: options.agentClass,
+ leaseId: inspect?.handshake?.grant?.leaseId,
+ artifactPaths: [],
+ hostPlaneReportPath: options.hostPlaneReportPath,
+ operatorCostProfilePath: options.operatorCostProfilePath,
+ handshakeRoot: options.handshakeRoot,
+ repoRoot: options.repoRoot,
+ now,
+ outputPath
+ });
+}
+
+function buildReport({
+ action,
+ generatedAt,
+ cellId,
+ laneId,
+ outputPath,
+ dockerRequested,
+ capabilities,
+ executionCell,
+ dockerLane,
+ rollbacks
+}) {
+ const reports = [executionCell, dockerLane].filter(Boolean);
+ const effectiveRate = summarizeEffectiveRate(reports);
+ const premiumSaganMode =
+ executionCell?.summary?.premiumSaganMode === true || dockerLane?.summary?.premiumSaganMode === true;
+ const observations = collectSummaryStrings(reports, 'observations');
+ if (reports.length > 1 && effectiveRate.usdPerHour != null) {
+ observations.push('agent-billed-once-at-effective-rate');
+ }
+ if (rollbacks.executionCell) {
+ observations.push(`execution-cell-rollback-${rollbacks.executionCell.status}`);
+ }
+ if (rollbacks.dockerLane) {
+ observations.push(`docker-lane-rollback-${rollbacks.dockerLane.status}`);
+ }
+
+ return {
+ schema: EXECUTION_CELL_BUNDLE_REPORT_SCHEMA,
+ generatedAt,
+ action,
+ status: resolveBundleStatus(action, executionCell, dockerLane, rollbacks),
+ cellId,
+ laneId: toOptionalText(laneId),
+ outputPath,
+ executionCellReportPath: executionCell?.leasePath || null,
+ dockerLaneReportPath: dockerLane?.handshakePath || null,
+ executionCell,
+ dockerLane: dockerLane || null,
+ rollbacks: {
+ executionCell: rollbacks.executionCell || null,
+ dockerLane: rollbacks.dockerLane || null
+ },
+ summary: {
+ holder: toOptionalText(executionCell?.summary?.holder) || toOptionalText(dockerLane?.summary?.holder),
+ agentClass:
+ toOptionalText(executionCell?.summary?.agentClass) || toOptionalText(dockerLane?.handshake?.request?.agentClass),
+ cellClass: toOptionalText(executionCell?.summary?.cellClass),
+ suiteClass: toOptionalText(executionCell?.summary?.suiteClass),
+ planeBinding: toOptionalText(executionCell?.summary?.planeBinding),
+ harnessKind: toOptionalText(executionCell?.summary?.harnessKind),
+ harnessInstanceId: toOptionalText(executionCell?.summary?.harnessInstanceId),
+ executionCellLeaseId: toOptionalText(executionCell?.summary?.leaseId),
+ dockerLaneLeaseId: toOptionalText(dockerLane?.summary?.leaseId),
+ linkedExecutionCellId: toOptionalText(dockerLane?.summary?.linkedExecutionCellId),
+ linkedExecutionCellLeaseId: toOptionalText(dockerLane?.summary?.linkedExecutionCellLeaseId),
+ linkedDockerLaneId: toOptionalText(executionCell?.summary?.linkedDockerLaneId),
+ linkedDockerLaneLeaseId: toOptionalText(executionCell?.summary?.linkedDockerLaneLeaseId),
+ reciprocalLinkReady: hasReciprocalBundleLink(executionCell, dockerLane, cellId, laneId),
+ dockerRequested,
+ windowsNativeTestStand: isWindowsNativeTestStand(
+ executionCell?.summary?.planeBinding,
+ executionCell?.summary?.harnessKind
+ ),
+ effectiveBillableRateMultiplier: effectiveRate.multiplier,
+ effectiveBillableRateUsdPerHour: effectiveRate.usdPerHour,
+ premiumSaganMode,
+ operatorAuthorizationRef:
+ toOptionalText(executionCell?.summary?.operatorAuthorizationRef) ||
+ toOptionalText(dockerLane?.summary?.operatorAuthorizationRef),
+ isolatedLaneGroupId:
+ toOptionalText(executionCell?.summary?.isolatedLaneGroupId) ||
+ toOptionalText(dockerLane?.summary?.isolatedLaneGroupId),
+ fingerprintSha256:
+ toOptionalText(executionCell?.summary?.fingerprintSha256) ||
+ toOptionalText(dockerLane?.summary?.fingerprintSha256),
+ capabilities,
+ denialReasons: collectSummaryStrings([...reports, rollbacks.executionCell, rollbacks.dockerLane], 'denialReasons'),
+ observations: [...new Set(observations.filter(Boolean))]
+ }
+ };
+}
+
+function parseArgs(argv) {
+ const options = {
+ action: '',
+ cellId: '',
+ laneId: '',
+ agentId: '',
+ agentClass: '',
+ cellClass: '',
+ suiteClass: '',
+ planeBinding: '',
+ harnessKind: DEFAULT_HARNESS_KIND,
+ capabilities: [],
+ operatorId: '',
+ operatorAuthorizationRef: '',
+ workingRoot: '',
+ artifactRoot: '',
+ harnessInstanceId: '',
+ hostPlaneReportPath: '',
+ operatorCostProfilePath: '',
+ executionCellReportPath: '',
+ dockerLaneReportPath: '',
+ outputPath: '',
+ leaseRoot: '',
+ handshakeRoot: '',
+ artifactPaths: [],
+ help: false
+ };
+
+ for (let index = 2; index < argv.length; index += 1) {
+ const token = argv[index];
+ const next = argv[index + 1];
+ switch (token) {
+ case '--help':
+ case '-h':
+ options.help = true;
+ break;
+ case '--action':
+ options.action = next;
+ index += 1;
+ break;
+ case '--cell-id':
+ options.cellId = next;
+ index += 1;
+ break;
+ case '--lane-id':
+ options.laneId = next;
+ index += 1;
+ break;
+ case '--agent-id':
+ options.agentId = next;
+ index += 1;
+ break;
+ case '--agent-class':
+ options.agentClass = next;
+ index += 1;
+ break;
+ case '--cell-class':
+ options.cellClass = next;
+ index += 1;
+ break;
+ case '--suite-class':
+ options.suiteClass = next;
+ index += 1;
+ break;
+ case '--plane-binding':
+ options.planeBinding = next;
+ index += 1;
+ break;
+ case '--harness-kind':
+ options.harnessKind = next;
+ index += 1;
+ break;
+ case '--capability':
+ options.capabilities.push(next);
+ index += 1;
+ break;
+ case '--operator-id':
+ options.operatorId = next;
+ index += 1;
+ break;
+ case '--operator-authorization-ref':
+ options.operatorAuthorizationRef = next;
+ index += 1;
+ break;
+ case '--working-root':
+ options.workingRoot = next;
+ index += 1;
+ break;
+ case '--artifact-root':
+ options.artifactRoot = next;
+ index += 1;
+ break;
+ case '--harness-instance-id':
+ options.harnessInstanceId = next;
+ index += 1;
+ break;
+ case '--host-plane-report':
+ options.hostPlaneReportPath = next;
+ index += 1;
+ break;
+ case '--operator-cost-profile':
+ options.operatorCostProfilePath = next;
+ index += 1;
+ break;
+ case '--execution-cell-report':
+ options.executionCellReportPath = next;
+ index += 1;
+ break;
+ case '--docker-lane-report':
+ options.dockerLaneReportPath = next;
+ index += 1;
+ break;
+ case '--lease-root':
+ options.leaseRoot = next;
+ index += 1;
+ break;
+ case '--handshake-root':
+ options.handshakeRoot = next;
+ index += 1;
+ break;
+ case '--artifact-path':
+ options.artifactPaths.push(next);
+ index += 1;
+ break;
+ case '--output':
+ options.outputPath = next;
+ index += 1;
+ break;
+ default:
+ throw new Error(`Unknown argument '${token}'`);
+ }
+ }
+
+ return options;
+}
+
+function printUsage() {
+ console.log(
+ 'Usage: node tools/priority/execution-cell-bundle.mjs --action --cell-id [options]'
+ );
+}
+
+export async function runExecutionCellBundle(options = {}) {
+ const now = options.now || new Date();
+ const generatedAt = now.toISOString();
+ const repoRoot = path.resolve(options.repoRoot || REPO_ROOT);
+ const outputPath = path.resolve(repoRoot, options.outputPath || DEFAULT_OUTPUT_PATH);
+ const dockerRequested = wantsDockerLane(options);
+ const capabilities = inferBundleCapabilities(options.capabilities, options.planeBinding, dockerRequested);
+
+ if (!toOptionalText(options.cellId)) {
+ const report = buildReport({
+ action: options.action,
+ generatedAt,
+ cellId: '',
+ laneId: options.laneId,
+ outputPath,
+ dockerRequested,
+ capabilities,
+ executionCell: null,
+ dockerLane: null,
+ rollbacks: {}
+ });
+ report.status = STATUS.invalidState;
+ report.summary.denialReasons = ['cell-id-required'];
+ await writeReport(outputPath, report);
+ return report;
+ }
+
+ if (dockerRequested && !toOptionalText(options.laneId)) {
+ const report = buildReport({
+ action: options.action,
+ generatedAt,
+ cellId: options.cellId,
+ laneId: '',
+ outputPath,
+ dockerRequested,
+ capabilities,
+ executionCell: null,
+ dockerLane: null,
+ rollbacks: {}
+ });
+ report.status = STATUS.invalidState;
+ report.summary.denialReasons = ['lane-id-required'];
+ await writeReport(outputPath, report);
+ return report;
+ }
+
+ const executionCellReportPath = path.resolve(
+ repoRoot,
+ options.executionCellReportPath || DEFAULT_EXECUTION_CELL_REPORT_PATH
+ );
+ const dockerLaneReportPath = path.resolve(repoRoot, options.dockerLaneReportPath || DEFAULT_DOCKER_REPORT_PATH);
+
+ const executionCellOptions = {
+ action: options.action,
+ cellId: options.cellId,
+ agentId: options.agentId,
+ agentClass: options.agentClass,
+ cellClass: options.cellClass,
+ suiteClass: options.suiteClass,
+ planeBinding: options.planeBinding,
+ harnessKind: options.harnessKind || DEFAULT_HARNESS_KIND,
+ capabilities,
+ operatorId: options.operatorId,
+ operatorAuthorizationRef: options.operatorAuthorizationRef,
+ workingRoot: options.workingRoot,
+ artifactRoot: options.artifactRoot,
+ harnessInstanceId: options.harnessInstanceId,
+ dockerLaneReportPath,
+ hostPlaneReportPath: options.hostPlaneReportPath,
+ operatorCostProfilePath: options.operatorCostProfilePath,
+ leaseRoot: options.leaseRoot,
+ repoRoot,
+ now,
+ artifactPaths: options.artifactPaths,
+ outputPath: executionCellReportPath
+ };
+
+ const dockerLaneOptions = dockerRequested
+ ? {
+ action: options.action,
+ laneId: options.laneId,
+ agentId: options.agentId,
+ agentClass: options.agentClass,
+ capabilities,
+ operatorId: options.operatorId,
+ operatorAuthorizationRef: options.operatorAuthorizationRef,
+ executionCellReportPath,
+ hostPlaneReportPath: options.hostPlaneReportPath,
+ operatorCostProfilePath: options.operatorCostProfilePath,
+ handshakeRoot: options.handshakeRoot,
+ repoRoot,
+ now,
+ artifactPaths: options.artifactPaths,
+ outputPath: dockerLaneReportPath
+ }
+ : null;
+
+ let executionCell = null;
+ let dockerLane = null;
+ const rollbacks = {};
+
+ switch (normalizeText(options.action).toLowerCase()) {
+ case 'request':
+ executionCell = await runExecutionCellLease(executionCellOptions);
+ if (dockerLaneOptions) {
+ dockerLane = await runDockerLaneHandshake(dockerLaneOptions);
+ await writeReport(dockerLaneReportPath, dockerLane);
+ }
+ break;
+ case 'grant':
+ executionCell = await runExecutionCellLease(executionCellOptions);
+ if (dockerLaneOptions) {
+ if (normalizeText(executionCell?.status) === STATUS.granted) {
+ dockerLane = await runDockerLaneHandshake(dockerLaneOptions);
+ await writeReport(dockerLaneReportPath, dockerLane);
+ if (normalizeText(dockerLane?.status) !== STATUS.granted) {
+ rollbacks.executionCell = await maybeReleaseExecutionCell(
+ executionCellOptions,
+ now,
+ executionCellReportPath,
+ executionCell?.lease?.grant?.leaseId
+ );
+ }
+ } else {
+ rollbacks.dockerLane = await maybeReleaseDockerLane(dockerLaneOptions, now, dockerLaneReportPath);
+ }
+ }
+ break;
+ case 'commit':
+ if (dockerLaneOptions) {
+ dockerLane = await runDockerLaneHandshake(dockerLaneOptions);
+ await writeReport(dockerLaneReportPath, dockerLane);
+ if (normalizeText(dockerLane?.status) === STATUS.committed) {
+ executionCell = await runExecutionCellLease(executionCellOptions);
+ if (normalizeText(executionCell?.status) !== STATUS.committed) {
+ rollbacks.dockerLane = await maybeReleaseDockerLane(dockerLaneOptions, now, dockerLaneReportPath);
+ }
+ } else {
+ executionCell = await runExecutionCellLease({ ...executionCellOptions, action: 'inspect' });
+ }
+ } else {
+ executionCell = await runExecutionCellLease(executionCellOptions);
+ }
+ break;
+ case 'heartbeat':
+ if (dockerLaneOptions) {
+ dockerLane = await runDockerLaneHandshake(dockerLaneOptions);
+ await writeReport(dockerLaneReportPath, dockerLane);
+ }
+ executionCell = await runExecutionCellLease(executionCellOptions);
+ break;
+ case 'release':
+ if (dockerLaneOptions) {
+ dockerLane = await runDockerLaneHandshake(dockerLaneOptions);
+ await writeReport(dockerLaneReportPath, dockerLane);
+ }
+ executionCell = await runExecutionCellLease(executionCellOptions);
+ break;
+ case 'inspect':
+ executionCell = await runExecutionCellLease({ ...executionCellOptions, action: 'inspect' });
+ if (dockerLaneOptions) {
+ dockerLane = await runDockerLaneHandshake({ ...dockerLaneOptions, action: 'inspect' });
+ await writeReport(dockerLaneReportPath, dockerLane);
+ }
+ break;
+ default:
+ throw new Error(`Unsupported action '${options.action}'`);
+ }
+
+ const report = buildReport({
+ action: normalizeText(options.action).toLowerCase(),
+ generatedAt,
+ cellId: options.cellId,
+ laneId: options.laneId,
+ outputPath,
+ dockerRequested,
+ capabilities,
+ executionCell,
+ dockerLane,
+ rollbacks
+ });
+ await writeReport(outputPath, report);
+ return report;
+}
+
+function exitCodeForStatus(status) {
+ if ([STATUS.requested, STATUS.granted, STATUS.committed, STATUS.renewed, STATUS.released, STATUS.active].includes(status)) {
+ return 0;
+ }
+ if (status === STATUS.notFound) {
+ return 0;
+ }
+ return 1;
+}
+
+export async function main(argv = process.argv) {
+ const options = parseArgs(argv);
+ if (options.help) {
+ printUsage();
+ return 0;
+ }
+
+ const report = await runExecutionCellBundle({
+ ...options,
+ repoRoot: process.cwd()
+ });
+ console.log(
+ `[execution-cell-bundle] report: ${path.resolve(process.cwd(), options.outputPath || DEFAULT_OUTPUT_PATH)} status=${report.status} cell=${report.cellId} lane=${report.laneId ?? 'none'}`
+ );
+ return exitCodeForStatus(report.status);
+}
+
+const isEntrypoint = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
+if (isEntrypoint) {
+ const exitCode = await main(process.argv);
+ process.exitCode = exitCode;
+}
diff --git a/tools/priority/execution-cell-lease.mjs b/tools/priority/execution-cell-lease.mjs
new file mode 100644
index 000000000..b9f02bd92
--- /dev/null
+++ b/tools/priority/execution-cell-lease.mjs
@@ -0,0 +1,802 @@
+#!/usr/bin/env node
+
+import { spawnSync } from 'node:child_process';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import process from 'node:process';
+import { fileURLToPath } from 'node:url';
+
+import { resolveGitAdminPaths } from './lib/git-admin-paths.mjs';
+
+const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
+const REPO_ROOT = path.resolve(MODULE_DIR, '..', '..');
+
+export const EXECUTION_CELL_LEASE_SCHEMA = 'priority/execution-cell-lease@v1';
+export const EXECUTION_CELL_LEASE_REPORT_SCHEMA = 'priority/execution-cell-lease-report@v1';
+export const DEFAULT_OUTPUT_PATH = path.join('tests', 'results', '_agent', 'runtime', 'execution-cell-lease.json');
+export const DEFAULT_HOST_PLANE_REPORT_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'host-planes',
+ 'labview-2026-host-plane-report.json'
+);
+export const DEFAULT_OPERATOR_COST_PROFILE_PATH = path.join('tools', 'policy', 'operator-cost-profile.json');
+export const DEFAULT_TTL_SECONDS = 1800;
+export const DEFAULT_HARNESS_KIND = 'teststand-compare-harness';
+export const PREMIUM_RATE_MULTIPLIER = 1.5;
+export const ORDINARY_RATE_MULTIPLIER = 1.0;
+export const DOCKER_LANE_CAPABILITY = 'docker-lane';
+export const NATIVE_LV32_CAPABILITY = 'native-labview-2026-32';
+export const DEFAULT_CELL_CLASS = 'worker';
+
+export const STATUS = Object.freeze({
+ requested: 'requested',
+ granted: 'granted',
+ committed: 'committed',
+ renewed: 'renewed',
+ released: 'released',
+ active: 'active',
+ busy: 'busy',
+ denied: 'denied',
+ notFound: 'not-found',
+ mismatch: 'mismatch',
+ invalidState: 'invalid-state',
+ stale: 'stale'
+});
+
+export const CELL_CLASS = Object.freeze({
+ worker: 'worker',
+ coordinator: 'coordinator',
+ kernelCoordinator: 'kernel-coordinator'
+});
+
+function normalizeText(value) {
+ if (value == null) {
+ return '';
+ }
+ return String(value).trim();
+}
+
+function toOptionalText(value) {
+ const normalized = normalizeText(value);
+ return normalized || null;
+}
+
+function normalizeAgentClass(value) {
+ const normalized = normalizeText(value).toLowerCase();
+ if (['sagan', 'subagent', 'other'].includes(normalized)) {
+ return normalized;
+ }
+ return 'subagent';
+}
+
+function normalizeCellClass(value) {
+ const normalized = normalizeText(value).toLowerCase();
+ if (Object.values(CELL_CLASS).includes(normalized)) {
+ return normalized;
+ }
+ return DEFAULT_CELL_CLASS;
+}
+
+function nowIso(now = new Date()) {
+ return now.toISOString();
+}
+
+function uniqueId(prefix = 'id', now = Date.now()) {
+ return `${prefix}-${now}-${Math.random().toString(16).slice(2, 10)}`;
+}
+
+function sanitizeCellId(cellId) {
+ return normalizeText(cellId).replace(/[^a-zA-Z0-9._-]+/g, '__');
+}
+
+function resolveDefaultLeaseRoot(options = {}) {
+ try {
+ return path.join(
+ resolveGitAdminPaths({
+ cwd: options.repoRoot || REPO_ROOT,
+ env: options.env || process.env,
+ spawnSyncFn: options.spawnSyncFn || spawnSync
+ }).gitCommonDir,
+ 'execution-cell-leases'
+ );
+ } catch {
+ return path.join(options.repoRoot || REPO_ROOT, '.git', 'execution-cell-leases');
+ }
+}
+
+export function defaultLeaseRoot(options = {}) {
+ return options.leaseRoot || process.env.EXECUTION_CELL_LEASE_ROOT || resolveDefaultLeaseRoot(options);
+}
+
+export function leasePathForCell(cellId, leaseRoot = defaultLeaseRoot()) {
+ return path.join(leaseRoot, `${sanitizeCellId(cellId)}.json`);
+}
+
+async function ensureParentDir(filePath) {
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
+}
+
+async function readJsonIfPresent(filePath) {
+ try {
+ return JSON.parse(await fs.readFile(filePath, 'utf8'));
+ } catch (error) {
+ if (error?.code === 'ENOENT') {
+ return null;
+ }
+ throw error;
+ }
+}
+
+async function writeJsonAtomic(filePath, payload) {
+ await ensureParentDir(filePath);
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
+ const body = `${JSON.stringify(payload, null, 2)}\n`;
+ await fs.writeFile(tempPath, body, 'utf8');
+ try {
+ await fs.rename(tempPath, filePath);
+ } finally {
+ await fs.rm(tempPath, { force: true });
+ }
+}
+
+function normalizeCapabilities(capabilities = []) {
+ const values = [];
+ for (const entry of capabilities) {
+ const normalized = normalizeText(entry);
+ if (normalized) {
+ values.push(normalized);
+ }
+ }
+ return [...new Set(values)];
+}
+
+function isPremiumDualLaneRequest(capabilities = []) {
+ const set = new Set(normalizeCapabilities(capabilities));
+ return set.has(DOCKER_LANE_CAPABILITY) && set.has(NATIVE_LV32_CAPABILITY);
+}
+
+function isWindowsNativeTestStandPlaneBinding(planeBinding) {
+ const normalized = normalizeText(planeBinding).toLowerCase();
+ if (!normalized) {
+ return true;
+ }
+ return normalized === 'dual-plane-parity' || normalized.startsWith('native-labview-');
+}
+
+function resolveHeartbeatTimestamp(lease) {
+ return (
+ lease?.heartbeatAt ||
+ lease?.commit?.committedAt ||
+ lease?.grant?.grantedAt ||
+ lease?.request?.requestedAt ||
+ null
+ );
+}
+
+function leaseAgeSeconds(lease, nowMs = Date.now()) {
+ const timestamp = resolveHeartbeatTimestamp(lease);
+ if (!timestamp) {
+ return Number.POSITIVE_INFINITY;
+ }
+ const parsed = Date.parse(timestamp);
+ if (!Number.isFinite(parsed)) {
+ return Number.POSITIVE_INFINITY;
+ }
+ return Math.max(0, (nowMs - parsed) / 1000);
+}
+
+function resolveTtlSeconds(lease) {
+ return Number.isInteger(lease?.grant?.ttlSeconds) ? lease.grant.ttlSeconds : DEFAULT_TTL_SECONDS;
+}
+
+export function isExecutionCellLeaseStale(lease, nowMs = Date.now()) {
+ if (!lease || lease.state === 'released') {
+ return false;
+ }
+ return leaseAgeSeconds(lease, nowMs) > resolveTtlSeconds(lease);
+}
+
+function buildHostContext(hostPlaneReport) {
+ const fingerprint = hostPlaneReport?.host?.osFingerprint;
+ if (!fingerprint || typeof fingerprint !== 'object') {
+ return {
+ context: null,
+ observations: ['host-os-fingerprint-missing']
+ };
+ }
+
+ return {
+ context: {
+ isolatedLaneGroupId: toOptionalText(fingerprint.isolatedLaneGroupId),
+ fingerprintSha256: toOptionalText(fingerprint.fingerprintSha256),
+ platform: toOptionalText(fingerprint.platform),
+ computerName: toOptionalText(hostPlaneReport?.host?.computerName),
+ canonical: {
+ version: toOptionalText(fingerprint?.canonical?.version),
+ buildNumber: toOptionalText(fingerprint?.canonical?.buildNumber),
+ ubr: Number.isInteger(fingerprint?.canonical?.ubr) ? fingerprint.canonical.ubr : null
+ }
+ },
+ observations: []
+ };
+}
+
+function resolveOperatorProfile(profile, explicitOperatorId) {
+ const operators = Array.isArray(profile?.operators) ? profile.operators : [];
+ const desiredId = toOptionalText(explicitOperatorId) || toOptionalText(profile?.defaultOperatorId);
+ const activeOperators = operators.filter((entry) => entry?.active !== false);
+ const resolved =
+ activeOperators.find((entry) => normalizeText(entry?.id) === normalizeText(desiredId)) ||
+ activeOperators[0] ||
+ null;
+
+ return {
+ operatorId: toOptionalText(resolved?.id) || desiredId,
+ currency: toOptionalText(profile?.currency) || 'USD',
+ laborRateUsdPerHour: Number.isFinite(resolved?.laborRateUsdPerHour)
+ ? Number(resolved.laborRateUsdPerHour)
+ : null
+ };
+}
+
+function buildRequestRecord({
+ cellId,
+ agentId,
+ agentClass,
+ cellClass,
+ suiteClass,
+ planeBinding,
+ harnessKind,
+ capabilities,
+ operatorId,
+ operatorAuthorizationRef,
+ workingRoot,
+ artifactRoot,
+ now,
+ requestId,
+ hostContext
+}) {
+ const requestedCapabilities = normalizeCapabilities(capabilities);
+ const premiumDualLaneRequested = isPremiumDualLaneRequest(requestedCapabilities);
+ const generatedAt = nowIso(now);
+ return {
+ schema: EXECUTION_CELL_LEASE_SCHEMA,
+ generatedAt,
+ cellId,
+ resourceKind: 'execution-cell',
+ state: 'requested',
+ sequence: 1,
+ heartbeatAt: generatedAt,
+ host: hostContext,
+ request: {
+ requestId,
+ requestedAt: generatedAt,
+ agentId,
+ agentClass,
+ cellClass,
+ suiteClass: toOptionalText(suiteClass),
+ planeBinding: toOptionalText(planeBinding),
+ harnessKind: toOptionalText(harnessKind) || DEFAULT_HARNESS_KIND,
+ capabilities: requestedCapabilities,
+ premiumDualLaneRequested,
+ operatorId: toOptionalText(operatorId),
+ operatorAuthorizationRef: toOptionalText(operatorAuthorizationRef),
+ workingRoot: toOptionalText(workingRoot),
+ artifactRoot: toOptionalText(artifactRoot)
+ },
+ grant: null,
+ commit: null,
+ release: null
+ };
+}
+
+function buildGrantDecision(lease, operatorProfile, nowMs = Date.now()) {
+ const reasons = [];
+ const stale = isExecutionCellLeaseStale(lease, nowMs);
+ const leaseState = toOptionalText(lease?.state);
+ const requestedCapabilities = normalizeCapabilities(lease?.request?.capabilities);
+ const premiumDualLaneRequested = lease?.request?.premiumDualLaneRequested === true;
+ const requestedCellClass = normalizeCellClass(lease?.request?.cellClass);
+ const requestedHarnessKind = toOptionalText(lease?.request?.harnessKind) || DEFAULT_HARNESS_KIND;
+ const requestedPlaneBinding = toOptionalText(lease?.request?.planeBinding);
+ if (leaseState === 'active' && !stale) {
+ reasons.push('execution-cell-already-active');
+ }
+ if (
+ requestedHarnessKind === DEFAULT_HARNESS_KIND &&
+ !isWindowsNativeTestStandPlaneBinding(requestedPlaneBinding)
+ ) {
+ reasons.push('teststand-windows-native-only');
+ }
+ if (requestedCellClass === CELL_CLASS.kernelCoordinator && lease?.request?.agentClass !== 'sagan') {
+ reasons.push('kernel-cell-sagan-only');
+ }
+ if (premiumDualLaneRequested && lease?.request?.agentClass !== 'sagan') {
+ reasons.push('premium-sagan-only');
+ }
+ if (premiumDualLaneRequested && requestedCellClass !== CELL_CLASS.kernelCoordinator) {
+ reasons.push('premium-kernel-cell-required');
+ }
+ if (premiumDualLaneRequested && !toOptionalText(lease?.request?.operatorAuthorizationRef)) {
+ reasons.push('operator-authorization-required');
+ }
+ if (!Number.isFinite(operatorProfile?.laborRateUsdPerHour)) {
+ reasons.push('operator-cost-rate-unavailable');
+ }
+
+ const billableRateMultiplier = premiumDualLaneRequested ? PREMIUM_RATE_MULTIPLIER : ORDINARY_RATE_MULTIPLIER;
+ return {
+ allowed: reasons.length === 0,
+ reasons,
+ premiumDualLaneRequested,
+ premiumSaganMode: premiumDualLaneRequested,
+ policyDecision: premiumDualLaneRequested ? 'sagan-premium-dual-lane' : 'ordinary-execution-cell',
+ grantedCapabilities: requestedCapabilities,
+ billableRateMultiplier,
+ billableRateUsdPerHour: Number.isFinite(operatorProfile?.laborRateUsdPerHour)
+ ? Number((operatorProfile.laborRateUsdPerHour * billableRateMultiplier).toFixed(3))
+ : null
+ };
+}
+
+function buildBaseReport(action, cellId, leasePath, generatedAt, lease, extras = {}) {
+ const stale = isExecutionCellLeaseStale(lease, Date.parse(generatedAt));
+ return {
+ schema: EXECUTION_CELL_LEASE_REPORT_SCHEMA,
+ generatedAt,
+ action,
+ cellId,
+ leasePath,
+ lease,
+ summary: {
+ leaseState: lease?.state ?? null,
+ leaseId: toOptionalText(lease?.grant?.leaseId),
+ holder: toOptionalText(lease?.request?.agentId),
+ agentClass: toOptionalText(lease?.request?.agentClass),
+ cellClass: toOptionalText(lease?.request?.cellClass),
+ harnessKind: toOptionalText(lease?.request?.harnessKind),
+ harnessInstanceId: toOptionalText(lease?.commit?.harnessInstanceId),
+ suiteClass: toOptionalText(lease?.request?.suiteClass),
+ planeBinding: toOptionalText(lease?.request?.planeBinding),
+ premiumSaganMode:
+ lease?.grant?.premiumSaganMode === true || lease?.request?.premiumDualLaneRequested === true,
+ billableRateMultiplier: Number.isFinite(lease?.grant?.billableRateMultiplier)
+ ? lease.grant.billableRateMultiplier
+ : null,
+ billableRateUsdPerHour: Number.isFinite(lease?.grant?.billableRateUsdPerHour)
+ ? lease.grant.billableRateUsdPerHour
+ : null,
+ operatorAuthorizationRef: toOptionalText(lease?.request?.operatorAuthorizationRef),
+ isolatedLaneGroupId: toOptionalText(lease?.host?.isolatedLaneGroupId),
+ fingerprintSha256: toOptionalText(lease?.host?.fingerprintSha256),
+ linkedDockerLaneId: toOptionalText(lease?.commit?.dockerLaneId),
+ linkedDockerLaneLeaseId: toOptionalText(lease?.commit?.dockerLaneLeaseId),
+ workingRoot: toOptionalText(lease?.commit?.workingRoot) || toOptionalText(lease?.request?.workingRoot),
+ artifactRoot: toOptionalText(lease?.commit?.artifactRoot) || toOptionalText(lease?.request?.artifactRoot),
+ isStale: stale,
+ ageSeconds: Number.isFinite(leaseAgeSeconds(lease, Date.parse(generatedAt)))
+ ? Number(leaseAgeSeconds(lease, Date.parse(generatedAt)).toFixed(3))
+ : null,
+ ttlSeconds: lease ? resolveTtlSeconds(lease) : null,
+ denialReasons: [],
+ observations: []
+ },
+ ...extras
+ };
+}
+
+function resolveDockerLaneLinkContext(report) {
+ if (!report || typeof report !== 'object') {
+ return null;
+ }
+ const handshake = report.handshake;
+ if (!handshake || typeof handshake !== 'object') {
+ return null;
+ }
+ return {
+ laneId: toOptionalText(report?.laneId) || toOptionalText(handshake?.laneId),
+ leaseId: toOptionalText(report?.summary?.leaseId) || toOptionalText(handshake?.grant?.leaseId),
+ holder: toOptionalText(report?.summary?.holder) || toOptionalText(handshake?.request?.agentId),
+ isolatedLaneGroupId:
+ toOptionalText(report?.summary?.isolatedLaneGroupId) || toOptionalText(handshake?.host?.isolatedLaneGroupId),
+ fingerprintSha256:
+ toOptionalText(report?.summary?.fingerprintSha256) || toOptionalText(handshake?.host?.fingerprintSha256)
+ };
+}
+
+function validateDockerLaneLink(lease, linkedDockerLane) {
+ if (!linkedDockerLane) {
+ return ['docker-lane-report-invalid'];
+ }
+
+ const reasons = [];
+ if (!linkedDockerLane.laneId) {
+ reasons.push('docker-lane-id-missing');
+ }
+ if (!linkedDockerLane.leaseId) {
+ reasons.push('docker-lane-lease-id-missing');
+ }
+ if (!linkedDockerLane.holder) {
+ reasons.push('docker-lane-holder-missing');
+ }
+ if (!linkedDockerLane.isolatedLaneGroupId || !linkedDockerLane.fingerprintSha256) {
+ reasons.push('docker-lane-host-fingerprint-missing');
+ }
+
+ const leaseHolder = toOptionalText(lease?.request?.agentId);
+ if (leaseHolder && linkedDockerLane.holder && linkedDockerLane.holder !== leaseHolder) {
+ reasons.push('docker-lane-owner-mismatch');
+ }
+
+ const leaseIsolatedLaneGroupId = toOptionalText(lease?.host?.isolatedLaneGroupId);
+ const leaseFingerprintSha256 = toOptionalText(lease?.host?.fingerprintSha256);
+ if (
+ leaseIsolatedLaneGroupId &&
+ linkedDockerLane.isolatedLaneGroupId &&
+ linkedDockerLane.isolatedLaneGroupId !== leaseIsolatedLaneGroupId
+ ) {
+ reasons.push('docker-lane-isolated-lane-group-mismatch');
+ }
+ if (
+ leaseFingerprintSha256 &&
+ linkedDockerLane.fingerprintSha256 &&
+ linkedDockerLane.fingerprintSha256 !== leaseFingerprintSha256
+ ) {
+ reasons.push('docker-lane-host-fingerprint-mismatch');
+ }
+
+ return reasons;
+}
+
+function parseArgs(argv) {
+ const result = {
+ action: 'inspect',
+ capabilities: [],
+ artifactPaths: []
+ };
+ for (let index = 0; index < argv.length; index += 1) {
+ const token = argv[index];
+ if (token === '--action') {
+ result.action = argv[++index];
+ } else if (token === '--cell-id') {
+ result.cellId = argv[++index];
+ } else if (token === '--agent-id') {
+ result.agentId = argv[++index];
+ } else if (token === '--agent-class') {
+ result.agentClass = argv[++index];
+ } else if (token === '--cell-class') {
+ result.cellClass = argv[++index];
+ } else if (token === '--suite-class') {
+ result.suiteClass = argv[++index];
+ } else if (token === '--plane-binding') {
+ result.planeBinding = argv[++index];
+ } else if (token === '--harness-kind') {
+ result.harnessKind = argv[++index];
+ } else if (token === '--working-root') {
+ result.workingRoot = argv[++index];
+ } else if (token === '--artifact-root') {
+ result.artifactRoot = argv[++index];
+ } else if (token === '--docker-lane-report-path') {
+ result.dockerLaneReportPath = argv[++index];
+ } else if (token === '--lease-id') {
+ result.leaseId = argv[++index];
+ } else if (token === '--harness-instance-id') {
+ result.harnessInstanceId = argv[++index];
+ } else if (token === '--operator-id') {
+ result.operatorId = argv[++index];
+ } else if (token === '--operator-authorization-ref') {
+ result.operatorAuthorizationRef = argv[++index];
+ } else if (token === '--host-plane-report-path') {
+ result.hostPlaneReportPath = argv[++index];
+ } else if (token === '--operator-cost-profile-path') {
+ result.operatorCostProfilePath = argv[++index];
+ } else if (token === '--output-path') {
+ result.outputPath = argv[++index];
+ } else if (token === '--lease-root') {
+ result.leaseRoot = argv[++index];
+ } else if (token === '--capability') {
+ result.capabilities.push(argv[++index]);
+ } else if (token === '--premium-dual-lane') {
+ result.capabilities.push(DOCKER_LANE_CAPABILITY);
+ result.capabilities.push(NATIVE_LV32_CAPABILITY);
+ } else if (token === '--artifact-path') {
+ result.artifactPaths.push(argv[++index]);
+ }
+ }
+ return result;
+}
+
+async function loadOptionalJson(filePath) {
+ if (!filePath) {
+ return null;
+ }
+ return readJsonIfPresent(filePath);
+}
+
+export async function runExecutionCellLease(options = {}) {
+ const action = toOptionalText(options.action) || 'inspect';
+ const cellId = toOptionalText(options.cellId);
+ if (!cellId) {
+ throw new Error('cellId is required');
+ }
+
+ const repoRoot = options.repoRoot || REPO_ROOT;
+ const leaseRoot = defaultLeaseRoot({ ...options, repoRoot });
+ const leasePath = leasePathForCell(cellId, leaseRoot);
+ const outputPath = path.resolve(repoRoot, options.outputPath || DEFAULT_OUTPUT_PATH);
+ const hostPlaneReportPath = path.resolve(repoRoot, options.hostPlaneReportPath || DEFAULT_HOST_PLANE_REPORT_PATH);
+ const operatorCostProfilePath = path.resolve(
+ repoRoot,
+ options.operatorCostProfilePath || DEFAULT_OPERATOR_COST_PROFILE_PATH
+ );
+ const now = options.now || new Date();
+ const generatedAt = nowIso(now);
+
+ const hostPlaneReport = await loadOptionalJson(hostPlaneReportPath);
+ const operatorCostProfile = await loadOptionalJson(operatorCostProfilePath);
+ const hostContext = buildHostContext(hostPlaneReport);
+ const operatorProfile = resolveOperatorProfile(operatorCostProfile, options.operatorId);
+ const agentClass = normalizeAgentClass(options.agentClass);
+ const cellClass = normalizeCellClass(options.cellClass);
+ const capabilities = normalizeCapabilities(options.capabilities);
+
+ const existing = await readJsonIfPresent(leasePath);
+
+ if (action === 'request') {
+ const lease = buildRequestRecord({
+ cellId,
+ agentId: toOptionalText(options.agentId),
+ agentClass,
+ cellClass,
+ suiteClass: options.suiteClass,
+ planeBinding: options.planeBinding,
+ harnessKind: options.harnessKind,
+ capabilities,
+ operatorId: operatorProfile.operatorId,
+ operatorAuthorizationRef: options.operatorAuthorizationRef,
+ workingRoot: options.workingRoot,
+ artifactRoot: options.artifactRoot,
+ now,
+ requestId: uniqueId('request', now.getTime()),
+ hostContext: hostContext.context
+ });
+
+ await writeJsonAtomic(leasePath, lease);
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, lease, {
+ status: STATUS.requested,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.observations.push(...hostContext.observations);
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ if (!existing) {
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, null, {
+ status: STATUS.notFound,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.observations.push('execution-cell-lease-missing');
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ if (action === 'grant') {
+ const decision = buildGrantDecision(existing, operatorProfile, now.getTime());
+ if (!decision.allowed) {
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, existing, {
+ status: decision.reasons.includes('execution-cell-already-active') ? STATUS.busy : STATUS.denied,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.denialReasons.push(...decision.reasons);
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ const lease = {
+ ...existing,
+ generatedAt,
+ state: 'granted',
+ sequence: Number.isInteger(existing.sequence) ? existing.sequence + 1 : 2,
+ heartbeatAt: generatedAt,
+ host: hostContext.context || existing.host || null,
+ grant: {
+ grantedAt: generatedAt,
+ grantor: toOptionalText(options.grantor) || 'execution-cell-governor',
+ leaseId: uniqueId('lease', now.getTime()),
+ ttlSeconds: Number.isInteger(options.ttlSeconds) ? options.ttlSeconds : DEFAULT_TTL_SECONDS,
+ premiumDualLaneRequested: decision.premiumDualLaneRequested,
+ premiumSaganMode: decision.premiumSaganMode,
+ policyDecision: decision.policyDecision,
+ grantedCapabilities: decision.grantedCapabilities,
+ billableRateMultiplier: decision.billableRateMultiplier,
+ billableRateUsdPerHour: decision.billableRateUsdPerHour
+ }
+ };
+
+ await writeJsonAtomic(leasePath, lease);
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, lease, {
+ status: STATUS.granted,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.observations.push(...hostContext.observations);
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ if (action === 'commit' || action === 'heartbeat') {
+ const leaseId = toOptionalText(options.leaseId);
+ if (leaseId && leaseId !== toOptionalText(existing?.grant?.leaseId)) {
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, existing, {
+ status: STATUS.mismatch,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.denialReasons.push('lease-id-mismatch');
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ if (toOptionalText(existing.state) !== 'granted' && toOptionalText(existing.state) !== 'active') {
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, existing, {
+ status: STATUS.invalidState,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.denialReasons.push('execution-cell-not-granted');
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ let linkedDockerLane = null;
+ if (action === 'commit' && toOptionalText(options.dockerLaneReportPath)) {
+ linkedDockerLane = resolveDockerLaneLinkContext(
+ await loadOptionalJson(path.resolve(repoRoot, options.dockerLaneReportPath))
+ );
+ const linkReasons = validateDockerLaneLink(existing, linkedDockerLane);
+ if (linkReasons.length > 0) {
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, existing, {
+ status: STATUS.mismatch,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.denialReasons.push(...linkReasons);
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+ }
+
+ const lease = {
+ ...existing,
+ generatedAt,
+ state: 'active',
+ sequence: Number.isInteger(existing.sequence) ? existing.sequence + 1 : 2,
+ heartbeatAt: generatedAt,
+ host: hostContext.context || existing.host || null,
+ commit: {
+ committedAt: generatedAt,
+ harnessInstanceId:
+ toOptionalText(options.harnessInstanceId) || toOptionalText(existing?.commit?.harnessInstanceId),
+ dockerLaneId:
+ linkedDockerLane?.laneId || toOptionalText(existing?.commit?.dockerLaneId),
+ dockerLaneLeaseId:
+ linkedDockerLane?.leaseId || toOptionalText(existing?.commit?.dockerLaneLeaseId),
+ workingRoot: toOptionalText(options.workingRoot) || toOptionalText(existing?.request?.workingRoot),
+ artifactRoot: toOptionalText(options.artifactRoot) || toOptionalText(existing?.request?.artifactRoot)
+ }
+ };
+
+ await writeJsonAtomic(leasePath, lease);
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, lease, {
+ status: action === 'commit' ? STATUS.committed : STATUS.renewed,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.observations.push(...hostContext.observations);
+ if (linkedDockerLane?.laneId) {
+ report.summary.observations.push('linked-docker-lane-commit');
+ }
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ if (action === 'release') {
+ const leaseId = toOptionalText(options.leaseId);
+ if (leaseId && leaseId !== toOptionalText(existing?.grant?.leaseId)) {
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, existing, {
+ status: STATUS.mismatch,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ report.summary.denialReasons.push('lease-id-mismatch');
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ const lease = {
+ ...existing,
+ generatedAt,
+ state: 'released',
+ sequence: Number.isInteger(existing.sequence) ? existing.sequence + 1 : 2,
+ heartbeatAt: generatedAt,
+ release: {
+ releasedAt: generatedAt,
+ artifactPaths: options.artifactPaths?.map((entry) => normalizeText(entry)).filter(Boolean) || []
+ }
+ };
+ await writeJsonAtomic(leasePath, lease);
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, lease, {
+ status: STATUS.released,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ if (action === 'inspect') {
+ const stale = isExecutionCellLeaseStale(existing, now.getTime());
+ const report = buildBaseReport(action, cellId, leasePath, generatedAt, existing, {
+ status: stale ? STATUS.stale : toOptionalText(existing.state) === 'released' ? STATUS.released : STATUS.active,
+ policy: {
+ operatorId: operatorProfile.operatorId,
+ currency: operatorProfile.currency,
+ laborRateUsdPerHour: operatorProfile.laborRateUsdPerHour
+ }
+ });
+ await writeJsonAtomic(outputPath, report);
+ return report;
+ }
+
+ throw new Error(`Unsupported action '${action}'`);
+}
+
+async function main() {
+ const options = parseArgs(process.argv.slice(2));
+ const report = await runExecutionCellLease(options);
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
+}
+
+const isEntrypoint = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
+if (isEntrypoint) {
+ main().catch((error) => {
+ console.error(error instanceof Error ? error.message : String(error));
+ process.exitCode = 1;
+ });
+}
diff --git a/tools/priority/github-comment-budget-hook.mjs b/tools/priority/github-comment-budget-hook.mjs
new file mode 100644
index 000000000..78cfe2735
--- /dev/null
+++ b/tools/priority/github-comment-budget-hook.mjs
@@ -0,0 +1,475 @@
+#!/usr/bin/env node
+
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { runMaterializeAgentCostRollup } from './materialize-agent-cost-rollup.mjs';
+
+export const REPORT_SCHEMA = 'priority/github-comment-budget-hook@v1';
+export const POLICY_SCHEMA = 'priority/github-comment-budget-hook-policy@v1';
+export const DEFAULT_POLICY_PATH = path.join('tools', 'policy', 'github-comment-budget-hook.json');
+export const DEFAULT_OUTPUT_PATH = path.join('tests', 'results', '_agent', 'cost', 'github-comment-budget-hook.json');
+export const DEFAULT_MARKDOWN_OUTPUT_PATH = path.join('tests', 'results', '_agent', 'cost', 'github-comment-budget-hook.md');
+export const COMMENT_HOOK_START_MARKER = '';
+export const COMMENT_HOOK_END_MARKER = '';
+export const COMMENT_HOOK_JSON_PREFIX = '`
+ ];
+
+ if (report.summary.status === 'blocked') {
+ const blockerCodes = report.blockers.map((entry) => `\`${entry.code}\``).join(', ');
+ lines.push(`_Budget hook_: unavailable (${blockerCodes || '`unknown-blocker`'}). Receipt: \`${report.source.outputPath ?? 'none'}\`.`);
+ } else {
+ const billingWindow = report.funding.billingWindow;
+ const reservedFunding = report.funding.reservedFunding;
+ const operatorBudgetText = report.summary.operatorBudgetCapUsd == null
+ ? 'operator cap unknown'
+ : `operator ${formatUsd(report.summary.operatorLaborObservedUsd)} of ${formatUsd(report.summary.operatorBudgetCapUsd)} cap (remaining ${report.summary.operatorBudgetRemainingStatus === 'lower-bound' ? '>=' : ''}${formatUsd(report.summary.operatorBudgetRemainingLowerBoundUsd)})`;
+ const billingWindowText = billingWindow?.invoiceTurnId
+ ? `window \`${billingWindow.invoiceTurnId}\` spent ${formatUsd(billingWindow.tokenSpendUsd)} remaining ${formatUsd(billingWindow.remainingUsd)}`
+ : 'window unavailable';
+ const reserveText = reservedFunding.count > 0
+ ? `; calibration reserve ${formatUsd(reservedFunding.totalReservedUsd)} across ${reservedFunding.count} held window(s)`
+ : '';
+ const timingText = report.summary.operatorLaborMissingTurnCount > 0
+ ? `; ${report.summary.operatorLaborMissingTurnCount} turn(s) still pending labor timing`
+ : '';
+ lines.push(`_Budget hook_: blended lower bound ${formatUsd(report.summary.observedBlendedLowerBoundUsd)}; ${operatorBudgetText}; ${billingWindowText}; turns ${report.turns.totalTurns} total (${report.turns.liveTurnCount} live, ${report.turns.backgroundTurnCount} background)${timingText}${reserveText}. Receipt: \`${report.source.outputPath}\`.`);
+ }
+
+ lines.push(COMMENT_HOOK_END_MARKER, '');
+ return `${lines.join('\n').trimEnd()}\n`;
+}
+
+export function stripExistingBudgetHook(body) {
+ const normalizedBody = normalizeText(body);
+ if (!normalizedBody.includes(COMMENT_HOOK_START_MARKER)) {
+ return normalizedBody;
+ }
+ const startIndex = normalizedBody.indexOf(COMMENT_HOOK_START_MARKER);
+ const endIndex = normalizedBody.indexOf(COMMENT_HOOK_END_MARKER, startIndex);
+ if (startIndex < 0 || endIndex < 0) {
+ return normalizedBody;
+ }
+ const prefix = normalizedBody.slice(0, startIndex).trimEnd();
+ const suffix = normalizedBody.slice(endIndex + COMMENT_HOOK_END_MARKER.length).trimStart();
+ if (prefix && suffix) {
+ return `${prefix}\n\n${suffix}`.trimEnd();
+ }
+ return (prefix || suffix || '').trimEnd();
+}
+
+export function appendBudgetHook(body, hookMarkdown) {
+ const cleanBody = stripExistingBudgetHook(body);
+ const hook = normalizeText(hookMarkdown);
+ if (!hook) {
+ return cleanBody;
+ }
+ if (!cleanBody) {
+ return `${hook}\n`;
+ }
+ return `${cleanBody}\n\n${hook}\n`;
+}
+
+export function buildGitHubCommentBudgetHookReport({ rollup, repository, targetKind, targetNumber, operatorBudgetCapUsd, reservedFunding, billingWindow, source, blockers, now }) {
+ const metrics = rollup?.summary?.metrics ?? {};
+ const tokenSpendUsd = toNonNegativeNumber(metrics.totalUsd) ?? 0;
+ const operatorLaborObservedUsd = toNonNegativeNumber(metrics.operatorLaborUsd) ?? 0;
+ const operatorLaborMissingTurnCount = Number(metrics.operatorLaborMissingTurnCount ?? 0) || 0;
+ const observedBlendedLowerBoundUsd = roundUsd(tokenSpendUsd + operatorLaborObservedUsd) ?? 0;
+ const knownBlendedUsd = toNonNegativeNumber(metrics.blendedTotalUsd);
+ const operatorBudgetRemainingLowerBoundUsd =
+ operatorBudgetCapUsd == null ? null : roundUsd(Math.max(0, operatorBudgetCapUsd - operatorLaborObservedUsd));
+ const operatorBudgetRemainingStatus =
+ operatorBudgetCapUsd == null ? 'unknown' : operatorLaborMissingTurnCount > 0 ? 'lower-bound' : 'observed';
+
+ const blocking = Array.isArray(blockers) ? blockers.filter(Boolean) : [];
+ const status = blocking.length > 0 ? 'blocked' : operatorLaborMissingTurnCount > 0 ? 'warn' : 'pass';
+ const recommendation =
+ status === 'blocked'
+ ? 'repair-comment-budget-hook-inputs'
+ : operatorLaborMissingTurnCount > 0
+ ? 'continue-observing-labor-timing'
+ : 'comment-budget-hook-ready';
+
+ return {
+ schema: REPORT_SCHEMA,
+ generatedAt: now.toISOString(),
+ repository,
+ target: {
+ kind: asOptional(targetKind) || 'unknown',
+ number: targetNumber ?? null
+ },
+ summary: {
+ status,
+ recommendation,
+ tokenSpendUsd,
+ operatorLaborObservedUsd,
+ operatorLaborMissingTurnCount,
+ observedBlendedLowerBoundUsd,
+ knownBlendedUsd,
+ operatorBudgetCapUsd,
+ operatorBudgetRemainingLowerBoundUsd,
+ operatorBudgetRemainingStatus
+ },
+ turns: {
+ totalTurns: Number(metrics.totalTurns ?? 0) || 0,
+ liveTurnCount: Number(metrics.liveTurnCount ?? 0) || 0,
+ backgroundTurnCount: Number(metrics.backgroundTurnCount ?? 0) || 0
+ },
+ funding: {
+ billingWindow,
+ reservedFunding
+ },
+ source,
+ blockers: blocking
+ };
+}
+
+export function runGitHubCommentBudgetHook(
+ options,
+ {
+ now = new Date(),
+ readJsonFn = readJson,
+ writeJsonFn = writeJson,
+ writeTextFn = writeText,
+ runMaterializeAgentCostRollupFn = runMaterializeAgentCostRollup
+ } = {}
+) {
+ const repoRoot = path.resolve(options.repoRoot || process.cwd());
+ const { resolvedPolicyPath, policy } = loadPolicy(repoRoot, options.policyPath || DEFAULT_POLICY_PATH);
+ let costRollupPath = path.resolve(repoRoot, options.costRollupPath || asOptional(policy.costRollupPath) || DEFAULT_OUTPUT_PATH.replace('github-comment-budget-hook', 'agent-cost-rollup'));
+ let costRollupMaterialized = false;
+ let costRollupMaterializationReportPath = null;
+ const blockers = [];
+
+ const shouldMaterialize = options.materialize ?? Boolean(policy.materializeCostRollup);
+ if (shouldMaterialize) {
+ try {
+ const materializeResult = runMaterializeAgentCostRollupFn({
+ repoRoot,
+ repo: options.repo,
+ policyPath: asOptional(policy.materializationPolicyPath) || undefined,
+ costRollupPath,
+ outputPath: asOptional(policy.materializationReportPath) || undefined
+ });
+ costRollupMaterialized = true;
+ costRollupPath = path.resolve(materializeResult.costRollupPath || costRollupPath);
+ costRollupMaterializationReportPath = safeRelative(repoRoot, materializeResult.outputPath);
+ } catch (error) {
+ blockers.push(createBlocker('cost-rollup-materialization-failed', error?.message || String(error)));
+ }
+ }
+
+ let rollup = null;
+ if (!fs.existsSync(costRollupPath)) {
+ blockers.push(createBlocker('cost-rollup-missing', 'Agent cost rollup is missing.', safeRelative(repoRoot, costRollupPath)));
+ } else {
+ try {
+ rollup = readJsonFn(costRollupPath);
+ if (normalizeText(rollup?.schema) !== 'priority/agent-cost-rollup@v1') {
+ blockers.push(createBlocker('cost-rollup-schema-mismatch', 'Agent cost rollup schema must remain priority/agent-cost-rollup@v1.', safeRelative(repoRoot, costRollupPath)));
+ }
+ } catch (error) {
+ blockers.push(createBlocker('cost-rollup-unreadable', error?.message || String(error), safeRelative(repoRoot, costRollupPath)));
+ }
+ }
+
+ const billingWindow = summarizeBillingWindow(rollup);
+ const reservedFunding = summarizeReservedFundingWindows(rollup, policy, billingWindow?.invoiceTurnId ?? null);
+ const repository = chooseTargetRepository(options.repo, rollup);
+ const operatorBudgetCapUsd = toNonNegativeNumber(policy.operatorBudgetCapUsd);
+ const outputPath = path.resolve(repoRoot, options.outputPath || asOptional(policy.outputPath) || DEFAULT_OUTPUT_PATH);
+ const markdownOutputPath = path.resolve(repoRoot, options.markdownOutputPath || asOptional(policy.markdownOutputPath) || DEFAULT_MARKDOWN_OUTPUT_PATH);
+
+ const report = buildGitHubCommentBudgetHookReport({
+ rollup,
+ repository,
+ targetKind: options.targetKind,
+ targetNumber: options.targetNumber,
+ operatorBudgetCapUsd,
+ reservedFunding,
+ billingWindow,
+ source: {
+ policyPath: safeRelative(repoRoot, resolvedPolicyPath),
+ costRollupPath: safeRelative(repoRoot, costRollupPath),
+ costRollupMaterialized,
+ costRollupMaterializationReportPath,
+ operatorCostProfilePath: asOptional(rollup?.summary?.provenance?.operatorProfiles?.[0]?.operatorProfilePath) || 'tools/policy/operator-cost-profile.json',
+ outputPath: safeRelative(repoRoot, outputPath),
+ markdownOutputPath: safeRelative(repoRoot, markdownOutputPath)
+ },
+ blockers,
+ now
+ });
+
+ const markdown = buildMarkdown(report);
+ writeJsonFn(outputPath, report);
+ writeTextFn(markdownOutputPath, markdown);
+
+ return {
+ report,
+ markdown,
+ outputPath,
+ markdownOutputPath
+ };
+}
+
+function printUsage() {
+ [
+ 'Usage: node tools/priority/github-comment-budget-hook.mjs [options]',
+ '',
+ 'Builds a durable spend/budget hook for automation-authored GitHub comments.',
+ '',
+ ` --policy Policy path (default: ${DEFAULT_POLICY_PATH}).`,
+ ' --repo-root Repository root (default: cwd).',
+ ' --repo Repository slug override.',
+ ' --target-kind Comment target kind.',
+ ' --target-number Comment target number.',
+ ' --cost-rollup Cost rollup path override.',
+ ` --output JSON report path (default: ${DEFAULT_OUTPUT_PATH}).`,
+ ` --markdown-output Markdown hook path (default: ${DEFAULT_MARKDOWN_OUTPUT_PATH}).`,
+ ' --materialize Force cost-rollup materialization before read.',
+ ' --no-materialize Skip cost-rollup materialization.',
+ ' -h, --help Show this message.'
+ ].forEach((line) => console.log(line));
+}
+
+if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
+ try {
+ const options = parseArgs(process.argv);
+ if (options.help) {
+ printUsage();
+ process.exit(0);
+ }
+ const result = runGitHubCommentBudgetHook(options);
+ console.log(`[github-comment-budget-hook] wrote ${result.outputPath}`);
+ console.log(`[github-comment-budget-hook] markdown ${result.markdownOutputPath}`);
+ } catch (error) {
+ console.error(`[github-comment-budget-hook] ${error.message}`);
+ process.exit(1);
+ }
+}
diff --git a/tools/priority/lib/remote-utils.mjs b/tools/priority/lib/remote-utils.mjs
index 2c60340c6..6f398a939 100644
--- a/tools/priority/lib/remote-utils.mjs
+++ b/tools/priority/lib/remote-utils.mjs
@@ -174,7 +174,13 @@ export function buildGraphqlArgs(query, variables = {}) {
if (value == null) {
continue;
}
- args.push('-f', `${key}=${String(value)}`);
+ const flag =
+ typeof value === 'boolean' ||
+ typeof value === 'number' ||
+ typeof value === 'bigint'
+ ? '-F'
+ : '-f';
+ args.push(flag, `${key}=${String(value)}`);
}
return args;
}
diff --git a/tools/priority/pr-spend-projection.mjs b/tools/priority/pr-spend-projection.mjs
index 8438284bc..93c6cb6a2 100644
--- a/tools/priority/pr-spend-projection.mjs
+++ b/tools/priority/pr-spend-projection.mjs
@@ -6,6 +6,12 @@ import path from 'node:path';
import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import { runMaterializeAgentCostRollup } from './materialize-agent-cost-rollup.mjs';
+import {
+ COMMENT_HOOK_END_MARKER,
+ COMMENT_HOOK_START_MARKER,
+ appendBudgetHook,
+ runGitHubCommentBudgetHook
+} from './github-comment-budget-hook.mjs';
export const REPORT_SCHEMA = 'priority/pr-spend-projection@v1';
export const COST_ROLLUP_SCHEMA = 'priority/agent-cost-rollup@v1';
@@ -292,6 +298,16 @@ function buildMarkdown(report) {
return `${lines.join('\n').trimEnd()}\n`;
}
+function buildBudgetHookFallback(error) {
+ const message = normalizeText(error?.message ?? error);
+ return [
+ COMMENT_HOOK_START_MARKER,
+ `_Budget hook_: unavailable (\`comment-budget-hook-generation-failed\`): ${message || 'unknown error'}.`,
+ COMMENT_HOOK_END_MARKER,
+ ''
+ ].join('\n');
+}
+
function findExistingSpendComment(repo, prNumber, marker = COMMENT_MARKER) {
const result = spawnSync(
'gh',
@@ -726,7 +742,8 @@ export function runPrSpendProjection(
upsertCommentFn = upsertPullRequestComment,
lookupCurrentLoginFn = lookupCurrentLogin,
resolvePullRequestContextFn = resolvePullRequestContext,
- materializeAgentCostRollupFn = runMaterializeAgentCostRollup
+ materializeAgentCostRollupFn = runMaterializeAgentCostRollup,
+ runGitHubCommentBudgetHookFn = runGitHubCommentBudgetHook
} = {}
) {
const repo = resolveRepoSlugFn(options.repo);
@@ -783,7 +800,20 @@ export function runPrSpendProjection(
report.source.costRollupPath = safeRelative(resolvedCostRollupPath);
report.source.costRollupMaterialized = costRollupMaterialized;
report.source.costRollupMaterializationReportPath = materializationReportPath ? safeRelative(materializationReportPath) : null;
- const markdown = buildMarkdown(report);
+ let budgetHookMarkdown = '';
+ try {
+ budgetHookMarkdown = runGitHubCommentBudgetHookFn({
+ repoRoot: process.cwd(),
+ repo,
+ costRollupPath: resolvedCostRollupPath,
+ materialize: false,
+ targetKind: 'pr',
+ targetNumber: options.prNumber ?? prContext?.number ?? null
+ })?.markdown ?? '';
+ } catch (error) {
+ budgetHookMarkdown = buildBudgetHookFallback(error);
+ }
+ const markdown = appendBudgetHook(buildMarkdown(report), budgetHookMarkdown);
const markdownPath = writeTextFn(options.markdownOutputPath || DEFAULT_MARKDOWN_OUTPUT_PATH, markdown);
report.source.markdownPath = safeRelative(markdownPath);
diff --git a/tools/priority/release-conductor.mjs b/tools/priority/release-conductor.mjs
index 444f7f438..5dea1b441 100644
--- a/tools/priority/release-conductor.mjs
+++ b/tools/priority/release-conductor.mjs
@@ -13,6 +13,9 @@ export const DEFAULT_QUEUE_REPORT_PATH = path.join('tests', 'results', '_agent',
export const DEFAULT_POLICY_SNAPSHOT_PATH = path.join('tests', 'results', '_agent', 'policy', 'policy-state-snapshot.json');
export const DEFAULT_DWELL_MINUTES = 60;
export const DEFAULT_QUARANTINE_STALE_HOURS = 24;
+export const RELEASE_PUBLICATION_WORKFLOW = 'release.yml';
+export const RELEASE_PUBLICATION_WORKFLOW_REF = 'develop';
+export const RELEASE_PUBLICATION_TAG_INPUT = 'release_tag';
const REQUIRED_DWELL_WORKFLOWS = Object.freeze([
{ name: 'Validate', file: 'validate.yml' },
@@ -24,6 +27,7 @@ function printUsage() {
console.log('');
console.log('Options:');
console.log(' --apply Apply release mutation (default is --dry-run).');
+ console.log(' --repair-existing-tag Repair an existing authoritative tag by recreating it as a signed annotated tag.');
console.log(` --report Write report JSON (default: ${DEFAULT_REPORT_PATH}).`);
console.log(` --queue-report Queue supervisor report path (default: ${DEFAULT_QUEUE_REPORT_PATH}).`);
console.log(` --policy-snapshot Policy snapshot path (default: ${DEFAULT_POLICY_SNAPSHOT_PATH}).`);
@@ -96,6 +100,7 @@ export function parseArgs(argv = process.argv) {
const options = {
apply: false,
dryRun: true,
+ repairExistingTag: false,
reportPath: DEFAULT_REPORT_PATH,
queueReportPath: DEFAULT_QUEUE_REPORT_PATH,
policySnapshotPath: DEFAULT_POLICY_SNAPSHOT_PATH,
@@ -119,6 +124,10 @@ export function parseArgs(argv = process.argv) {
options.dryRun = false;
continue;
}
+ if (token === '--repair-existing-tag') {
+ options.repairExistingTag = true;
+ continue;
+ }
if (token === '--dry-run') {
options.apply = false;
options.dryRun = true;
@@ -297,11 +306,46 @@ export function evaluateQueueHealthGate(queueReportEnvelope) {
queueReport?.throughputController?.mode ??
queueReport?.adaptiveInflight?.mode ??
null;
+ const pausedReasons = Array.isArray(queueReport?.pausedReasons) ? queueReport.pausedReasons : [];
+ const runtimeTotals =
+ queueReport?.runtimeFleet && typeof queueReport.runtimeFleet === 'object' ? queueReport.runtimeFleet.totals : null;
+ const mergeQueueOccupancy =
+ queueReport?.queueInventory?.mergeQueueOccupancy ??
+ queueReport?.summary?.mergeQueueOccupancy ??
+ null;
+ const readyQueuedCount =
+ queueReport?.queueInventory?.readyQueuedCount ??
+ queueReport?.summary?.readyQueuedCount ??
+ null;
+ const quarantinedCount = queueReport?.summary?.quarantinedCount ?? null;
+ const idleSuccessRatePause =
+ paused &&
+ controllerMode === 'stabilize' &&
+ pausedReasons.length > 0 &&
+ pausedReasons.every((reason) => reason === 'success-rate-below-threshold') &&
+ Number(mergeQueueOccupancy ?? 0) === 0 &&
+ Number(readyQueuedCount ?? 0) === 0 &&
+ Number(runtimeTotals?.queued ?? 0) === 0 &&
+ Number(runtimeTotals?.inProgress ?? 0) === 0 &&
+ Number(runtimeTotals?.stalled ?? 0) === 0 &&
+ Number(quarantinedCount ?? 0) === 0;
const reasons = [];
+ if (idleSuccessRatePause) {
+ reasons.push('release-safe-idle-queue-pause');
+ }
if (paused) reasons.push('queue-paused');
if (controllerMode === 'stabilize') reasons.push('queue-stabilize-mode');
+ if (idleSuccessRatePause) {
+ return {
+ status: 'pass',
+ reasons: ['release-safe-idle-queue-pause'],
+ paused,
+ controllerMode
+ };
+ }
+
return {
status: reasons.length === 0 ? 'pass' : 'fail',
reasons,
@@ -350,6 +394,7 @@ export function evaluateQuarantineGate({
return {
status: 'fail',
reasons: ['queue-report-unavailable'],
+ staleHours,
staleCount: null,
activeCount: null,
staleEntries: []
@@ -443,17 +488,44 @@ function fetchWorkflowRunsByName({ runGhJsonFn, repository, branch, sampleSize,
};
}
-function detectSigningMaterial({ runCommandFn, repoRoot }) {
+function detectSigningMaterial({ runCommandFn, repoRoot, environment = process.env }) {
const keyResult = runCommandFn('git', ['config', '--get', 'user.signingkey'], {
cwd: repoRoot,
allowFailure: true
});
const signingKey = asOptional(keyResult.stdout);
+ const formatResult = runCommandFn('git', ['config', '--get', 'gpg.format'], {
+ cwd: repoRoot,
+ allowFailure: true
+ });
+ const nameResult = runCommandFn('git', ['config', '--get', 'user.name'], {
+ cwd: repoRoot,
+ allowFailure: true
+ });
+ const emailResult = runCommandFn('git', ['config', '--get', 'user.email'], {
+ cwd: repoRoot,
+ allowFailure: true
+ });
+ const configuredFormat = asOptional(formatResult.stdout);
+ const backend = asOptional(environment.RELEASE_TAG_SIGNING_BACKEND) ?? configuredFormat ?? 'openpgp';
+ const source = signingKey ? asOptional(environment.RELEASE_TAG_SIGNING_SOURCE) ?? 'git-config' : 'missing';
+ const identityName = asOptional(nameResult.stdout);
+ const identityEmail = asOptional(emailResult.stdout);
+ const identityAvailable = Boolean(identityName && identityEmail);
return {
available: Boolean(signingKey),
signingKey,
- source: signingKey ? 'git-config' : 'missing'
+ source,
+ backend,
+ identity: {
+ available: identityAvailable,
+ name: identityName,
+ email: identityEmail,
+ source: identityAvailable ? asOptional(environment.RELEASE_TAG_SIGNING_IDENTITY_SOURCE) ?? 'git-config' : 'missing',
+ login: asOptional(environment.RELEASE_TAG_SIGNING_IDENTITY_LOGIN),
+ accountId: asOptional(environment.RELEASE_TAG_SIGNING_IDENTITY_ID)
+ }
};
}
@@ -463,6 +535,119 @@ function resolveTargetTag(version) {
return normalized.startsWith('v') ? normalized : `v${normalized}`;
}
+function inspectLocalTag({ repoRoot, tagRef, runCommandFn }) {
+ if (!tagRef) {
+ return {
+ present: false,
+ objectOid: null
+ };
+ }
+
+ const result = runCommandFn('git', ['rev-parse', '--verify', '--quiet', `refs/tags/${tagRef}`], {
+ cwd: repoRoot,
+ allowFailure: true
+ });
+ return {
+ present: result.status === 0,
+ objectOid: asOptional(result.stdout)
+ };
+}
+
+function inspectRemoteTag({ repoRoot, remoteName, tagRef, runCommandFn }) {
+ if (!remoteName || !tagRef) {
+ return {
+ exists: false,
+ refName: tagRef ? `refs/tags/${tagRef}` : null,
+ objectOid: null,
+ targetCommitOid: null,
+ annotated: null,
+ lookupError: null
+ };
+ }
+
+ const refName = `refs/tags/${tagRef}`;
+ const result = runCommandFn('git', ['ls-remote', '--tags', remoteName, refName, `${refName}^{}`], {
+ cwd: repoRoot,
+ allowFailure: true
+ });
+ if (result.status !== 0) {
+ return {
+ exists: false,
+ refName,
+ objectOid: null,
+ targetCommitOid: null,
+ annotated: null,
+ lookupError: asOptional(result.stderr) ?? asOptional(result.stdout) ?? `git ls-remote failed (${result.status})`
+ };
+ }
+
+ let objectOid = null;
+ let peeledOid = null;
+ for (const rawLine of String(result.stdout ?? '').split(/\r?\n/)) {
+ const line = rawLine.trim();
+ if (!line) {
+ continue;
+ }
+ const [oid, resolvedRef] = line.split(/\s+/, 2);
+ if (resolvedRef === refName) {
+ objectOid = oid;
+ } else if (resolvedRef === `${refName}^{}`) {
+ peeledOid = oid;
+ }
+ }
+
+ const exists = Boolean(objectOid);
+ return {
+ exists,
+ refName,
+ objectOid,
+ targetCommitOid: peeledOid ?? objectOid,
+ annotated: exists ? Boolean(peeledOid) : null,
+ lookupError: null
+ };
+}
+
+function createRepairState({ requested, remoteTag = null, localTag = null }) {
+ return {
+ requested: Boolean(requested),
+ status: 'not-requested',
+ remoteTagRef: remoteTag?.refName ?? null,
+ remoteTagExists: Boolean(remoteTag?.exists),
+ remoteTagAnnotated: remoteTag?.annotated ?? null,
+ remoteTagObjectOid: remoteTag?.objectOid ?? null,
+ remoteTargetCommitOid: remoteTag?.targetCommitOid ?? null,
+ localTagPresent: Boolean(localTag?.present),
+ localTagDeleted: false,
+ tagRecreated: false,
+ pushLeaseExpectedOid: remoteTag?.objectOid ?? null,
+ lookupError: remoteTag?.lookupError ?? null
+ };
+}
+
+function resolveTagPushRemote({ repoRoot, repository, runCommandFn }) {
+ for (const remoteName of ['upstream', 'origin']) {
+ const remoteResult = runCommandFn('git', ['config', '--get', `remote.${remoteName}.url`], {
+ cwd: repoRoot,
+ allowFailure: true
+ });
+ const remoteUrl = asOptional(remoteResult.stdout);
+ const remoteSlug = parseRemoteUrl(remoteUrl);
+ if (remoteSlug && remoteSlug === repository) {
+ return {
+ remoteName,
+ remoteSlug,
+ source: 'matching-remote-url'
+ };
+ }
+ }
+
+ return {
+ remoteName: null,
+ remoteSlug: null,
+ source: 'missing'
+ };
+}
+
async function writeReport(filePath, payload) {
const resolved = path.resolve(filePath);
await mkdir(path.dirname(resolved), { recursive: true });
@@ -567,11 +752,90 @@ export async function runReleaseConductor(options = {}) {
});
}
- const signingMaterial = detectSigningMaterial({ runCommandFn, repoRoot });
+ const signingMaterial = detectSigningMaterial({ runCommandFn, repoRoot, environment });
const targetTag = resolveTargetTag(args.version);
let tagCreated = false;
+ let tagPushed = false;
let tagError = null;
+ let tagPushError = null;
let proposalOnly = true;
+ const publicationReplay = {
+ requested: Boolean(args.repairExistingTag && applyRequested),
+ workflow: RELEASE_PUBLICATION_WORKFLOW,
+ ref: RELEASE_PUBLICATION_WORKFLOW_REF,
+ tagInputName: RELEASE_PUBLICATION_TAG_INPUT,
+ tagInputValue: targetTag,
+ dispatched: false,
+ status: args.repairExistingTag && applyRequested ? 'blocked' : 'not-requested',
+ error: null
+ };
+ const tagPushRemote = resolveTagPushRemote({ repoRoot, repository, runCommandFn });
+ const remoteTag = inspectRemoteTag({
+ repoRoot,
+ remoteName: asOptional(tagPushRemote.remoteName),
+ tagRef: targetTag,
+ runCommandFn
+ });
+ const localTag = inspectLocalTag({
+ repoRoot,
+ tagRef: targetTag,
+ runCommandFn
+ });
+ const repair = createRepairState({
+ requested: args.repairExistingTag,
+ remoteTag,
+ localTag
+ });
+
+ if (repair.remoteTagExists && !repair.requested) {
+ repair.status = 'repair-available';
+ pushUniqueDecisionEntry(advisories, {
+ code: 'existing-tag-repair-available',
+ message: `Authoritative tag ${targetTag} already exists; rerun release conductor with --repair-existing-tag to recreate it as a signed annotated tag.`
+ });
+ }
+ if (repair.requested && !targetTag) {
+ repair.status = 'blocked';
+ } else if (repair.requested && remoteTag.lookupError) {
+ repair.status = 'blocked';
+ } else if (repair.requested && !asOptional(tagPushRemote.remoteName)) {
+ repair.status = 'blocked';
+ } else if (repair.requested && !repair.remoteTagExists) {
+ repair.status = 'blocked';
+ } else if (repair.requested && (!repair.remoteTargetCommitOid || !repair.pushLeaseExpectedOid)) {
+ repair.status = 'blocked';
+ } else if (repair.requested && repair.remoteTagExists) {
+ repair.status = applyRequested ? 'blocked' : 'ready';
+ }
+
+ if (repair.requested) {
+ if (!targetTag) {
+ blockers.push({
+ code: 'missing-version-for-tag',
+ message: 'Repair mode requires --version to identify the authoritative release tag.'
+ });
+ } else if (!asOptional(tagPushRemote.remoteName)) {
+ blockers.push({
+ code: 'tag-push-remote-missing',
+ message: `Repair mode could not resolve an authoritative push remote matching ${repository}.`
+ });
+ } else if (remoteTag.lookupError) {
+ blockers.push({
+ code: 'repair-remote-tag-lookup-failed',
+ message: `Unable to inspect authoritative tag ${targetTag}: ${remoteTag.lookupError}`
+ });
+ } else if (!repair.remoteTagExists) {
+ blockers.push({
+ code: 'repair-target-tag-missing',
+ message: `Repair mode requires existing authoritative tag ${targetTag}, but no authoritative tag ref was found on ${tagPushRemote.remoteName}.`
+ });
+ } else if (!repair.remoteTargetCommitOid || !repair.pushLeaseExpectedOid) {
+ blockers.push({
+ code: 'repair-target-unresolved',
+ message: `Repair mode could not resolve the authoritative object/commit for ${targetTag}.`
+ });
+ }
+ }
if (blockers.length === 0 && applyRequested && conductorEnabled) {
if (!targetTag) {
@@ -579,6 +843,112 @@ export async function runReleaseConductor(options = {}) {
code: 'missing-version-for-tag',
message: 'Apply mode requires --version to propose/create a release tag.'
});
+ } else if (!signingMaterial.available) {
+ blockers.push({
+ code: 'tag-signing-material-missing',
+ message: 'Apply mode requires signed-tag readiness before tag push. Configure user.signingkey (or equivalent signing material) and retry.'
+ });
+ } else if (args.repairExistingTag) {
+ if (repair.localTagPresent) {
+ const deleteResult = runCommandFn('git', ['tag', '-d', targetTag], {
+ cwd: repoRoot,
+ allowFailure: true
+ });
+ if (deleteResult.status !== 0) {
+ tagError = asOptional(deleteResult.stderr) ?? asOptional(deleteResult.stdout) ?? 'local tag delete failed';
+ blockers.push({
+ code: 'repair-local-tag-delete-failed',
+ message: `Unable to remove existing local tag ${targetTag} before repair: ${tagError}`
+ });
+ } else {
+ repair.localTagDeleted = true;
+ }
+ }
+
+ if (blockers.length === 0) {
+ const tagResult = runCommandFn(
+ 'git',
+ ['tag', '-s', '-f', targetTag, repair.remoteTargetCommitOid, '-m', `Release ${targetTag}`],
+ {
+ cwd: repoRoot,
+ allowFailure: true
+ }
+ );
+ if (tagResult.status === 0) {
+ tagCreated = true;
+ repair.tagRecreated = true;
+ const pushRemoteName = asOptional(tagPushRemote.remoteName);
+ if (!pushRemoteName) {
+ tagPushError = 'Unable to resolve an authoritative git remote for repair publication.';
+ blockers.push({
+ code: 'tag-push-remote-missing',
+ message: `Signed repair tag ${targetTag} was created locally but no authoritative push remote matched ${repository}.`
+ });
+ } else {
+ const leaseArg = `--force-with-lease=refs/tags/${targetTag}:${repair.pushLeaseExpectedOid}`;
+ const pushResult = runCommandFn(
+ 'git',
+ ['push', leaseArg, pushRemoteName, `refs/tags/${targetTag}:refs/tags/${targetTag}`],
+ {
+ cwd: repoRoot,
+ allowFailure: true
+ }
+ );
+ if (pushResult.status === 0) {
+ tagPushed = true;
+ proposalOnly = false;
+ repair.status = 'repaired';
+ const dispatchResult = runCommandFn(
+ 'gh',
+ [
+ 'workflow',
+ 'run',
+ RELEASE_PUBLICATION_WORKFLOW,
+ '--ref',
+ RELEASE_PUBLICATION_WORKFLOW_REF,
+ '-f',
+ `${RELEASE_PUBLICATION_TAG_INPUT}=${targetTag}`
+ ],
+ {
+ cwd: repoRoot,
+ allowFailure: true
+ }
+ );
+ if (dispatchResult.status === 0) {
+ publicationReplay.dispatched = true;
+ publicationReplay.status = 'dispatched';
+ } else {
+ publicationReplay.status = 'dispatch-failed';
+ publicationReplay.error =
+ asOptional(dispatchResult.stderr) ??
+ asOptional(dispatchResult.stdout) ??
+ 'release workflow dispatch failed';
+ blockers.push({
+ code: 'release-replay-dispatch-failed',
+ message: `Release publication replay dispatch failed for ${targetTag}: ${publicationReplay.error}`
+ });
+ }
+ } else {
+ tagPushError = asOptional(pushResult.stderr) ?? asOptional(pushResult.stdout) ?? 'repair tag push failed';
+ blockers.push({
+ code: 'repair-tag-push-failed',
+ message: `Signed repair publication failed for ${targetTag}: ${tagPushError}`
+ });
+ }
+ }
+ } else {
+ tagError = asOptional(tagResult.stderr) ?? asOptional(tagResult.stdout) ?? 'repair tag creation failed';
+ blockers.push({
+ code: 'repair-tag-recreate-failed',
+ message: `Signed repair tag creation failed for ${targetTag}: ${tagError}`
+ });
+ }
+ }
+ } else if (repair.remoteTagExists) {
+ blockers.push({
+ code: 'existing-tag-requires-repair-mode',
+ message: `Authoritative tag ${targetTag} already exists. Rerun release conductor with --repair-existing-tag to recreate it as a signed annotated tag at ${repair.remoteTargetCommitOid}.`
+ });
} else if (signingMaterial.available) {
const tagResult = runCommandFn('git', ['tag', '-s', targetTag, '-m', `Release ${targetTag}`], {
cwd: repoRoot,
@@ -586,7 +956,29 @@ export async function runReleaseConductor(options = {}) {
});
if (tagResult.status === 0) {
tagCreated = true;
- proposalOnly = false;
+ const pushRemoteName = asOptional(tagPushRemote.remoteName);
+ if (!pushRemoteName) {
+ tagPushError = 'Unable to resolve an authoritative git remote for tag publication.';
+ blockers.push({
+ code: 'tag-push-remote-missing',
+ message: `Signed tag ${targetTag} was created locally but no authoritative push remote matched ${repository}.`
+ });
+ } else {
+ const pushResult = runCommandFn('git', ['push', pushRemoteName, `refs/tags/${targetTag}`], {
+ cwd: repoRoot,
+ allowFailure: true
+ });
+ if (pushResult.status === 0) {
+ tagPushed = true;
+ proposalOnly = false;
+ } else {
+ tagPushError = asOptional(pushResult.stderr) ?? asOptional(pushResult.stdout) ?? 'tag push failed';
+ blockers.push({
+ code: 'tag-push-failed',
+ message: `Signed tag publication failed for ${targetTag}: ${tagPushError}`
+ });
+ }
+ }
} else {
tagError = asOptional(tagResult.stderr) ?? asOptional(tagResult.stdout) ?? 'tag creation failed';
blockers.push({
@@ -614,8 +1006,13 @@ export async function runReleaseConductor(options = {}) {
targetTag,
proposalOnly,
tagCreated,
+ tagPushed,
tagError,
- signingMaterial
+ tagPushError,
+ tagPushRemote,
+ signingMaterial,
+ repair,
+ publicationReplay
},
inputs: {
reportPath: args.reportPath,
diff --git a/tools/priority/release-published-bundle-observer.mjs b/tools/priority/release-published-bundle-observer.mjs
new file mode 100644
index 000000000..b0a63ca14
--- /dev/null
+++ b/tools/priority/release-published-bundle-observer.mjs
@@ -0,0 +1,501 @@
+#!/usr/bin/env node
+
+import fs from 'node:fs';
+import path from 'node:path';
+import process from 'node:process';
+import { spawnSync } from 'node:child_process';
+import { fileURLToPath } from 'node:url';
+
+export const REPORT_SCHEMA = 'priority/release-published-bundle-observer-report@v1';
+export const DEFAULT_OUTPUT_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'release',
+ 'release-published-bundle-observer.json'
+);
+export const DEFAULT_RESULTS_DIR = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'release',
+ 'published-bundle-observer'
+);
+export const COMPAREVI_TOOLS_ASSET_PATTERN = /^CompareVI\.Tools-v.+\.zip$/i;
+
+function asOptional(value) {
+ if (value == null) {
+ return null;
+ }
+ const normalized = String(value).trim();
+ return normalized.length > 0 ? normalized : null;
+}
+
+function parseRemoteUrl(url) {
+ if (!url) {
+ return null;
+ }
+ const ssh = String(url).match(/:(?[^/]+\/[^/]+?)(?:\.git)?$/);
+ const https = String(url).match(/github\.com\/(?[^/]+\/[^/]+?)(?:\.git)?$/);
+ const repoPath = ssh?.groups?.repoPath ?? https?.groups?.repoPath;
+ if (!repoPath) {
+ return null;
+ }
+ const [owner, repoRaw] = repoPath.split('/');
+ if (!owner || !repoRaw) {
+ return null;
+ }
+ const repo = repoRaw.endsWith('.git') ? repoRaw.slice(0, -4) : repoRaw;
+ return `${owner}/${repo}`;
+}
+
+function resolveRepositorySlug(repoRoot, explicitRepo, environment = process.env) {
+ const explicit = asOptional(explicitRepo);
+ if (explicit && explicit.includes('/')) {
+ return explicit;
+ }
+ const envRepo = asOptional(environment.GITHUB_REPOSITORY);
+ if (envRepo && envRepo.includes('/')) {
+ return envRepo;
+ }
+ for (const remoteName of ['upstream', 'origin']) {
+ const result = spawnSync('git', ['config', '--get', `remote.${remoteName}.url`], {
+ cwd: repoRoot,
+ encoding: 'utf8',
+ stdio: ['ignore', 'pipe', 'ignore']
+ });
+ if (result.status !== 0) {
+ continue;
+ }
+ const parsed = parseRemoteUrl(result.stdout.trim());
+ if (parsed) {
+ return parsed;
+ }
+ }
+ throw new Error('Unable to resolve repository slug. Set GITHUB_REPOSITORY or pass --repo.');
+}
+
+function writeJson(filePath, payload) {
+ const resolved = path.resolve(filePath);
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
+ fs.writeFileSync(resolved, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+ return resolved;
+}
+
+function runGhJson(args, { cwd } = {}) {
+ const result = spawnSync('gh', args, {
+ cwd,
+ encoding: 'utf8',
+ stdio: ['ignore', 'pipe', 'pipe']
+ });
+ if (result.status !== 0) {
+ const message = result.stderr?.trim() || result.stdout?.trim() || `gh ${args.join(' ')} failed (${result.status})`;
+ throw new Error(message);
+ }
+ const text = String(result.stdout ?? '').trim();
+ return text ? JSON.parse(text) : null;
+}
+
+function runGh(args, { cwd } = {}) {
+ const result = spawnSync('gh', args, {
+ cwd,
+ encoding: 'utf8',
+ stdio: ['ignore', 'pipe', 'pipe']
+ });
+ if (result.status !== 0) {
+ const message = result.stderr?.trim() || result.stdout?.trim() || `gh ${args.join(' ')} failed (${result.status})`;
+ throw new Error(message);
+ }
+ return result;
+}
+
+function expandArchive(archivePath, destinationPath) {
+ const archive = path.resolve(archivePath).replace(/'/g, "''");
+ const destination = path.resolve(destinationPath).replace(/'/g, "''");
+ const command = [
+ "$ErrorActionPreference='Stop'",
+ `if (Test-Path -LiteralPath '${destination}') { Remove-Item -LiteralPath '${destination}' -Recurse -Force }`,
+ `Expand-Archive -LiteralPath '${archive}' -DestinationPath '${destination}' -Force`
+ ].join('; ');
+ const result = spawnSync('pwsh', ['-NoLogo', '-NoProfile', '-Command', command], {
+ encoding: 'utf8',
+ stdio: ['ignore', 'pipe', 'pipe']
+ });
+ if (result.status !== 0) {
+ const message =
+ result.stderr?.trim() || result.stdout?.trim() || `Expand-Archive failed for ${path.basename(archivePath)} (${result.status})`;
+ throw new Error(message);
+ }
+ const directories = fs
+ .readdirSync(destinationPath, { withFileTypes: true })
+ .filter((entry) => entry.isDirectory())
+ .map((entry) => path.join(destinationPath, entry.name));
+ if (directories.length === 1) {
+ return directories[0];
+ }
+ return destinationPath;
+}
+
+function getObjectPathValue(inputObject, objectPath) {
+ const segments = String(objectPath ?? '')
+ .split('.')
+ .map((segment) => segment.trim())
+ .filter(Boolean);
+ let current = inputObject;
+ for (const segment of segments) {
+ if (current == null || typeof current !== 'object' || !(segment in current)) {
+ return null;
+ }
+ current = current[segment];
+ }
+ return current;
+}
+
+function findCompareVIToolsAsset(release) {
+ const assets = Array.isArray(release?.assets) ? release.assets : [];
+ return assets.find((asset) => COMPAREVI_TOOLS_ASSET_PATTERN.test(String(asset?.name ?? ''))) ?? null;
+}
+
+function selectRelease(releases, requestedTag = null) {
+ const normalizedReleases = Array.isArray(releases) ? releases : [];
+ if (requestedTag) {
+ const release = normalizedReleases.find((entry) => asOptional(entry?.tag_name) === requestedTag) ?? null;
+ return {
+ status: release ? (findCompareVIToolsAsset(release) ? 'selected' : 'asset-missing') : 'release-not-found',
+ release,
+ asset: release ? findCompareVIToolsAsset(release) : null
+ };
+ }
+
+ for (const release of normalizedReleases) {
+ const asset = findCompareVIToolsAsset(release);
+ if (asset) {
+ return {
+ status: 'selected',
+ release,
+ asset
+ };
+ }
+ }
+
+ return {
+ status: normalizedReleases.length > 0 ? 'asset-missing' : 'release-unobserved',
+ release: normalizedReleases[0] ?? null,
+ asset: null
+ };
+}
+
+function evaluateBundleContract(bundleRoot) {
+ const metadataPath = path.join(bundleRoot, 'comparevi-tools-release.json');
+ const result = {
+ status: 'metadata-missing',
+ metadataPath,
+ schema: null,
+ authoritativeConsumerPin: null,
+ authoritativeConsumerPinKind: null,
+ capabilityId: null,
+ distributionRole: null,
+ distributionModel: null,
+ bundleImportPath: null,
+ bundleImportPathExists: false,
+ releaseAssetPattern: null,
+ contractPathResolutions: [],
+ dockerCapabilityId: null,
+ dockerDistributionRole: null,
+ dockerDistributionModel: null,
+ authoritativeImageContractSource: null,
+ authoritativeImageContractSourceResolved: false,
+ dockerBundleImportPath: null,
+ dockerBundleImportPathExists: false,
+ dockerReleaseAssetPattern: null,
+ dockerImageContractSchema: null,
+ metadataPresent: false,
+ metadataSchemaMatches: false,
+ viHistoryCapabilityPresent: false,
+ viHistoryCapabilityProducerNative: false,
+ dockerProfileCapabilityPresent: false,
+ dockerProfileCapabilityProducerNative: false,
+ bundleContractPinResolved: false,
+ bundleContractPathsResolved: false
+ };
+
+ if (!fs.existsSync(metadataPath)) {
+ return result;
+ }
+
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
+ result.metadataPresent = true;
+ result.schema = asOptional(metadata?.schema);
+ result.metadataSchemaMatches = result.schema === 'comparevi-tools-release-manifest@v1';
+ result.authoritativeConsumerPin = asOptional(metadata?.versionContract?.authoritativeConsumerPin);
+ result.authoritativeConsumerPinKind = asOptional(metadata?.versionContract?.authoritativeConsumerPinKind);
+ result.bundleContractPinResolved = Boolean(result.authoritativeConsumerPin && result.authoritativeConsumerPinKind);
+
+ const capability = metadata?.consumerContract?.capabilities?.viHistory ?? null;
+ result.capabilityId = asOptional(capability?.capabilityId);
+ result.distributionRole = asOptional(capability?.distributionRole);
+ result.distributionModel = asOptional(capability?.distributionModel);
+ result.bundleImportPath = asOptional(capability?.bundleImportPath);
+ result.releaseAssetPattern = asOptional(capability?.releaseAssetPattern);
+ result.viHistoryCapabilityPresent =
+ asOptional(capability?.schema) === 'comparevi-tools/vi-history-capability@v1' && result.capabilityId === 'vi-history';
+ result.viHistoryCapabilityProducerNative =
+ result.distributionRole === 'upstream-producer' && result.distributionModel === 'release-bundle';
+
+ if (result.bundleImportPath) {
+ result.bundleImportPathExists = fs.existsSync(path.join(bundleRoot, result.bundleImportPath));
+ }
+
+ const contractPaths = capability && typeof capability.contractPaths === 'object' ? capability.contractPaths : {};
+ result.contractPathResolutions = Object.entries(contractPaths).map(([name, contractPath]) => ({
+ name,
+ path: String(contractPath),
+ resolved: getObjectPathValue(metadata, contractPath) != null
+ }));
+ result.bundleContractPathsResolved = result.contractPathResolutions.every((entry) => entry.resolved);
+
+ const dockerCapability = metadata?.consumerContract?.capabilities?.dockerProfile ?? null;
+ result.dockerCapabilityId = asOptional(dockerCapability?.capabilityId);
+ result.dockerDistributionRole = asOptional(dockerCapability?.distributionRole);
+ result.dockerDistributionModel = asOptional(dockerCapability?.distributionModel);
+ result.authoritativeImageContractSource = asOptional(dockerCapability?.authoritativeImageContractSource);
+ result.dockerBundleImportPath = asOptional(dockerCapability?.bundleImportPath);
+ result.dockerReleaseAssetPattern = asOptional(dockerCapability?.releaseAssetPattern);
+ result.dockerProfileCapabilityPresent =
+ asOptional(dockerCapability?.schema) === 'comparevi-tools/docker-profile-capability@v1' &&
+ result.dockerCapabilityId === 'docker-profile';
+ result.dockerProfileCapabilityProducerNative =
+ result.dockerDistributionRole === 'upstream-producer' && result.dockerDistributionModel === 'release-bundle';
+ result.authoritativeImageContractSourceResolved =
+ Boolean(result.authoritativeImageContractSource) &&
+ getObjectPathValue(metadata, result.authoritativeImageContractSource) != null;
+
+ if (result.dockerBundleImportPath) {
+ result.dockerBundleImportPathExists = fs.existsSync(path.join(bundleRoot, result.dockerBundleImportPath));
+ }
+
+ result.dockerImageContractSchema = asOptional(
+ getObjectPathValue(metadata, result.authoritativeImageContractSource ?? '')?.schema
+ );
+
+ result.status =
+ result.metadataSchemaMatches &&
+ result.viHistoryCapabilityPresent &&
+ result.viHistoryCapabilityProducerNative &&
+ result.bundleContractPinResolved &&
+ result.bundleImportPathExists &&
+ result.bundleContractPathsResolved
+ ? 'producer-native-ready'
+ : 'producer-native-incomplete';
+
+ return result;
+}
+
+function defaultDownloadAsset({ repoRoot, repository, releaseTag, assetName, destinationDirectory, runGhFn = runGh }) {
+ fs.mkdirSync(destinationDirectory, { recursive: true });
+ runGhFn(
+ ['release', 'download', releaseTag, '--repo', repository, '--pattern', assetName, '--dir', destinationDirectory, '--clobber'],
+ { cwd: repoRoot }
+ );
+ return path.join(destinationDirectory, assetName);
+}
+
+export function parseArgs(argv = process.argv) {
+ const args = argv.slice(2);
+ const options = {
+ repoRoot: process.cwd(),
+ repo: null,
+ tag: null,
+ outputPath: DEFAULT_OUTPUT_PATH,
+ resultsDir: DEFAULT_RESULTS_DIR,
+ help: false
+ };
+
+ for (let index = 0; index < args.length; index += 1) {
+ const token = args[index];
+ if (token === '-h' || token === '--help') {
+ options.help = true;
+ continue;
+ }
+ if (token === '--repo-root' || token === '--repo' || token === '--tag' || token === '--output' || token === '--results-dir') {
+ const next = args[index + 1];
+ if (!next || next.startsWith('-')) {
+ throw new Error(`Missing value for ${token}.`);
+ }
+ if (token === '--repo-root') options.repoRoot = next;
+ if (token === '--repo') options.repo = next;
+ if (token === '--tag') options.tag = next;
+ if (token === '--output') options.outputPath = next;
+ if (token === '--results-dir') options.resultsDir = next;
+ index += 1;
+ continue;
+ }
+ throw new Error(`Unknown option: ${token}`);
+ }
+
+ return options;
+}
+
+function printHelp() {
+ [
+ 'Usage: node tools/priority/release-published-bundle-observer.mjs [options]',
+ '',
+ 'Options:',
+ ' --repo-root Repository root override.',
+ ' --repo Repository slug override.',
+ ' --tag Observe a specific published release tag instead of the newest CompareVI.Tools asset release.',
+ ` --output Output JSON path (default: ${DEFAULT_OUTPUT_PATH}).`,
+ ` --results-dir Working directory for downloaded/extracted bundle files (default: ${DEFAULT_RESULTS_DIR}).`,
+ ' -h, --help Show help.'
+ ].forEach((line) => console.log(line));
+}
+
+export async function runReleasePublishedBundleObserver(options = {}, deps = {}) {
+ const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
+ const environment = deps.environment ?? process.env;
+ const repository = resolveRepositorySlug(repoRoot, options.repo, environment);
+ const outputPath = path.resolve(repoRoot, options.outputPath ?? DEFAULT_OUTPUT_PATH);
+ const resultsDir = path.resolve(repoRoot, options.resultsDir ?? DEFAULT_RESULTS_DIR);
+ const requestedTag = asOptional(options.tag);
+ const runGhJsonFn = deps.runGhJsonFn ?? runGhJson;
+ const downloadAssetFn = deps.downloadAssetFn ?? defaultDownloadAsset;
+ const extractArchiveFn = deps.extractArchiveFn ?? expandArchive;
+ const writeJsonFn = deps.writeJsonFn ?? writeJson;
+ const now = deps.now ?? new Date();
+
+ const releases = runGhJsonFn(['api', `repos/${repository}/releases?per_page=20`], { cwd: repoRoot });
+ const selection = selectRelease(releases, requestedTag);
+
+ const report = {
+ schema: REPORT_SCHEMA,
+ generatedAt: now.toISOString(),
+ repository,
+ inputs: {
+ requestedTag,
+ resultsDir: path.relative(repoRoot, resultsDir).replace(/\\/g, '/')
+ },
+ selection: {
+ status: selection.status,
+ releaseTag: asOptional(selection.release?.tag_name),
+ publishedAt: asOptional(selection.release?.published_at),
+ releaseName: asOptional(selection.release?.name),
+ releaseId: selection.release?.id ?? null,
+ prerelease: selection.release?.prerelease ?? null,
+ draft: selection.release?.draft ?? null,
+ assetName: asOptional(selection.asset?.name),
+ assetId: selection.asset?.id ?? null
+ },
+ bundle: {
+ status: 'not-downloaded',
+ archivePath: null,
+ extractionRoot: null,
+ downloadDirectory: path.relative(repoRoot, path.join(resultsDir, 'download')).replace(/\\/g, '/')
+ },
+ bundleContract: {
+ status: selection.status === 'release-unobserved' || selection.status === 'release-not-found' ? 'release-unobserved' : 'unobserved',
+ metadataPath: null,
+ schema: null,
+ authoritativeConsumerPin: null,
+ authoritativeConsumerPinKind: null,
+ capabilityId: null,
+ distributionRole: null,
+ distributionModel: null,
+ bundleImportPath: null,
+ bundleImportPathExists: false,
+ releaseAssetPattern: null,
+ contractPathResolutions: [],
+ metadataPresent: false,
+ metadataSchemaMatches: false,
+ viHistoryCapabilityPresent: false,
+ viHistoryCapabilityProducerNative: false,
+ bundleContractPinResolved: false,
+ bundleContractPathsResolved: false
+ },
+ summary: {
+ status: selection.status,
+ releaseTag: asOptional(selection.release?.tag_name),
+ assetName: asOptional(selection.asset?.name),
+ publishedAt: asOptional(selection.release?.published_at),
+ authoritativeConsumerPin: null
+ }
+ };
+
+ if (selection.status !== 'selected') {
+ const writtenPath = writeJsonFn(outputPath, report);
+ return {
+ report,
+ outputPath: writtenPath,
+ exitCode: 1
+ };
+ }
+
+ const downloadDirectory = path.join(resultsDir, 'download');
+ const extractDirectory = path.join(resultsDir, 'bundle');
+ try {
+ const archivePath = path.resolve(
+ downloadAssetFn({
+ repoRoot,
+ repository,
+ releaseTag: selection.release.tag_name,
+ assetName: selection.asset.name,
+ destinationDirectory: downloadDirectory,
+ runGhFn: deps.runGhFn ?? runGh
+ })
+ );
+ report.bundle.status = 'downloaded';
+ report.bundle.archivePath = path.relative(repoRoot, archivePath).replace(/\\/g, '/');
+
+ const extractionRoot = path.resolve(extractArchiveFn(archivePath, extractDirectory));
+ report.bundle.status = 'extracted';
+ report.bundle.extractionRoot = path.relative(repoRoot, extractionRoot).replace(/\\/g, '/');
+
+ const bundleContract = evaluateBundleContract(extractionRoot);
+ report.bundleContract = {
+ ...bundleContract,
+ metadataPath: path.relative(repoRoot, bundleContract.metadataPath).replace(/\\/g, '/')
+ };
+ report.summary.status = bundleContract.status;
+ report.summary.authoritativeConsumerPin = bundleContract.authoritativeConsumerPin;
+ } catch (error) {
+ const message = error?.message ?? String(error);
+ report.bundle.status = report.bundle.status === 'not-downloaded' ? 'download-failed' : 'extract-failed';
+ report.bundle.error = message;
+ report.bundleContract.status = report.bundle.status;
+ report.summary.status = report.bundle.status;
+ }
+
+ const writtenPath = writeJsonFn(outputPath, report);
+ return {
+ report,
+ outputPath: writtenPath,
+ exitCode: report.summary.status === 'producer-native-ready' ? 0 : 1
+ };
+}
+
+export async function main(argv = process.argv) {
+ const options = parseArgs(argv);
+ if (options.help) {
+ printHelp();
+ return 0;
+ }
+ const { report, outputPath, exitCode } = await runReleasePublishedBundleObserver(options);
+ console.log(
+ `[release-published-bundle-observer] wrote ${outputPath} status=${report.summary.status} tag=${report.summary.releaseTag ?? 'none'}`
+ );
+ return exitCode;
+}
+
+const isDirectExecution =
+ process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
+
+if (isDirectExecution) {
+ main().then(
+ (code) => {
+ process.exitCode = code;
+ },
+ (error) => {
+ console.error(`[release-published-bundle-observer] ${error.message}`);
+ process.exitCode = 1;
+ }
+ );
+}
diff --git a/tools/priority/release-signing-readiness.mjs b/tools/priority/release-signing-readiness.mjs
new file mode 100644
index 000000000..a4caeac28
--- /dev/null
+++ b/tools/priority/release-signing-readiness.mjs
@@ -0,0 +1,559 @@
+#!/usr/bin/env node
+
+import fs from 'node:fs';
+import path from 'node:path';
+import process from 'node:process';
+import { spawnSync } from 'node:child_process';
+import { fileURLToPath } from 'node:url';
+
+export const REPORT_SCHEMA = 'priority/release-signing-readiness-report@v1';
+export const DEFAULT_OUTPUT_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'release',
+ 'release-signing-readiness.json'
+);
+export const DEFAULT_RELEASE_CONDUCTOR_REPORT_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'release',
+ 'release-conductor-report.json'
+);
+export const DEFAULT_RELEASE_PUBLISHED_BUNDLE_OBSERVER_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'release',
+ 'release-published-bundle-observer.json'
+);
+export const REQUIRED_SIGNING_SECRET = 'RELEASE_TAG_SIGNING_PRIVATE_KEY';
+export const OPTIONAL_SIGNING_SECRET = 'RELEASE_TAG_SIGNING_PUBLIC_KEY';
+export const REQUIRED_SIGNING_SCOPE = 'admin:ssh_signing_key';
+export const RELEASE_CONDUCTOR_ENABLE_VARIABLE = 'RELEASE_CONDUCTOR_ENABLED';
+
+function asOptional(value) {
+ if (value == null) {
+ return null;
+ }
+ const normalized = String(value).trim();
+ return normalized.length > 0 ? normalized : null;
+}
+
+function parseRemoteUrl(url) {
+ if (!url) return null;
+ const ssh = String(url).match(/:(?[^/]+\/[^/]+?)(?:\.git)?$/);
+ const https = String(url).match(/github\.com\/(?[^/]+\/[^/]+?)(?:\.git)?$/);
+ const repoPath = ssh?.groups?.repoPath ?? https?.groups?.repoPath;
+ if (!repoPath) return null;
+ const [owner, repoRaw] = repoPath.split('/');
+ if (!owner || !repoRaw) return null;
+ const repo = repoRaw.endsWith('.git') ? repoRaw.slice(0, -4) : repoRaw;
+ return `${owner}/${repo}`;
+}
+
+function resolveRepositorySlug(repoRoot, explicitRepo, environment = process.env) {
+ const explicit = asOptional(explicitRepo);
+ if (explicit && explicit.includes('/')) {
+ return explicit;
+ }
+ const envRepo = asOptional(environment.GITHUB_REPOSITORY);
+ if (envRepo && envRepo.includes('/')) {
+ return envRepo;
+ }
+ for (const remoteName of ['upstream', 'origin']) {
+ const result = spawnSync('git', ['config', '--get', `remote.${remoteName}.url`], {
+ cwd: repoRoot,
+ encoding: 'utf8',
+ stdio: ['ignore', 'pipe', 'ignore']
+ });
+ if (result.status !== 0) {
+ continue;
+ }
+ const parsed = parseRemoteUrl(result.stdout.trim());
+ if (parsed) {
+ return parsed;
+ }
+ }
+ throw new Error('Unable to resolve repository slug. Set GITHUB_REPOSITORY or pass --repo.');
+}
+
+function readOptionalJson(filePath) {
+ const resolved = path.resolve(filePath);
+ if (!fs.existsSync(resolved)) {
+ return null;
+ }
+ return JSON.parse(fs.readFileSync(resolved, 'utf8'));
+}
+
+function writeJson(filePath, payload) {
+ const resolved = path.resolve(filePath);
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
+ fs.writeFileSync(resolved, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+ return resolved;
+}
+
+function runGhJson(args, { cwd } = {}) {
+ const result = spawnSync('gh', args, {
+ cwd,
+ encoding: 'utf8',
+ stdio: ['ignore', 'pipe', 'pipe']
+ });
+ if (result.status !== 0) {
+ const message = result.stderr?.trim() || result.stdout?.trim() || `gh ${args.join(' ')} failed (${result.status})`;
+ throw new Error(message);
+ }
+ const text = String(result.stdout ?? '').trim();
+ return text ? JSON.parse(text) : null;
+}
+
+export function parseArgs(argv = process.argv) {
+ const args = argv.slice(2);
+ const options = {
+ repoRoot: process.cwd(),
+ repo: null,
+ outputPath: DEFAULT_OUTPUT_PATH,
+ releaseConductorReportPath: DEFAULT_RELEASE_CONDUCTOR_REPORT_PATH,
+ releasePublishedBundleObserverPath: DEFAULT_RELEASE_PUBLISHED_BUNDLE_OBSERVER_PATH,
+ help: false
+ };
+
+ for (let index = 0; index < args.length; index += 1) {
+ const token = args[index];
+ if (token === '-h' || token === '--help') {
+ options.help = true;
+ continue;
+ }
+ if (
+ token === '--repo-root' ||
+ token === '--repo' ||
+ token === '--output' ||
+ token === '--release-conductor-report' ||
+ token === '--release-published-bundle-observer'
+ ) {
+ const next = args[index + 1];
+ if (!next || next.startsWith('-')) {
+ throw new Error(`Missing value for ${token}.`);
+ }
+ if (token === '--repo-root') options.repoRoot = next;
+ if (token === '--repo') options.repo = next;
+ if (token === '--output') options.outputPath = next;
+ if (token === '--release-conductor-report') options.releaseConductorReportPath = next;
+ if (token === '--release-published-bundle-observer') options.releasePublishedBundleObserverPath = next;
+ index += 1;
+ continue;
+ }
+ throw new Error(`Unknown option: ${token}`);
+ }
+
+ return options;
+}
+
+function printHelp() {
+ [
+ 'Usage: node tools/priority/release-signing-readiness.mjs [options]',
+ '',
+ 'Options:',
+ ' --repo-root Repository root override.',
+ ' --repo Repository slug override.',
+ ` --output Output JSON path (default: ${DEFAULT_OUTPUT_PATH}).`,
+ ` --release-conductor-report Release conductor report path (default: ${DEFAULT_RELEASE_CONDUCTOR_REPORT_PATH}).`,
+ ` --release-published-bundle-observer Published bundle observer path (default: ${DEFAULT_RELEASE_PUBLISHED_BUNDLE_OBSERVER_PATH}).`,
+ ' -h, --help Show help.'
+ ].forEach((line) => console.log(line));
+}
+
+function hasSigningWorkflowContract(repoRoot) {
+ const workflowPath = path.join(repoRoot, '.github', 'workflows', 'release-conductor.yml');
+ if (!fs.existsSync(workflowPath)) {
+ return {
+ ready: false,
+ workflowPath,
+ reasons: ['release-conductor-workflow-missing']
+ };
+ }
+ const workflow = fs.readFileSync(workflowPath, 'utf8');
+ const requiredSnippets = [
+ 'Configure release tag signing material',
+ 'RELEASE_TAG_SIGNING_PRIVATE_KEY',
+ 'RELEASE_TAG_SIGNING_IDENTITY_NAME',
+ 'RELEASE_TAG_SIGNING_IDENTITY_EMAIL',
+ "gh api user --jq '.login'",
+ 'git config gpg.format ssh',
+ 'git config user.signingkey "$public_key_path"',
+ 'git config user.name "$signing_name"',
+ 'git config user.email "$signing_email"'
+ ];
+ const missing = requiredSnippets.filter((snippet) => !workflow.includes(snippet));
+ return {
+ ready: missing.length === 0,
+ workflowPath,
+ reasons: missing.map((snippet) => `missing-workflow-snippet:${snippet}`)
+ };
+}
+
+function normalizeSecretInventory(payload) {
+ const secrets = Array.isArray(payload?.secrets) ? payload.secrets : [];
+ const names = new Set(secrets.map((entry) => String(entry?.name ?? '').trim()).filter(Boolean));
+ const requiredPresent = names.has(REQUIRED_SIGNING_SECRET);
+ const optionalPresent = names.has(OPTIONAL_SIGNING_SECRET);
+ return {
+ status: requiredPresent ? 'configured' : 'missing',
+ requiredSecretPresent: requiredPresent,
+ optionalPublicKeyPresent: optionalPresent,
+ listedSecretCount: secrets.length,
+ listedSecretNames: Array.from(names).sort()
+ };
+}
+
+function normalizeVariableInventory(payload) {
+ const variables = Array.isArray(payload?.variables) ? payload.variables : [];
+ const values = new Map(
+ variables
+ .map((entry) => [String(entry?.name ?? '').trim(), asOptional(entry?.value)])
+ .filter(([name]) => Boolean(name))
+ );
+ const configuredValue = values.get(RELEASE_CONDUCTOR_ENABLE_VARIABLE) ?? null;
+ const enabled = configuredValue === '1';
+ return {
+ status: enabled ? 'enabled' : 'disabled',
+ variablePresent: values.has(RELEASE_CONDUCTOR_ENABLE_VARIABLE),
+ enabled,
+ configuredValue,
+ listedVariableCount: variables.length,
+ listedVariableNames: Array.from(values.keys()).sort()
+ };
+}
+
+function normalizeSigningAuthority(payload) {
+ const keys = Array.isArray(payload) ? payload : Array.isArray(payload?.ssh_signing_keys) ? payload.ssh_signing_keys : [];
+ return {
+ status: keys.length > 0 ? 'ready' : 'keys-missing',
+ requiredScope: REQUIRED_SIGNING_SCOPE,
+ scopeAvailable: true,
+ listedKeyCount: keys.length
+ };
+}
+
+function hasMissingScopeError(message, scope) {
+ if (!message || !scope) {
+ return false;
+ }
+ return message.includes(scope) || message.includes(`"${scope}"`);
+}
+
+function derivePublicationState(conductorReport) {
+ const release = conductorReport?.release ?? null;
+ if (!release) {
+ return {
+ status: 'unobserved',
+ tagCreated: false,
+ tagPushed: false,
+ targetTag: null
+ };
+ }
+ const tagCreated = release.tagCreated === true;
+ const tagPushed = release.tagPushed === true;
+ return {
+ status: tagPushed ? 'authoritative-publication-successful' : tagCreated ? 'tag-created-not-pushed' : 'not-attempted',
+ tagCreated,
+ tagPushed,
+ targetTag: asOptional(release.targetTag)
+ };
+}
+
+function derivePublishedBundleObserverState(observerReport) {
+ if (!observerReport) {
+ return {
+ status: 'unobserved',
+ releaseTag: null,
+ assetName: null,
+ publishedAt: null,
+ authoritativeConsumerPin: null
+ };
+ }
+
+ return {
+ status: asOptional(observerReport?.summary?.status) || 'unobserved',
+ releaseTag: asOptional(observerReport?.summary?.releaseTag) || asOptional(observerReport?.selection?.releaseTag),
+ assetName: asOptional(observerReport?.summary?.assetName) || asOptional(observerReport?.selection?.assetName),
+ publishedAt: asOptional(observerReport?.summary?.publishedAt) || asOptional(observerReport?.selection?.publishedAt),
+ authoritativeConsumerPin: asOptional(observerReport?.summary?.authoritativeConsumerPin)
+ };
+}
+
+function createPublishedBundleBlocker(publishedBundleObserver) {
+ switch (publishedBundleObserver.status) {
+ case 'release-unobserved':
+ return {
+ code: 'published-bundle-release-unobserved',
+ message: 'No published CompareVI.Tools release could be observed yet for the producer-native vi-history distributor contract.'
+ };
+ case 'release-not-found':
+ return {
+ code: 'published-bundle-release-not-found',
+ message: 'The requested CompareVI.Tools release tag was not found on GitHub, so producer-native vi-history publication is still unavailable.'
+ };
+ case 'asset-missing':
+ return {
+ code: 'published-bundle-asset-missing',
+ message: 'The observed CompareVI.Tools release does not publish a CompareVI.Tools zip asset yet.'
+ };
+ case 'download-failed':
+ return {
+ code: 'published-bundle-download-failed',
+ message: 'The published CompareVI.Tools asset could not be downloaded for producer-native vi-history verification.'
+ };
+ case 'extract-failed':
+ return {
+ code: 'published-bundle-extract-failed',
+ message: 'The published CompareVI.Tools asset could not be extracted for producer-native vi-history verification.'
+ };
+ case 'metadata-missing':
+ return {
+ code: 'published-bundle-metadata-missing',
+ message: 'The published CompareVI.Tools asset is missing comparevi-tools-release.json, so the producer-native vi-history contract is not published yet.'
+ };
+ case 'producer-native-incomplete':
+ return {
+ code: 'published-bundle-producer-native-incomplete',
+ message: 'The published CompareVI.Tools asset exists, but it is still missing the producer-native vi-history consumer contract.'
+ };
+ default:
+ return null;
+ }
+}
+
+export async function runReleaseSigningReadiness(options = {}, deps = {}) {
+ const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
+ const environment = deps.environment ?? process.env;
+ const repository = resolveRepositorySlug(repoRoot, options.repo, environment);
+ const outputPath = path.resolve(repoRoot, options.outputPath ?? DEFAULT_OUTPUT_PATH);
+ const conductorReportPath = path.resolve(
+ repoRoot,
+ options.releaseConductorReportPath ?? DEFAULT_RELEASE_CONDUCTOR_REPORT_PATH
+ );
+ const publishedBundleObserverPath = path.resolve(
+ repoRoot,
+ options.releasePublishedBundleObserverPath ?? DEFAULT_RELEASE_PUBLISHED_BUNDLE_OBSERVER_PATH
+ );
+ const runGhJsonFn = deps.runGhJsonFn ?? runGhJson;
+ const readOptionalJsonFn = deps.readOptionalJsonFn ?? readOptionalJson;
+ const writeJsonFn = deps.writeJsonFn ?? writeJson;
+ const now = deps.now ?? new Date();
+
+ const workflowContract = hasSigningWorkflowContract(repoRoot);
+ const [owner, repo] = repository.split('/');
+ let secretInventory;
+ try {
+ const payload = runGhJsonFn(['api', `repos/${owner}/${repo}/actions/secrets?per_page=100`], { cwd: repoRoot });
+ secretInventory = {
+ ...normalizeSecretInventory(payload),
+ source: 'github-actions-secrets-api',
+ error: null
+ };
+ } catch (error) {
+ secretInventory = {
+ status: 'unverifiable',
+ requiredSecretPresent: null,
+ optionalPublicKeyPresent: null,
+ listedSecretCount: null,
+ listedSecretNames: [],
+ source: 'github-actions-secrets-api',
+ error: error?.message ?? String(error)
+ };
+ }
+
+ let releaseConductorApply;
+ try {
+ const payload = runGhJsonFn(['api', `repos/${owner}/${repo}/actions/variables?per_page=100`], { cwd: repoRoot });
+ releaseConductorApply = {
+ ...normalizeVariableInventory(payload),
+ source: 'github-actions-variables-api',
+ error: null
+ };
+ } catch (error) {
+ releaseConductorApply = {
+ status: 'unverifiable',
+ variablePresent: null,
+ enabled: null,
+ configuredValue: null,
+ listedVariableCount: null,
+ listedVariableNames: [],
+ source: 'github-actions-variables-api',
+ error: error?.message ?? String(error)
+ };
+ }
+
+ let signingAuthority;
+ try {
+ const payload = runGhJsonFn(['api', 'user/ssh_signing_keys?per_page=100'], { cwd: repoRoot });
+ signingAuthority = {
+ ...normalizeSigningAuthority(payload),
+ source: 'github-user-ssh-signing-keys-api',
+ error: null
+ };
+ } catch (error) {
+ const message = error?.message ?? String(error);
+ const scopeMissing = hasMissingScopeError(message, REQUIRED_SIGNING_SCOPE);
+ signingAuthority = {
+ status: scopeMissing ? 'scope-missing' : 'unverifiable',
+ requiredScope: REQUIRED_SIGNING_SCOPE,
+ scopeAvailable: scopeMissing ? false : null,
+ listedKeyCount: null,
+ source: 'github-user-ssh-signing-keys-api',
+ error: message
+ };
+ }
+
+ const conductorReport = readOptionalJsonFn(conductorReportPath);
+ const publishedBundleObserverReport = readOptionalJsonFn(publishedBundleObserverPath);
+ if (
+ publishedBundleObserverReport &&
+ publishedBundleObserverReport.schema !== 'priority/release-published-bundle-observer-report@v1'
+ ) {
+ throw new Error(
+ `Expected priority/release-published-bundle-observer-report@v1 at ${publishedBundleObserverPath}.`
+ );
+ }
+ const publication = derivePublicationState(conductorReport);
+ const publishedBundleObserver = derivePublishedBundleObserverState(publishedBundleObserverReport);
+ const blockers = [];
+
+ if (!workflowContract.ready) {
+ blockers.push({
+ code: 'workflow-signing-contract-missing',
+ message: 'Release conductor workflow does not yet expose the workflow-owned signing contract.'
+ });
+ }
+ if (secretInventory.status === 'missing') {
+ blockers.push({
+ code: 'workflow-signing-secret-missing',
+ message: `${REQUIRED_SIGNING_SECRET} is not configured for the repository Actions secrets surface.`
+ });
+ } else if (secretInventory.status === 'unverifiable') {
+ blockers.push({
+ code: 'workflow-signing-secret-unverifiable',
+ message: 'Unable to verify repository Actions secrets from the current automation identity.'
+ });
+ }
+ if (releaseConductorApply.status === 'disabled') {
+ blockers.push({
+ code: 'release-conductor-apply-disabled',
+ message: `${RELEASE_CONDUCTOR_ENABLE_VARIABLE} is not set to 1 for the repository Actions variable surface.`
+ });
+ } else if (releaseConductorApply.status === 'unverifiable') {
+ blockers.push({
+ code: 'release-conductor-apply-unverifiable',
+ message: 'Unable to verify release conductor apply gating from the current automation identity.'
+ });
+ }
+ if (signingAuthority.status === 'keys-missing') {
+ blockers.push({
+ code: 'workflow-signing-key-missing',
+ message: 'Authenticated identity can inspect SSH signing keys, but no SSH signing key is currently registered.'
+ });
+ } else if (signingAuthority.status === 'scope-missing') {
+ blockers.push({
+ code: 'workflow-signing-admin-scope-missing',
+ message: `${REQUIRED_SIGNING_SCOPE} is not available to the current automation identity, so SSH signing-key authority cannot be verified or managed.`
+ });
+ } else if (signingAuthority.status === 'unverifiable') {
+ blockers.push({
+ code: 'workflow-signing-authority-unverifiable',
+ message: 'Unable to verify SSH signing-key authority for the current automation identity.'
+ });
+ }
+
+ const publishedBundleBlocker = createPublishedBundleBlocker(publishedBundleObserver);
+ if (publishedBundleBlocker) {
+ blockers.push(publishedBundleBlocker);
+ }
+
+ const externalBlockerPriority = [
+ 'workflow-signing-secret-missing',
+ 'workflow-signing-secret-unverifiable',
+ 'workflow-signing-admin-scope-missing',
+ 'workflow-signing-key-missing',
+ 'workflow-signing-authority-unverifiable',
+ 'release-conductor-apply-disabled',
+ 'release-conductor-apply-unverifiable'
+ ];
+
+ const summary = {
+ status: blockers.length === 0 ? 'pass' : 'warn',
+ codePathState: workflowContract.ready ? 'ready' : 'missing-contract',
+ signingCapabilityState:
+ secretInventory.status === 'configured'
+ ? 'configured'
+ : secretInventory.status === 'missing'
+ ? 'missing'
+ : 'unverifiable',
+ signingAuthorityState: signingAuthority.status,
+ releaseConductorApplyState: releaseConductorApply.status,
+ publicationState: publication.status,
+ publishedBundleState: publishedBundleObserver.status,
+ publishedBundleReleaseTag: publishedBundleObserver.releaseTag,
+ publishedBundleAuthoritativeConsumerPin: publishedBundleObserver.authoritativeConsumerPin,
+ externalBlocker: externalBlockerPriority.find((code) => blockers.some((entry) => entry.code === code)) ?? null,
+ blockerCount: blockers.length
+ };
+
+ const report = {
+ schema: REPORT_SCHEMA,
+ generatedAt: now.toISOString(),
+ repository,
+ inputs: {
+ releaseConductorReportPath: path.relative(repoRoot, conductorReportPath).replace(/\\/g, '/'),
+ releasePublishedBundleObserverPath: path.relative(repoRoot, publishedBundleObserverPath).replace(/\\/g, '/')
+ },
+ workflowContract: {
+ ready: workflowContract.ready,
+ workflowPath: path.relative(repoRoot, workflowContract.workflowPath).replace(/\\/g, '/'),
+ reasons: workflowContract.reasons
+ },
+ secretInventory,
+ releaseConductorApply,
+ signingAuthority,
+ publication,
+ publishedBundleObserver,
+ summary,
+ blockers
+ };
+
+ const writtenPath = writeJsonFn(outputPath, report);
+ return {
+ report,
+ outputPath: writtenPath,
+ exitCode: summary.status === 'pass' ? 0 : 1
+ };
+}
+
+export async function main(argv = process.argv) {
+ const options = parseArgs(argv);
+ if (options.help) {
+ printHelp();
+ return 0;
+ }
+ const { report, outputPath, exitCode } = await runReleaseSigningReadiness(options);
+ console.log(
+ `[release-signing-readiness] wrote ${outputPath} status=${report.summary.status} externalBlocker=${report.summary.externalBlocker ?? 'none'}`
+ );
+ return exitCode;
+}
+
+const isDirectExecution =
+ process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
+
+if (isDirectExecution) {
+ main().then(
+ (code) => {
+ process.exitCode = code;
+ },
+ (error) => {
+ console.error(`[release-signing-readiness] ${error.message}`);
+ process.exitCode = 1;
+ }
+ );
+}
diff --git a/tools/priority/release-trust-remediation.mjs b/tools/priority/release-trust-remediation.mjs
new file mode 100644
index 000000000..8201afa52
--- /dev/null
+++ b/tools/priority/release-trust-remediation.mjs
@@ -0,0 +1,166 @@
+#!/usr/bin/env node
+
+import { appendFile, mkdir, readFile, writeFile } from 'node:fs/promises';
+import path from 'node:path';
+import process from 'node:process';
+import { fileURLToPath } from 'node:url';
+
+export const DEFAULT_TRUST_REPORT_PATH = path.join('tests', 'results', '_agent', 'supply-chain', 'release-trust-gate.json');
+export const DEFAULT_OUTPUT_PATH = path.join('tests', 'results', '_agent', 'release', 'release-trust-remediation.md');
+const REPAIR_FAILURE_CODES = new Set(['tag-not-annotated', 'tag-signature-unverified']);
+
+function normalizeOptional(value) {
+ if (value == null) return null;
+ const normalized = String(value).trim();
+ return normalized || null;
+}
+
+function normalizeVersionFromTag(tagRef) {
+ const normalized = normalizeOptional(tagRef);
+ if (!normalized) {
+ return null;
+ }
+ return normalized.startsWith('v') ? normalized.slice(1) : normalized;
+}
+
+export function parseArgs(argv = process.argv) {
+ const args = argv.slice(2);
+ const options = {
+ trustReportPath: DEFAULT_TRUST_REPORT_PATH,
+ outputPath: DEFAULT_OUTPUT_PATH,
+ summaryPath: null,
+ tagRef: null
+ };
+
+ for (let index = 0; index < args.length; index += 1) {
+ const token = args[index];
+ if (token === '--trust-report' || token === '--output' || token === '--summary' || token === '--tag-ref') {
+ const next = args[index + 1];
+ if (!next || next.startsWith('-')) {
+ throw new Error(`Missing value for ${token}.`);
+ }
+ index += 1;
+ if (token === '--trust-report') options.trustReportPath = next;
+ if (token === '--output') options.outputPath = next;
+ if (token === '--summary') options.summaryPath = next;
+ if (token === '--tag-ref') options.tagRef = next;
+ continue;
+ }
+ if (token === '--help' || token === '-h') {
+ return { ...options, help: true };
+ }
+ throw new Error(`Unknown option: ${token}`);
+ }
+
+ return options;
+}
+
+async function readJson(filePath) {
+ return JSON.parse(await readFile(path.resolve(filePath), 'utf8'));
+}
+
+async function writeText(filePath, contents) {
+ const resolved = path.resolve(filePath);
+ await mkdir(path.dirname(resolved), { recursive: true });
+ await writeFile(resolved, contents, 'utf8');
+ return resolved;
+}
+
+async function appendText(filePath, contents) {
+ const resolved = path.resolve(filePath);
+ await mkdir(path.dirname(resolved), { recursive: true });
+ await appendFile(resolved, contents, 'utf8');
+ return resolved;
+}
+
+export function buildReleaseTrustRemediationMarkdown({ trustReport, tagRef }) {
+ const failures = Array.isArray(trustReport?.failures)
+ ? trustReport.failures
+ : Array.isArray(trustReport?.summary?.failures)
+ ? trustReport.summary.failures
+ : [];
+ const relevantFailures = failures.filter((failure) => REPAIR_FAILURE_CODES.has(String(failure?.code ?? '').trim()));
+ const normalizedTag = normalizeOptional(tagRef) ?? normalizeOptional(trustReport?.tagSignature?.refName);
+ const normalizedVersion = normalizeVersionFromTag(normalizedTag);
+
+ const lines = ['## Release Trust Remediation', ''];
+ if (relevantFailures.length === 0) {
+ lines.push('- No repair-mode remediation is required for the current trust-gate result.');
+ lines.push('');
+ return lines.join('\n');
+ }
+
+ lines.push(`- Release trust gate reported repair-eligible tag failures for \`${normalizedTag ?? 'unknown-tag'}\`.`);
+ lines.push(`- Failure codes: ${relevantFailures.map((failure) => `\`${failure.code}\``).join(', ')}`);
+ lines.push('- Preserve tag identity and asset names. Do not rename the release tag to bypass trust verification.');
+ lines.push('- Rerun `.github/workflows/release-conductor.yml` with:');
+ lines.push(` - \`version = ${normalizedVersion ?? 'X.Y.Z'}\``);
+ lines.push(' - `apply = true`');
+ lines.push(' - `repair_existing_tag = true`');
+ lines.push('- Continue release publication only after `tests/results/_agent/release/release-conductor-report.json` shows:');
+ lines.push(' - `release.repair.status = repaired`');
+ lines.push(' - `release.tagPushed = true`');
+ lines.push('');
+ return lines.join('\n');
+}
+
+export async function runReleaseTrustRemediation(options = {}) {
+ const args = options.args ?? parseArgs();
+ if (args.help) {
+ return { markdown: '', outputPath: null, summaryPath: null, wroteSummary: false };
+ }
+
+ const trustReport = await readJson(args.trustReportPath);
+ const markdown = buildReleaseTrustRemediationMarkdown({
+ trustReport,
+ tagRef: args.tagRef
+ });
+ const outputPath = await writeText(args.outputPath, `${markdown}\n`);
+
+ let summaryPath = null;
+ let wroteSummary = false;
+ if (args.summaryPath) {
+ summaryPath = await appendText(args.summaryPath, `\n${markdown}\n`);
+ wroteSummary = true;
+ }
+
+ return {
+ markdown,
+ outputPath,
+ summaryPath,
+ wroteSummary
+ };
+}
+
+async function main(argv = process.argv) {
+ const args = parseArgs(argv);
+ if (args.help) {
+ console.log('Usage: node tools/priority/release-trust-remediation.mjs [options]');
+ console.log('');
+ console.log(` --trust-report Trust-gate report path (default: ${DEFAULT_TRUST_REPORT_PATH}).`);
+ console.log(` --output Markdown output path (default: ${DEFAULT_OUTPUT_PATH}).`);
+ console.log(' --summary Optional workflow step summary path to overwrite.');
+ console.log(' --tag-ref Optional release tag name override.');
+ return 0;
+ }
+
+ const result = await runReleaseTrustRemediation({ args });
+ console.log(`[release-trust-remediation] wrote ${result.outputPath}`);
+ if (result.wroteSummary) {
+ console.log(`[release-trust-remediation] summary ${result.summaryPath}`);
+ }
+ return 0;
+}
+
+if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url))) {
+ main(process.argv)
+ .then((exitCode) => {
+ if (exitCode !== 0) {
+ process.exitCode = exitCode;
+ }
+ })
+ .catch((error) => {
+ console.error(error instanceof Error ? error.message : String(error));
+ process.exitCode = 1;
+ });
+}
diff --git a/tools/priority/runtime-supervisor.mjs b/tools/priority/runtime-supervisor.mjs
index 5c90d5574..0294bb767 100644
--- a/tools/priority/runtime-supervisor.mjs
+++ b/tools/priority/runtime-supervisor.mjs
@@ -59,6 +59,7 @@ import {
} from './sync-standing-priority.mjs';
import {
buildWorkerProviderSelectionRequest,
+ buildExecutionTopologyRuntimeState,
buildLocalReviewLoopRequest,
buildCanonicalDeliveryDecision,
selectWorkerProviderAssignment,
@@ -416,6 +417,10 @@ async function resolveGovernorPortfolioHandoff({ repoRoot, repository, deps = {}
nextAction: null,
ownerDecisionSource: null,
governorMode: null,
+ viHistoryDistributorDependencyStatus: null,
+ viHistoryDistributorDependencyTargetRepository: null,
+ viHistoryDistributorDependencyExternalBlocker: null,
+ viHistoryDistributorDependencyPublicationState: null,
reason: `Unable to read governor portfolio summary: ${error?.message || String(error)}`
};
}
@@ -429,6 +434,10 @@ async function resolveGovernorPortfolioHandoff({ repoRoot, repository, deps = {}
nextAction: null,
ownerDecisionSource: null,
governorMode: null,
+ viHistoryDistributorDependencyStatus: null,
+ viHistoryDistributorDependencyTargetRepository: null,
+ viHistoryDistributorDependencyExternalBlocker: null,
+ viHistoryDistributorDependencyPublicationState: null,
reason: 'Governor portfolio summary is unavailable for queue-empty handoff.'
};
}
@@ -442,6 +451,10 @@ async function resolveGovernorPortfolioHandoff({ repoRoot, repository, deps = {}
nextAction: null,
ownerDecisionSource: null,
governorMode: null,
+ viHistoryDistributorDependencyStatus: null,
+ viHistoryDistributorDependencyTargetRepository: null,
+ viHistoryDistributorDependencyExternalBlocker: null,
+ viHistoryDistributorDependencyPublicationState: null,
reason: 'Governor portfolio summary does not match the expected schema.'
};
}
@@ -451,6 +464,14 @@ async function resolveGovernorPortfolioHandoff({ repoRoot, repository, deps = {}
const nextAction = normalizeText(payload?.summary?.nextAction) || null;
const ownerDecisionSource = normalizeText(payload?.summary?.ownerDecisionSource) || null;
const governorMode = normalizeText(payload?.summary?.governorMode) || null;
+ const viHistoryDistributorDependencyStatus =
+ normalizeText(payload?.summary?.viHistoryDistributorDependencyStatus) || null;
+ const viHistoryDistributorDependencyTargetRepository =
+ normalizeText(payload?.summary?.viHistoryDistributorDependencyTargetRepository) || null;
+ const viHistoryDistributorDependencyExternalBlocker =
+ normalizeText(payload?.summary?.viHistoryDistributorDependencyExternalBlocker) || null;
+ const viHistoryDistributorDependencyPublicationState =
+ normalizeText(payload?.summary?.viHistoryDistributorDependencyPublicationState) || null;
if (!currentOwnerRepository || !nextOwnerRepository || !nextAction || !ownerDecisionSource || !governorMode) {
return {
@@ -461,10 +482,34 @@ async function resolveGovernorPortfolioHandoff({ repoRoot, repository, deps = {}
nextAction,
ownerDecisionSource,
governorMode,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository,
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
reason: 'Governor portfolio summary is missing required owner handoff fields.'
};
}
+ let reason = null;
+ if (currentOwnerRepository === repository) {
+ if (viHistoryDistributorDependencyStatus === 'blocked' && viHistoryDistributorDependencyTargetRepository) {
+ reason =
+ `Governor portfolio keeps current ownership in ${currentOwnerRepository} while the vi-history distributor ` +
+ `dependency for ${viHistoryDistributorDependencyTargetRepository} remains blocked` +
+ (viHistoryDistributorDependencyExternalBlocker
+ ? ` (${viHistoryDistributorDependencyExternalBlocker}).`
+ : '.');
+ } else if (viHistoryDistributorDependencyStatus === 'unknown' && viHistoryDistributorDependencyTargetRepository) {
+ reason =
+ `Governor portfolio keeps current ownership in ${currentOwnerRepository} until the vi-history distributor ` +
+ `dependency for ${viHistoryDistributorDependencyTargetRepository} is refreshed.`;
+ } else {
+ reason = `Governor portfolio keeps current ownership in ${currentOwnerRepository}.`;
+ }
+ } else {
+ reason = `Governor portfolio assigns current ownership to ${currentOwnerRepository}.`;
+ }
+
return {
summaryPath,
status: currentOwnerRepository === repository ? 'owner-match' : 'external-owner',
@@ -473,10 +518,11 @@ async function resolveGovernorPortfolioHandoff({ repoRoot, repository, deps = {}
nextAction,
ownerDecisionSource,
governorMode,
- reason:
- currentOwnerRepository === repository
- ? `Governor portfolio keeps current ownership in ${currentOwnerRepository}.`
- : `Governor portfolio assigns current ownership to ${currentOwnerRepository}.`
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository,
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
+ reason
};
}
@@ -508,8 +554,29 @@ async function resolveGovernorPortfolioPivotExecution({
const nextAction = normalizeText(governorPortfolioHandoff?.nextAction) || null;
const ownerDecisionSource = normalizeText(governorPortfolioHandoff?.ownerDecisionSource) || null;
const governorMode = normalizeText(governorPortfolioHandoff?.governorMode) || null;
+ const viHistoryDistributorDependencyStatus =
+ normalizeText(governorPortfolioHandoff?.viHistoryDistributorDependencyStatus) || null;
+ const viHistoryDistributorDependencyTargetRepository =
+ normalizeText(governorPortfolioHandoff?.viHistoryDistributorDependencyTargetRepository) || null;
+ const viHistoryDistributorDependencyExternalBlocker =
+ normalizeText(governorPortfolioHandoff?.viHistoryDistributorDependencyExternalBlocker) || null;
+ const viHistoryDistributorDependencyPublicationState =
+ normalizeText(governorPortfolioHandoff?.viHistoryDistributorDependencyPublicationState) || null;
if (!nextOwnerRepository || nextOwnerRepository.toLowerCase() === currentRepository.toLowerCase()) {
+ let reason = `Governor portfolio keeps repo-context ownership in ${currentRepository}.`;
+ if (viHistoryDistributorDependencyStatus === 'blocked' && viHistoryDistributorDependencyTargetRepository) {
+ reason =
+ `Governor portfolio keeps repo-context ownership in ${currentRepository} while the vi-history distributor ` +
+ `dependency for ${viHistoryDistributorDependencyTargetRepository} remains blocked` +
+ (viHistoryDistributorDependencyExternalBlocker
+ ? ` (${viHistoryDistributorDependencyExternalBlocker}).`
+ : '.');
+ } else if (viHistoryDistributorDependencyStatus === 'unknown' && viHistoryDistributorDependencyTargetRepository) {
+ reason =
+ `Governor portfolio keeps repo-context ownership in ${currentRepository} until the vi-history distributor ` +
+ `dependency for ${viHistoryDistributorDependencyTargetRepository} is refreshed.`;
+ }
return {
status: 'same-repository',
registryPath: null,
@@ -519,12 +586,16 @@ async function resolveGovernorPortfolioPivotExecution({
nextAction,
ownerDecisionSource,
governorMode,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository,
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
targetEntrypointPath: null,
targetHeadSha: null,
targetCheckoutState: null,
targetReceipts: null,
targetCurrentState: null,
- reason: `Governor portfolio keeps repo-context ownership in ${currentRepository}.`
+ reason
};
}
@@ -538,6 +609,10 @@ async function resolveGovernorPortfolioPivotExecution({
nextAction,
ownerDecisionSource,
governorMode,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository,
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
targetEntrypointPath: null,
targetHeadSha: null,
targetCheckoutState: null,
@@ -573,6 +648,10 @@ async function resolveGovernorPortfolioPivotExecution({
nextAction,
ownerDecisionSource,
governorMode,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository,
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
targetEntrypointPath: null,
targetHeadSha: null,
targetCheckoutState: null,
@@ -592,6 +671,10 @@ async function resolveGovernorPortfolioPivotExecution({
nextAction,
ownerDecisionSource,
governorMode,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository,
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
targetEntrypointPath: null,
targetHeadSha: null,
targetCheckoutState: null,
@@ -611,6 +694,10 @@ async function resolveGovernorPortfolioPivotExecution({
nextAction,
ownerDecisionSource,
governorMode,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository,
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
targetEntrypointPath: null,
targetHeadSha: null,
targetCheckoutState: null,
@@ -649,6 +736,10 @@ async function resolveGovernorPortfolioPivotExecution({
nextAction,
ownerDecisionSource,
governorMode,
+ viHistoryDistributorDependencyStatus,
+ viHistoryDistributorDependencyTargetRepository,
+ viHistoryDistributorDependencyExternalBlocker,
+ viHistoryDistributorDependencyPublicationState,
targetEntrypointPath: normalizeText(entrypoint.path) || null,
targetHeadSha: normalizeText(entrypoint.headSha) || null,
targetCheckoutState: normalizeText(entrypoint.checkoutState) || null,
@@ -733,6 +824,7 @@ function projectConcurrentLaneStatusReceipt(receiptPath, receipt) {
const hostedRun = receipt.hostedRun && typeof receipt.hostedRun === 'object' ? receipt.hostedRun : {};
const pullRequest = receipt.pullRequest && typeof receipt.pullRequest === 'object' ? receipt.pullRequest : {};
const mergeQueue = pullRequest.mergeQueue && typeof pullRequest.mergeQueue === 'object' ? pullRequest.mergeQueue : {};
+ const executionBundle = receipt.executionBundle && typeof receipt.executionBundle === 'object' ? receipt.executionBundle : {};
return {
receiptPath,
@@ -755,6 +847,28 @@ function projectConcurrentLaneStatusReceipt(receiptPath, receipt) {
enqueuedAt: normalizeText(mergeQueue.enqueuedAt) || null
}
},
+ executionBundle: {
+ path: normalizeText(executionBundle.path) || null,
+ schema: normalizeText(executionBundle.schema) || null,
+ status: normalizeText(executionBundle.status) || null,
+ cellId: normalizeText(executionBundle.cellId) || null,
+ laneId: normalizeText(executionBundle.laneId) || null,
+ cellClass: normalizeText(executionBundle.cellClass) || null,
+ suiteClass: normalizeText(executionBundle.suiteClass) || null,
+ executionCellLeaseId: normalizeText(executionBundle.executionCellLeaseId) || null,
+ dockerLaneLeaseId: normalizeText(executionBundle.dockerLaneLeaseId) || null,
+ harnessKind: normalizeText(executionBundle.harnessKind) || null,
+ harnessInstanceId: normalizeText(executionBundle.harnessInstanceId) || null,
+ planeBinding: normalizeText(executionBundle.planeBinding) || null,
+ premiumSaganMode: executionBundle.premiumSaganMode === true,
+ reciprocalLinkReady: executionBundle.reciprocalLinkReady === true,
+ effectiveBillableRateUsdPerHour: Number.isFinite(executionBundle.effectiveBillableRateUsdPerHour)
+ ? executionBundle.effectiveBillableRateUsdPerHour
+ : null,
+ operatorAuthorizationRef: normalizeText(executionBundle.operatorAuthorizationRef) || null,
+ isolatedLaneGroupId: normalizeText(executionBundle.isolatedLaneGroupId) || null,
+ fingerprintSha256: normalizeText(executionBundle.fingerprintSha256) || null
+ },
summary: {
laneCount: coercePositiveInteger(summary.laneCount) ?? 0,
activeLaneCount: coercePositiveInteger(summary.activeLaneCount) ?? 0,
@@ -763,6 +877,9 @@ function projectConcurrentLaneStatusReceipt(receiptPath, receipt) {
deferredLaneCount: coercePositiveInteger(summary.deferredLaneCount) ?? 0,
manualLaneCount: coercePositiveInteger(summary.manualLaneCount) ?? 0,
shadowLaneCount: coercePositiveInteger(summary.shadowLaneCount) ?? 0,
+ executionBundleStatus: normalizeText(summary.executionBundleStatus) || null,
+ executionBundleReciprocalLinkReady: summary.executionBundleReciprocalLinkReady === true,
+ executionBundlePremiumSaganMode: summary.executionBundlePremiumSaganMode === true,
pullRequestStatus: normalizeText(summary.pullRequestStatus) || null,
orchestratorDisposition: normalizeText(summary.orchestratorDisposition) || null
}
@@ -1074,7 +1191,16 @@ async function planCompareviRuntimeStepFromLiveStanding({ repoRoot, targetReposi
let reason = classification.message;
if (governorPortfolioHandoff.status === 'owner-match') {
- if (
+ if (normalizeText(governorPortfolioHandoff.viHistoryDistributorDependencyStatus) === 'blocked') {
+ const dependencyTarget =
+ normalizeText(governorPortfolioHandoff.viHistoryDistributorDependencyTargetRepository) ||
+ 'the canonical template';
+ const dependencyBlocker = normalizeText(governorPortfolioHandoff.viHistoryDistributorDependencyExternalBlocker);
+ reason =
+ `standing queue is empty; governor portfolio keeps ownership in ${governorPortfolioHandoff.currentOwnerRepository} ` +
+ `while the vi-history distributor dependency for ${dependencyTarget} remains blocked` +
+ (dependencyBlocker ? ` (${dependencyBlocker}).` : '.');
+ } else if (
normalizeText(governorPortfolioHandoff.nextOwnerRepository) &&
normalizeText(governorPortfolioHandoff.nextOwnerRepository).toLowerCase() !== targetRepository.toLowerCase() &&
['future-agent-may-pivot', 'reopen-template-monitoring-work'].includes(
@@ -1296,6 +1422,15 @@ async function buildCompareviTaskPacket({ repoRoot, schedulerDecision, preparedW
deps,
selectedProviderId: workerProviderSelection.selectedProviderId
});
+ const executionTopology = buildExecutionTopologyRuntimeState({
+ providerSelection: workerProviderSelection,
+ workerSlotId:
+ normalizeText(workerBranch?.slotId) ||
+ normalizeText(workerReady?.slotId) ||
+ normalizeText(preparedWorker?.slotId) ||
+ null,
+ concurrentLaneStatus
+ });
return {
source: 'comparevi-runtime',
@@ -1386,6 +1521,7 @@ async function buildCompareviTaskPacket({ repoRoot, schedulerDecision, preparedW
backlog: artifacts.backlogRepair ?? null,
concurrentLaneApply,
concurrentLaneStatus,
+ executionTopology,
planeTransition,
localReviewLoop,
liveAgentModelSelection,
diff --git a/tools/priority/sagan-context-concentrator.mjs b/tools/priority/sagan-context-concentrator.mjs
new file mode 100644
index 000000000..99ff5781e
--- /dev/null
+++ b/tools/priority/sagan-context-concentrator.mjs
@@ -0,0 +1,747 @@
+#!/usr/bin/env node
+
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
+const DEFAULT_REPO_ROOT = path.resolve(MODULE_DIR, '..', '..');
+
+export const REPORT_SCHEMA = 'priority/sagan-context-concentrator-report@v1';
+export const SUBAGENT_EPISODE_SCHEMA = 'priority/subagent-episode-report@v1';
+export const DEFAULT_PRIORITY_CACHE_PATH = '.agent_priority_cache.json';
+export const DEFAULT_GOVERNOR_SUMMARY_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'handoff',
+ 'autonomous-governor-summary.json'
+);
+export const DEFAULT_GOVERNOR_PORTFOLIO_SUMMARY_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'handoff',
+ 'autonomous-governor-portfolio-summary.json'
+);
+export const DEFAULT_MONITORING_MODE_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'handoff',
+ 'monitoring-mode.json'
+);
+export const DEFAULT_OPERATOR_STEERING_EVENT_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'handoff',
+ 'operator-steering-event.json'
+);
+export const DEFAULT_EPISODE_DIR = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'memory',
+ 'subagent-episodes'
+);
+export const DEFAULT_OUTPUT_PATH = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'handoff',
+ 'sagan-context-concentrator.json'
+);
+
+function normalizeText(value) {
+ if (value == null) {
+ return null;
+ }
+ const normalized = String(value).trim();
+ return normalized.length > 0 ? normalized : null;
+}
+
+function normalizeFiniteNumber(value) {
+ if (value == null || value === '') {
+ return null;
+ }
+ const parsed = Number(value);
+ return Number.isFinite(parsed) ? parsed : null;
+}
+
+function normalizeInteger(value) {
+ if (value == null || value === '') {
+ return null;
+ }
+ const parsed = Number(value);
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
+}
+
+function toPortablePath(filePath) {
+ return String(filePath).replace(/\\/g, '/');
+}
+
+function toRelative(repoRoot, targetPath) {
+ return path.relative(repoRoot, path.resolve(targetPath)).replace(/\\/g, '/');
+}
+
+function toDisplayPath(repoRoot, targetPath) {
+ if (!targetPath) {
+ return null;
+ }
+ const relative = path.relative(path.resolve(repoRoot), path.resolve(targetPath));
+ if (!relative.startsWith('..') && !path.isAbsolute(relative)) {
+ return toPortablePath(relative);
+ }
+ return toPortablePath(path.resolve(targetPath));
+}
+
+function writeJson(filePath, payload) {
+ const resolvedPath = path.resolve(filePath);
+ fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
+ fs.writeFileSync(resolvedPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+ return resolvedPath;
+}
+
+function readOptionalJson(filePath) {
+ const resolvedPath = path.resolve(filePath);
+ if (!fs.existsSync(resolvedPath)) {
+ return null;
+ }
+ return JSON.parse(fs.readFileSync(resolvedPath, 'utf8'));
+}
+
+function ensureSchema(payload, filePath, schema) {
+ if (payload?.schema !== schema) {
+ throw new Error(`Expected ${schema} at ${filePath}.`);
+ }
+ return payload;
+}
+
+function isEpisodeActive(episode) {
+ const status = normalizeText(episode?.summary?.status)?.toLowerCase();
+ return !['completed', 'pass', 'success', 'closed', 'retired'].includes(status || '');
+}
+
+function buildEpisodeDigest(episode, repoRoot, filePath) {
+ return {
+ episodeId: normalizeText(episode?.episodeId),
+ generatedAt: normalizeText(episode?.generatedAt),
+ agentId: normalizeText(episode?.agent?.id),
+ agentName: normalizeText(episode?.agent?.name),
+ agentRole: normalizeText(episode?.agent?.role),
+ status: normalizeText(episode?.summary?.status),
+ taskSummary: normalizeText(episode?.task?.summary),
+ nextAction: normalizeText(episode?.summary?.nextAction),
+ blocker: normalizeText(episode?.summary?.blocker),
+ executionPlane: normalizeText(episode?.execution?.executionPlane),
+ dockerLaneId: normalizeText(episode?.execution?.dockerLaneId),
+ sourcePath: toDisplayPath(repoRoot, filePath)
+ };
+}
+
+function makeMemoryItem({
+ id,
+ kind,
+ label,
+ status,
+ detail = null,
+ sourcePath = null,
+ updatedAt = null,
+ issueNumber = null,
+ repository = null,
+ agentName = null,
+ nextAction = null
+}) {
+ return {
+ id: normalizeText(id),
+ kind: normalizeText(kind),
+ label: normalizeText(label),
+ status: normalizeText(status),
+ detail: normalizeText(detail),
+ sourcePath: normalizeText(sourcePath),
+ updatedAt: normalizeText(updatedAt),
+ issueNumber: normalizeInteger(issueNumber),
+ repository: normalizeText(repository),
+ agentName: normalizeText(agentName),
+ nextAction: normalizeText(nextAction)
+ };
+}
+
+function addUniqueMemoryItem(collection, item, seenIds) {
+ if (!item?.id || seenIds.has(item.id)) {
+ return false;
+ }
+ collection.push(item);
+ seenIds.add(item.id);
+ return true;
+}
+
+function sortEpisodesDescending(entries) {
+ return [...entries].sort((left, right) => {
+ const leftTime = Date.parse(left.episode.generatedAt || 0);
+ const rightTime = Date.parse(right.episode.generatedAt || 0);
+ return rightTime - leftTime;
+ });
+}
+
+function listEpisodeFiles(directoryPath) {
+ if (!fs.existsSync(directoryPath) || !fs.statSync(directoryPath).isDirectory()) {
+ return [];
+ }
+ return fs
+ .readdirSync(directoryPath, { withFileTypes: true })
+ .filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.json'))
+ .map((entry) => path.join(directoryPath, entry.name))
+ .sort();
+}
+
+function readEpisodes(repoRoot, episodeDirPath, readJsonFn = readOptionalJson) {
+ const episodeFiles = listEpisodeFiles(episodeDirPath);
+ const validEpisodes = [];
+ const invalidEpisodes = [];
+
+ for (const episodePath of episodeFiles) {
+ try {
+ const payload = readJsonFn(episodePath);
+ ensureSchema(payload, episodePath, SUBAGENT_EPISODE_SCHEMA);
+ validEpisodes.push({ path: episodePath, episode: payload });
+ } catch (error) {
+ invalidEpisodes.push({
+ path: toDisplayPath(repoRoot, episodePath),
+ error: error.message
+ });
+ }
+ }
+
+ return {
+ files: episodeFiles,
+ validEpisodes,
+ invalidEpisodes
+ };
+}
+
+function countByStatus(entries) {
+ const counts = new Map();
+ for (const entry of entries) {
+ const status = normalizeText(entry.episode?.summary?.status) || 'unknown';
+ counts.set(status, (counts.get(status) || 0) + 1);
+ }
+ return [...counts.entries()]
+ .map(([status, count]) => ({ status, count }))
+ .sort((left, right) => left.status.localeCompare(right.status));
+}
+
+function countByAgent(entries) {
+ const counts = new Map();
+ for (const entry of entries) {
+ const agentId = normalizeText(entry.episode?.agent?.id) || 'unknown';
+ const agentName = normalizeText(entry.episode?.agent?.name);
+ const key = `${agentId}::${agentName || ''}`;
+ const current = counts.get(key) || {
+ agentId,
+ agentName,
+ count: 0
+ };
+ current.count += 1;
+ counts.set(key, current);
+ }
+ return [...counts.values()].sort((left, right) => {
+ if (right.count !== left.count) {
+ return right.count - left.count;
+ }
+ return (left.agentName || left.agentId).localeCompare(right.agentName || right.agentId);
+ });
+}
+
+function sumEpisodeCost(entries, fieldName) {
+ return entries.reduce((sum, entry) => {
+ const value = normalizeFiniteNumber(entry.episode?.cost?.[fieldName]);
+ return sum + (value ?? 0);
+ }, 0);
+}
+
+function deriveOwnerSummary(governorSummary, governorPortfolioSummary, monitoringMode) {
+ return {
+ currentOwnerRepository:
+ normalizeText(governorPortfolioSummary?.summary?.currentOwnerRepository) ||
+ normalizeText(governorSummary?.summary?.currentOwnerRepository) ||
+ normalizeText(monitoringMode?.policy?.compareRepository),
+ nextOwnerRepository:
+ normalizeText(governorPortfolioSummary?.summary?.nextOwnerRepository) ||
+ normalizeText(governorSummary?.summary?.nextOwnerRepository),
+ nextAction:
+ normalizeText(governorPortfolioSummary?.summary?.nextAction) ||
+ normalizeText(governorSummary?.summary?.nextAction),
+ governorMode:
+ normalizeText(governorSummary?.summary?.governorMode) ||
+ normalizeText(governorPortfolioSummary?.summary?.governorMode),
+ monitoringStatus:
+ normalizeText(governorSummary?.summary?.monitoringStatus) ||
+ normalizeText(monitoringMode?.summary?.status)
+ };
+}
+
+function deriveFocus(priorityCache, ownerSummary) {
+ const number = normalizeInteger(priorityCache?.number);
+ return {
+ activeIssue: number
+ ? {
+ number,
+ title: normalizeText(priorityCache?.title),
+ url: normalizeText(priorityCache?.url),
+ state: normalizeText(priorityCache?.state),
+ repository: normalizeText(priorityCache?.repository)
+ }
+ : null,
+ currentOwnerRepository: ownerSummary.currentOwnerRepository,
+ nextOwnerRepository: ownerSummary.nextOwnerRepository,
+ nextAction: ownerSummary.nextAction,
+ governorMode: ownerSummary.governorMode,
+ monitoringStatus: ownerSummary.monitoringStatus
+ };
+}
+
+function deriveSystemMemoryItems({
+ repoRoot,
+ priorityCachePath,
+ governorSummaryPath,
+ governorSummary,
+ governorPortfolioSummaryPath,
+ governorPortfolioSummary,
+ focus
+}) {
+ const items = [];
+ const seenIds = new Set();
+
+ if (focus.activeIssue) {
+ addUniqueMemoryItem(
+ items,
+ makeMemoryItem({
+ id: `issue-${focus.activeIssue.number}`,
+ kind: 'active-issue',
+ label: `#${focus.activeIssue.number}: ${focus.activeIssue.title || 'standing priority'}`,
+ status: focus.activeIssue.state || 'open',
+ detail: 'Current standing-priority objective',
+ sourcePath: toDisplayPath(repoRoot, priorityCachePath),
+ updatedAt: normalizeText(priorityCachePath ? focus.activeIssue?.updatedAt : null),
+ issueNumber: focus.activeIssue.number,
+ repository: focus.activeIssue.repository,
+ nextAction: focus.nextAction
+ }),
+ seenIds
+ );
+ }
+
+ addUniqueMemoryItem(
+ items,
+ makeMemoryItem({
+ id: 'governor-owner-decision',
+ kind: 'owner-decision',
+ label: focus.currentOwnerRepository
+ ? `Owner: ${focus.currentOwnerRepository}`
+ : 'Owner decision unavailable',
+ status: focus.governorMode || 'unknown',
+ detail: focus.nextOwnerRepository
+ ? `Next owner ${focus.nextOwnerRepository}`
+ : 'No next-owner decision recorded',
+ sourcePath: toDisplayPath(repoRoot, governorPortfolioSummaryPath || governorSummaryPath),
+ updatedAt:
+ normalizeText(governorPortfolioSummary?.generatedAt) || normalizeText(governorSummary?.generatedAt),
+ repository: focus.currentOwnerRepository,
+ nextAction: focus.nextAction
+ }),
+ seenIds
+ );
+
+ const releaseBlocker = normalizeText(governorSummary?.summary?.releaseSigningExternalBlocker);
+ const releasePublishedBundleState = normalizeText(governorSummary?.summary?.releasePublishedBundleState);
+ if (releaseBlocker || releasePublishedBundleState) {
+ addUniqueMemoryItem(
+ items,
+ makeMemoryItem({
+ id: 'release-publication-blocker',
+ kind: 'blocker',
+ label: releaseBlocker || `Published bundle ${releasePublishedBundleState}`,
+ status: normalizeText(governorSummary?.summary?.releaseSigningStatus) || 'warn',
+ detail: normalizeText(governorSummary?.summary?.releasePublicationState),
+ sourcePath: toDisplayPath(repoRoot, governorSummaryPath),
+ updatedAt: normalizeText(governorSummary?.generatedAt),
+ issueNumber: focus.activeIssue?.number,
+ repository: focus.currentOwnerRepository,
+ nextAction: focus.nextAction
+ }),
+ seenIds
+ );
+ }
+
+ const dependencyStatus = normalizeText(governorPortfolioSummary?.summary?.viHistoryDistributorDependencyStatus);
+ if (dependencyStatus) {
+ addUniqueMemoryItem(
+ items,
+ makeMemoryItem({
+ id: 'vi-history-distributor-dependency',
+ kind: 'dependency',
+ label: `vi-history dependency ${dependencyStatus}`,
+ status: dependencyStatus,
+ detail:
+ normalizeText(governorPortfolioSummary?.summary?.viHistoryDistributorDependencyExternalBlocker) ||
+ normalizeText(governorPortfolioSummary?.summary?.viHistoryDistributorDependencyPublishedBundleState),
+ sourcePath: toDisplayPath(repoRoot, governorPortfolioSummaryPath),
+ updatedAt: normalizeText(governorPortfolioSummary?.generatedAt),
+ repository:
+ normalizeText(governorPortfolioSummary?.summary?.viHistoryDistributorDependencyTargetRepository),
+ nextAction: focus.nextAction
+ }),
+ seenIds
+ );
+ }
+
+ return { items, seenIds };
+}
+
+function deriveEpisodeMemoryItems(sortedEpisodes, repoRoot, seenIds) {
+ const hotEpisodes = [];
+ const warmEpisodes = [];
+ const usedEpisodeIds = new Set();
+
+ for (const entry of sortedEpisodes) {
+ const digest = buildEpisodeDigest(entry.episode, repoRoot, entry.path);
+ const item = makeMemoryItem({
+ id: `episode-${digest.episodeId || digest.agentId || digest.generatedAt}`,
+ kind: 'subagent-episode',
+ label: `${digest.agentName || digest.agentId || 'subagent'}: ${digest.taskSummary || 'task'}`,
+ status: digest.status || 'reported',
+ detail: digest.blocker || digest.executionPlane,
+ sourcePath: digest.sourcePath,
+ updatedAt: digest.generatedAt,
+ issueNumber: normalizeInteger(entry.episode?.task?.issueNumber),
+ repository: normalizeText(entry.episode?.repository),
+ agentName: digest.agentName,
+ nextAction: digest.nextAction
+ });
+
+ if (usedEpisodeIds.has(item.id) || seenIds.has(item.id)) {
+ continue;
+ }
+
+ if (isEpisodeActive(entry.episode) && hotEpisodes.length < 3) {
+ hotEpisodes.push(item);
+ usedEpisodeIds.add(item.id);
+ seenIds.add(item.id);
+ continue;
+ }
+
+ if (warmEpisodes.length < 5) {
+ warmEpisodes.push(item);
+ usedEpisodeIds.add(item.id);
+ continue;
+ }
+ }
+
+ const archiveCount = Math.max(sortedEpisodes.length - usedEpisodeIds.size, 0);
+ return { hotEpisodes, warmEpisodes, archiveCount };
+}
+
+function buildReport({
+ repoRoot,
+ priorityCachePath,
+ priorityCache,
+ governorSummaryPath,
+ governorSummary,
+ governorPortfolioSummaryPath,
+ governorPortfolioSummary,
+ monitoringModePath,
+ monitoringMode,
+ operatorSteeringEventPath,
+ operatorSteeringEvent,
+ episodeDirPath,
+ episodes,
+ now
+}) {
+ const ownerSummary = deriveOwnerSummary(governorSummary, governorPortfolioSummary, monitoringMode);
+ const focus = deriveFocus(priorityCache, ownerSummary);
+ const { items: systemItems, seenIds } = deriveSystemMemoryItems({
+ repoRoot,
+ priorityCachePath,
+ governorSummaryPath,
+ governorSummary,
+ governorPortfolioSummaryPath,
+ governorPortfolioSummary,
+ focus
+ });
+ const sortedEpisodes = sortEpisodesDescending(episodes.validEpisodes);
+ const { hotEpisodes, warmEpisodes, archiveCount } = deriveEpisodeMemoryItems(sortedEpisodes, repoRoot, seenIds);
+ const hotWorkingSet = [...systemItems, ...hotEpisodes];
+ const byStatus = countByStatus(episodes.validEpisodes);
+ const byAgent = countByAgent(episodes.validEpisodes);
+ const cost = {
+ episodeCountWithCost: episodes.validEpisodes.filter(
+ (entry) =>
+ normalizeFiniteNumber(entry.episode?.cost?.tokenUsd) != null ||
+ normalizeFiniteNumber(entry.episode?.cost?.operatorLaborUsd) != null ||
+ normalizeFiniteNumber(entry.episode?.cost?.blendedLowerBoundUsd) != null
+ ).length,
+ tokenUsd: Number(sumEpisodeCost(episodes.validEpisodes, 'tokenUsd').toFixed(6)),
+ operatorLaborUsd: Number(sumEpisodeCost(episodes.validEpisodes, 'operatorLaborUsd').toFixed(6)),
+ blendedLowerBoundUsd: Number(sumEpisodeCost(episodes.validEpisodes, 'blendedLowerBoundUsd').toFixed(6)),
+ observedDurationSeconds: Number(sumEpisodeCost(episodes.validEpisodes, 'observedDurationSeconds').toFixed(3))
+ };
+ const blockerCount = hotWorkingSet.filter((item) =>
+ ['blocked', 'warn', 'fail', 'unknown', 'producer-native-incomplete'].includes((item.status || '').toLowerCase())
+ ).length;
+ const concentrationStatus =
+ episodes.invalidEpisodes.length > 0
+ ? 'warn'
+ : governorSummary || governorPortfolioSummary
+ ? 'pass'
+ : 'incomplete';
+
+ return {
+ schema: REPORT_SCHEMA,
+ generatedAt: now.toISOString(),
+ repository:
+ normalizeText(governorSummary?.repository) ||
+ normalizeText(governorPortfolioSummary?.repository) ||
+ normalizeText(priorityCache?.repository),
+ inputs: {
+ priorityCachePath: toDisplayPath(repoRoot, priorityCachePath),
+ governorSummaryPath: toDisplayPath(repoRoot, governorSummaryPath),
+ governorPortfolioSummaryPath: toDisplayPath(repoRoot, governorPortfolioSummaryPath),
+ monitoringModePath: toDisplayPath(repoRoot, monitoringModePath),
+ operatorSteeringEventPath: toDisplayPath(repoRoot, operatorSteeringEventPath),
+ episodeDirectoryPath: toDisplayPath(repoRoot, episodeDirPath)
+ },
+ sources: {
+ priorityCache: {
+ path: toDisplayPath(repoRoot, priorityCachePath),
+ exists: Boolean(priorityCache)
+ },
+ governorSummary: {
+ path: toDisplayPath(repoRoot, governorSummaryPath),
+ exists: Boolean(governorSummary)
+ },
+ governorPortfolioSummary: {
+ path: toDisplayPath(repoRoot, governorPortfolioSummaryPath),
+ exists: Boolean(governorPortfolioSummary)
+ },
+ monitoringMode: {
+ path: toDisplayPath(repoRoot, monitoringModePath),
+ exists: Boolean(monitoringMode)
+ },
+ operatorSteeringEvent: {
+ path: toDisplayPath(repoRoot, operatorSteeringEventPath),
+ exists: Boolean(operatorSteeringEvent)
+ },
+ episodeDirectory: {
+ path: toDisplayPath(repoRoot, episodeDirPath),
+ exists: fs.existsSync(episodeDirPath),
+ fileCount: episodes.files.length,
+ validEpisodeCount: episodes.validEpisodes.length,
+ invalidEpisodeCount: episodes.invalidEpisodes.length
+ }
+ },
+ focus,
+ memory: {
+ hotWorkingSet,
+ warmMemory: warmEpisodes,
+ archiveCount
+ },
+ episodes: {
+ totalCount: episodes.files.length,
+ validCount: episodes.validEpisodes.length,
+ invalidCount: episodes.invalidEpisodes.length,
+ invalidEpisodes: episodes.invalidEpisodes,
+ byStatus,
+ byAgent,
+ recent: sortedEpisodes.slice(0, 5).map((entry) => buildEpisodeDigest(entry.episode, repoRoot, entry.path))
+ },
+ cost,
+ summary: {
+ status:
+ normalizeText(governorSummary?.summary?.governorMode) === 'monitoring-active' ? 'monitoring' : 'active',
+ concentrationStatus,
+ currentOwnerRepository: focus.currentOwnerRepository,
+ nextOwnerRepository: focus.nextOwnerRepository,
+ nextAction: focus.nextAction,
+ activeIssueNumber: normalizeInteger(focus.activeIssue?.number),
+ hotWorkingSetCount: hotWorkingSet.length,
+ warmMemoryCount: warmEpisodes.length,
+ archiveCount,
+ blockerCount,
+ recentEpisodeCount: episodes.validEpisodes.length,
+ blendedLowerBoundUsd: cost.blendedLowerBoundUsd
+ }
+ };
+}
+
+export function parseArgs(argv = process.argv) {
+ const args = argv.slice(2);
+ const options = {
+ repoRoot: DEFAULT_REPO_ROOT,
+ priorityCachePath: DEFAULT_PRIORITY_CACHE_PATH,
+ governorSummaryPath: DEFAULT_GOVERNOR_SUMMARY_PATH,
+ governorPortfolioSummaryPath: DEFAULT_GOVERNOR_PORTFOLIO_SUMMARY_PATH,
+ monitoringModePath: DEFAULT_MONITORING_MODE_PATH,
+ operatorSteeringEventPath: DEFAULT_OPERATOR_STEERING_EVENT_PATH,
+ episodeDirectoryPath: DEFAULT_EPISODE_DIR,
+ outputPath: DEFAULT_OUTPUT_PATH,
+ help: false
+ };
+
+ const stringFlags = new Map([
+ ['--repo-root', 'repoRoot'],
+ ['--priority-cache', 'priorityCachePath'],
+ ['--governor-summary', 'governorSummaryPath'],
+ ['--governor-portfolio-summary', 'governorPortfolioSummaryPath'],
+ ['--monitoring-mode', 'monitoringModePath'],
+ ['--operator-steering-event', 'operatorSteeringEventPath'],
+ ['--episode-directory', 'episodeDirectoryPath'],
+ ['--output', 'outputPath']
+ ]);
+
+ for (let index = 0; index < args.length; index += 1) {
+ const token = args[index];
+ if (token === '-h' || token === '--help') {
+ options.help = true;
+ continue;
+ }
+
+ if (stringFlags.has(token)) {
+ const next = args[index + 1];
+ if (!next || next.startsWith('-')) {
+ throw new Error(`Missing value for ${token}.`);
+ }
+ index += 1;
+ options[stringFlags.get(token)] = next;
+ continue;
+ }
+
+ throw new Error(`Unknown option: ${token}`);
+ }
+
+ return options;
+}
+
+function printHelp() {
+ console.log('Usage: node tools/priority/sagan-context-concentrator.mjs [options]');
+ console.log('');
+ console.log('Options:');
+ console.log(' --repo-root Repository root.');
+ console.log(` --priority-cache Priority cache (default: ${DEFAULT_PRIORITY_CACHE_PATH}).`);
+ console.log(` --governor-summary Governor summary (default: ${DEFAULT_GOVERNOR_SUMMARY_PATH}).`);
+ console.log(
+ ` --governor-portfolio-summary Governor portfolio summary (default: ${DEFAULT_GOVERNOR_PORTFOLIO_SUMMARY_PATH}).`
+ );
+ console.log(` --monitoring-mode Monitoring mode report (default: ${DEFAULT_MONITORING_MODE_PATH}).`);
+ console.log(
+ ` --operator-steering-event Operator steering event (default: ${DEFAULT_OPERATOR_STEERING_EVENT_PATH}).`
+ );
+ console.log(` --episode-directory Subagent episode directory (default: ${DEFAULT_EPISODE_DIR}).`);
+ console.log(` --output Output path (default: ${DEFAULT_OUTPUT_PATH}).`);
+ console.log(' -h, --help Show this help text.');
+}
+
+export async function runSaganContextConcentrator(options = {}, deps = {}) {
+ const repoRoot = path.resolve(options.repoRoot || DEFAULT_REPO_ROOT);
+ const priorityCachePath = path.resolve(repoRoot, options.priorityCachePath || DEFAULT_PRIORITY_CACHE_PATH);
+ const governorSummaryPath = path.resolve(repoRoot, options.governorSummaryPath || DEFAULT_GOVERNOR_SUMMARY_PATH);
+ const governorPortfolioSummaryPath = path.resolve(
+ repoRoot,
+ options.governorPortfolioSummaryPath || DEFAULT_GOVERNOR_PORTFOLIO_SUMMARY_PATH
+ );
+ const monitoringModePath = path.resolve(repoRoot, options.monitoringModePath || DEFAULT_MONITORING_MODE_PATH);
+ const operatorSteeringEventPath = path.resolve(
+ repoRoot,
+ options.operatorSteeringEventPath || DEFAULT_OPERATOR_STEERING_EVENT_PATH
+ );
+ const episodeDirPath = path.resolve(repoRoot, options.episodeDirectoryPath || DEFAULT_EPISODE_DIR);
+ const outputPath = path.resolve(repoRoot, options.outputPath || DEFAULT_OUTPUT_PATH);
+
+ const readOptionalJsonFn = deps.readOptionalJsonFn || readOptionalJson;
+ const writeJsonFn = deps.writeJsonFn || writeJson;
+ const now = deps.now || new Date();
+
+ const priorityCache = readOptionalJsonFn(priorityCachePath);
+ const governorSummary = readOptionalJsonFn(governorSummaryPath);
+ const governorPortfolioSummary = readOptionalJsonFn(governorPortfolioSummaryPath);
+ const monitoringMode = readOptionalJsonFn(monitoringModePath);
+ const operatorSteeringEvent = readOptionalJsonFn(operatorSteeringEventPath);
+ const episodes = readEpisodes(repoRoot, episodeDirPath, readOptionalJsonFn);
+
+ if (governorSummary) {
+ ensureSchema(governorSummary, governorSummaryPath, 'priority/autonomous-governor-summary-report@v1');
+ }
+ if (governorPortfolioSummary) {
+ ensureSchema(
+ governorPortfolioSummary,
+ governorPortfolioSummaryPath,
+ 'priority/autonomous-governor-portfolio-summary-report@v1'
+ );
+ }
+ if (monitoringMode) {
+ ensureSchema(monitoringMode, monitoringModePath, 'agent-handoff/monitoring-mode-v1');
+ }
+
+ const report = buildReport({
+ repoRoot,
+ priorityCachePath,
+ priorityCache,
+ governorSummaryPath,
+ governorSummary,
+ governorPortfolioSummaryPath,
+ governorPortfolioSummary,
+ monitoringModePath,
+ monitoringMode,
+ operatorSteeringEventPath,
+ operatorSteeringEvent,
+ episodeDirPath,
+ episodes,
+ now
+ });
+
+ const writtenPath = writeJsonFn(outputPath, report);
+ return { report, outputPath: writtenPath };
+}
+
+export async function main(argv = process.argv) {
+ let options;
+ try {
+ options = parseArgs(argv);
+ } catch (error) {
+ console.error(`[sagan-context-concentrator] ${error.message}`);
+ printHelp();
+ return 1;
+ }
+
+ if (options.help) {
+ printHelp();
+ return 0;
+ }
+
+ try {
+ const { report, outputPath } = await runSaganContextConcentrator(options);
+ console.log(
+ `[sagan-context-concentrator] wrote ${outputPath} (${report.summary.concentrationStatus}, hot=${report.summary.hotWorkingSetCount})`
+ );
+ return 0;
+ } catch (error) {
+ console.error(`[sagan-context-concentrator] ${error.message}`);
+ return 1;
+ }
+}
+
+const modulePath = path.resolve(fileURLToPath(import.meta.url));
+const invokedPath = process.argv[1] ? path.resolve(process.argv[1]) : null;
+if (invokedPath && invokedPath === modulePath) {
+ main(process.argv)
+ .then((code) => {
+ if (code !== 0) {
+ process.exitCode = code;
+ }
+ })
+ .catch((error) => {
+ console.error(`[sagan-context-concentrator] ${error.message}`);
+ process.exitCode = 1;
+ });
+}
diff --git a/tools/priority/subagent-episode.mjs b/tools/priority/subagent-episode.mjs
new file mode 100644
index 000000000..4fb0bb9ba
--- /dev/null
+++ b/tools/priority/subagent-episode.mjs
@@ -0,0 +1,292 @@
+#!/usr/bin/env node
+
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
+const DEFAULT_REPO_ROOT = path.resolve(MODULE_DIR, '..', '..');
+
+export const REPORT_SCHEMA = 'priority/subagent-episode-report@v1';
+export const DEFAULT_OUTPUT_DIR = path.join(
+ 'tests',
+ 'results',
+ '_agent',
+ 'memory',
+ 'subagent-episodes'
+);
+
+function normalizeText(value) {
+ if (value == null) {
+ return null;
+ }
+ const normalized = String(value).trim();
+ return normalized.length > 0 ? normalized : null;
+}
+
+function sanitizeSegment(value, fallback = 'episode') {
+ return String(value || '')
+ .trim()
+ .replace(/[^A-Za-z0-9._-]+/g, '-')
+ .replace(/^-+|-+$/g, '') || fallback;
+}
+
+function normalizeStringArray(value) {
+ if (!Array.isArray(value)) {
+ return [];
+ }
+ return value.map((entry) => normalizeText(entry)).filter(Boolean);
+}
+
+function normalizeFiniteNumber(value) {
+ if (value == null || value === '') {
+ return null;
+ }
+ const parsed = Number(value);
+ return Number.isFinite(parsed) ? parsed : null;
+}
+
+function normalizeInteger(value) {
+ if (value == null || value === '') {
+ return null;
+ }
+ const parsed = Number(value);
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
+}
+
+function normalizeObject(value) {
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
+}
+
+function toPortablePath(filePath) {
+ return String(filePath).replace(/\\/g, '/');
+}
+
+function toDisplayPath(repoRoot, filePath) {
+ if (!filePath) {
+ return null;
+ }
+ const resolvedRepoRoot = path.resolve(repoRoot);
+ const resolvedPath = path.resolve(filePath);
+ const relative = path.relative(resolvedRepoRoot, resolvedPath);
+ if (!relative.startsWith('..') && !path.isAbsolute(relative)) {
+ return toPortablePath(relative);
+ }
+ return toPortablePath(resolvedPath);
+}
+
+function isValidDateTime(value) {
+ return typeof value === 'string' && !Number.isNaN(Date.parse(value));
+}
+
+function readJsonFile(filePath) {
+ const resolvedPath = path.resolve(filePath);
+ return JSON.parse(fs.readFileSync(resolvedPath, 'utf8'));
+}
+
+function writeJsonFile(filePath, payload) {
+ const resolvedPath = path.resolve(filePath);
+ fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
+ fs.writeFileSync(resolvedPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
+ return resolvedPath;
+}
+
+export function parseArgs(argv = process.argv) {
+ const args = argv.slice(2);
+ const options = {
+ repoRoot: DEFAULT_REPO_ROOT,
+ inputPath: null,
+ outputPath: null,
+ help: false
+ };
+
+ for (let index = 0; index < args.length; index += 1) {
+ const token = args[index];
+ if (token === '-h' || token === '--help') {
+ options.help = true;
+ continue;
+ }
+
+ if (token === '--repo-root' || token === '--input' || token === '--output') {
+ const next = args[index + 1];
+ if (!next || next.startsWith('-')) {
+ throw new Error(`Missing value for ${token}.`);
+ }
+ index += 1;
+ if (token === '--repo-root') {
+ options.repoRoot = next;
+ } else if (token === '--input') {
+ options.inputPath = next;
+ } else if (token === '--output') {
+ options.outputPath = next;
+ }
+ continue;
+ }
+
+ throw new Error(`Unknown option: ${token}`);
+ }
+
+ if (!options.help && !normalizeText(options.inputPath)) {
+ throw new Error('--input is required.');
+ }
+
+ return options;
+}
+
+function buildDefaultOutputPath(repoRoot, report) {
+ const timestamp = report.generatedAt.replace(/[:.]/g, '-');
+ const agentSlug = sanitizeSegment(report.agent.name || report.agent.id || 'subagent', 'subagent');
+ const issueSlug = Number.isInteger(report.task.issueNumber) ? `issue-${report.task.issueNumber}` : 'no-issue';
+ return path.resolve(
+ repoRoot,
+ DEFAULT_OUTPUT_DIR,
+ `${timestamp}-${agentSlug}-${issueSlug}.json`
+ );
+}
+
+export function buildSubagentEpisodeReport(input, options = {}) {
+ const repoRoot = path.resolve(options.repoRoot || DEFAULT_REPO_ROOT);
+ const now = options.now || new Date();
+ const source = normalizeObject(input) || {};
+ const agent = normalizeObject(source.agent) || {};
+ const task = normalizeObject(source.task) || {};
+ const execution = normalizeObject(source.execution) || {};
+ const summary = normalizeObject(source.summary) || {};
+ const evidence = normalizeObject(source.evidence) || {};
+ const cost = normalizeObject(source.cost) || {};
+ const generatedAt = isValidDateTime(source.generatedAt) ? source.generatedAt : now.toISOString();
+ const issueNumber =
+ normalizeInteger(task.issueNumber) ??
+ normalizeInteger(source.issueNumber) ??
+ null;
+
+ const report = {
+ schema: REPORT_SCHEMA,
+ generatedAt,
+ repository: normalizeText(source.repository),
+ inputs: {
+ sourcePath: toDisplayPath(repoRoot, options.inputPath || null)
+ },
+ episodeId:
+ normalizeText(source.episodeId) ||
+ `${sanitizeSegment(agent.name || agent.id || 'subagent', 'subagent')}-${generatedAt.replace(/[:.]/g, '-')}`,
+ agent: {
+ id: normalizeText(agent.id),
+ name: normalizeText(agent.name),
+ role: normalizeText(agent.role),
+ model: normalizeText(agent.model)
+ },
+ task: {
+ summary: normalizeText(task.summary) || '(unspecified task)',
+ class: normalizeText(task.class),
+ issueNumber,
+ issueUrl: normalizeText(task.issueUrl) || normalizeText(source.issueUrl)
+ },
+ execution: {
+ status: normalizeText(execution.status) || 'completed',
+ lane: normalizeText(execution.lane),
+ branch: normalizeText(execution.branch),
+ executionPlane: normalizeText(execution.executionPlane),
+ dockerLaneId: normalizeText(execution.dockerLaneId),
+ hostCapabilityLeaseId: normalizeText(execution.hostCapabilityLeaseId)
+ },
+ summary: {
+ status: normalizeText(summary.status) || normalizeText(source.status) || 'reported',
+ outcome: normalizeText(summary.outcome),
+ blocker: normalizeText(summary.blocker),
+ nextAction: normalizeText(summary.nextAction),
+ detail: normalizeText(summary.detail)
+ },
+ evidence: {
+ filesTouched: normalizeStringArray(evidence.filesTouched),
+ receipts: normalizeStringArray(evidence.receipts),
+ commands: normalizeStringArray(evidence.commands),
+ notes: normalizeStringArray(evidence.notes)
+ },
+ cost: {
+ observedDurationSeconds:
+ normalizeFiniteNumber(cost.observedDurationSeconds) ??
+ normalizeFiniteNumber(cost.elapsedSeconds),
+ tokenUsd: normalizeFiniteNumber(cost.tokenUsd),
+ operatorLaborUsd: normalizeFiniteNumber(cost.operatorLaborUsd),
+ blendedLowerBoundUsd:
+ normalizeFiniteNumber(cost.blendedLowerBoundUsd) ??
+ normalizeFiniteNumber(cost.blendedUsd)
+ }
+ };
+
+ return report;
+}
+
+export async function runSubagentEpisode(options = {}, deps = {}) {
+ const repoRoot = path.resolve(options.repoRoot || DEFAULT_REPO_ROOT);
+ const inputPath = path.resolve(repoRoot, options.inputPath);
+ const readJsonFn = deps.readJsonFn || readJsonFile;
+ const writeJsonFn = deps.writeJsonFn || writeJsonFile;
+ const now = deps.now || new Date();
+
+ const input = readJsonFn(inputPath);
+ const report = buildSubagentEpisodeReport(input, {
+ repoRoot,
+ inputPath,
+ now
+ });
+ const outputPath = path.resolve(
+ repoRoot,
+ options.outputPath || buildDefaultOutputPath(repoRoot, report)
+ );
+ const writtenPath = writeJsonFn(outputPath, report);
+ return { report, outputPath: writtenPath };
+}
+
+function printHelp() {
+ console.log('Usage: node tools/priority/subagent-episode.mjs [options]');
+ console.log('');
+ console.log('Options:');
+ console.log(' --repo-root Repository root (default: current repo).');
+ console.log(' --input Required input JSON path describing a subagent episode.');
+ console.log(` --output Optional output path (default under ${DEFAULT_OUTPUT_DIR}).`);
+ console.log(' -h, --help Show this help text.');
+}
+
+export async function main(argv = process.argv) {
+ let options;
+ try {
+ options = parseArgs(argv);
+ } catch (error) {
+ console.error(`[subagent-episode] ${error.message}`);
+ printHelp();
+ return 1;
+ }
+
+ if (options.help) {
+ printHelp();
+ return 0;
+ }
+
+ try {
+ const { report, outputPath } = await runSubagentEpisode(options);
+ console.log(
+ `[subagent-episode] wrote ${outputPath} (${report.agent.name || report.agent.id || 'subagent'} -> ${report.summary.status})`
+ );
+ return 0;
+ } catch (error) {
+ console.error(`[subagent-episode] ${error.message}`);
+ return 1;
+ }
+}
+
+const modulePath = path.resolve(fileURLToPath(import.meta.url));
+const invokedPath = process.argv[1] ? path.resolve(process.argv[1]) : null;
+if (invokedPath && invokedPath === modulePath) {
+ main(process.argv)
+ .then((code) => {
+ if (code !== 0) {
+ process.exitCode = code;
+ }
+ })
+ .catch((error) => {
+ console.error(`[subagent-episode] ${error.message}`);
+ process.exitCode = 1;
+ });
+}
diff --git a/tools/priority/supply-chain-trust-gate.mjs b/tools/priority/supply-chain-trust-gate.mjs
index 9df964422..c844a46a6 100644
--- a/tools/priority/supply-chain-trust-gate.mjs
+++ b/tools/priority/supply-chain-trust-gate.mjs
@@ -32,8 +32,10 @@ const FAILURE_HINTS = {
'tag-ref-lookup-failed': 'Unable to resolve release tag via GitHub API. Confirm tag exists and token has repo read access.',
'tag-object-lookup-failed': 'Unable to resolve annotated tag object via GitHub API. Confirm tag object availability.',
'tag-signature-parse-failed': 'Tag signature payload could not be parsed. Re-run and inspect gh api output.',
- 'tag-not-annotated': 'Release tag is lightweight/non-annotated. Create a signed annotated tag for release.',
- 'tag-signature-unverified': 'Release tag signature is not verified. Sign the tag and re-run the release.',
+ 'tag-not-annotated':
+ 'Release tag is lightweight/non-annotated. Run priority:release:signing:readiness first; if readiness is ready, rerun .github/workflows/release-conductor.yml with repair_existing_tag = true to recreate the same release tag as a signed annotated tag.',
+ 'tag-signature-unverified':
+ 'Release tag signature is not verified. Run priority:release:signing:readiness first; if readiness is ready, rerun .github/workflows/release-conductor.yml with repair_existing_tag = true to repair the same release tag before rerunning release.',
'attestation-cli-unavailable': 'GitHub CLI is unavailable. Install/enable gh on runner before trust gate.',
'attestation-output-parse-failed': 'Attestation verification output was not valid JSON. Re-run verification and inspect gh logs.',
'attestation-unverified': 'Artifact attestation verification failed. Confirm attest-build-provenance step and signer workflow.',
diff --git a/tools/schemas/definitions.ts b/tools/schemas/definitions.ts
index 9514fcea0..15e30fc77 100644
--- a/tools/schemas/definitions.ts
+++ b/tools/schemas/definitions.ts
@@ -306,35 +306,145 @@ const compareCliSchema = cliInfoSchema;
const comparePolicySchema = z.enum(['lv-first', 'cli-first', 'cli-only', 'lv-only']);
+const testStandCompareOutcomeSchema = z
+ .object({
+ exitCode: z.number(),
+ seconds: z.number().optional(),
+ command: z.string().optional(),
+ diff: z.boolean().optional(),
+ })
+ .nullable();
+
+const testStandCompareNodeSchema = z.object({
+ events: z.string().min(1),
+ capture: z.union([z.string().min(1), z.null()]),
+ report: z.boolean(),
+ command: z.string().min(1).optional(),
+ cliPath: z.string().min(1).optional(),
+ cli: compareCliSchema.optional(),
+ staging: z
+ .object({
+ enabled: z.boolean(),
+ root: z.union([z.string().min(1), z.null()]),
+ })
+ .optional(),
+ allowSameLeaf: z.boolean().optional(),
+ policy: comparePolicySchema.optional(),
+ mode: z.string().min(1).optional(),
+ autoCli: z.boolean().optional(),
+ sameName: z.boolean().optional(),
+ timeoutSeconds: z.number().min(0).optional(),
+});
+
+const testStandExecutionCellSchema = z.object({
+ cellId: z.string().min(1).nullable().optional(),
+ leaseId: z.string().min(1).nullable().optional(),
+ leasePath: z.string().min(1).nullable().optional(),
+ agentId: z.string().min(1).nullable().optional(),
+ agentClass: z.enum(['sagan', 'subagent', 'other']).nullable().optional(),
+ cellClass: z.enum(['worker', 'coordinator', 'kernel-coordinator']).nullable().optional(),
+ suiteClass: z.enum(['single-compare', 'dual-plane-parity']).nullable().optional(),
+ planeBinding: z.string().min(1).nullable().optional(),
+ runtimeSurface: z.literal('windows-native-teststand').nullable().optional(),
+ premiumSaganMode: z.boolean().optional(),
+ operatorAuthorizationRef: z.string().min(1).nullable().optional(),
+ workingRoot: z.string().min(1).nullable().optional(),
+ artifactRoot: z.string().min(1).nullable().optional(),
+ isolatedLaneGroupId: z.string().min(1).nullable().optional(),
+ hostOsFingerprintSha256: hexSha256.nullable().optional(),
+});
+
+const testStandProcessModelSchema = z.object({
+ runtimeSurface: z.literal('windows-native-teststand'),
+ processModelClass: z.enum(['sequential-process-model', 'parallel-process-model']),
+ windowsOnly: z.literal(true),
+ rootHarnessInstanceId: z.string().min(1),
+ planeCount: z.number().int().min(1),
+});
+
+const testStandHarnessInstanceSchema = z.object({
+ harnessKind: z.string().min(1),
+ instanceId: z.string().min(1),
+ role: z.enum(['single-plane', 'coordinator', 'plane-child']),
+ processModelClass: z.enum(['sequential-process-model', 'parallel-process-model']),
+ planeBinding: z.string().min(1).nullable().optional(),
+ parentInstanceId: z.string().min(1).nullable().optional(),
+});
+
+const testStandPlaneSessionSchema = z.object({
+ plane: z.string().min(1),
+ architecture: z.enum(['32-bit', '64-bit']),
+ labviewExePath: z.union([z.string().min(1), z.null()]).optional(),
+ outputRoot: z.string().min(1),
+ warmup: z.object({
+ mode: warmupModeSchema,
+ events: warmupEventsSchema,
+ }),
+ compare: testStandCompareNodeSchema,
+ outcome: testStandCompareOutcomeSchema,
+ error: z.union([z.string().min(1), z.null()]).optional(),
+ exitCode: z.number(),
+ executionCell: testStandExecutionCellSchema.nullable().optional(),
+ harnessInstance: testStandHarnessInstanceSchema.nullable().optional(),
+ processModel: testStandProcessModelSchema.optional(),
+});
+
+const testStandParitySummarySchema = z.object({
+ status: z.enum(['match', 'mismatch', 'incomplete']),
+ comparedFields: z.array(z.string().min(1)),
+ exitCodeParity: z.boolean().nullable().optional(),
+ diffParity: z.boolean().nullable().optional(),
+ mismatchCount: z.number().int().min(0),
+ mismatches: z.array(
+ z.object({
+ field: z.string().min(1),
+ x64: z.union([z.string().min(1), z.number(), z.boolean(), z.null()]).optional(),
+ x32: z.union([z.string().min(1), z.number(), z.boolean(), z.null()]).optional(),
+ }),
+ ),
+});
+
const testStandCompareSessionSchema = z.object({
- schema: z.literal('teststand-compare-session/v1'),
+ schema: z.enum(['teststand-compare-session/v1', 'teststand-compare-session/v2']),
at: isoString,
warmup: z.object({
mode: warmupModeSchema,
events: warmupEventsSchema,
}),
- compare: z.object({
- events: z.string().min(1),
- capture: z.union([z.string().min(1), z.null()]),
- report: z.boolean(),
- command: z.string().min(1).optional(),
- cliPath: z.string().min(1).optional(),
- cli: compareCliSchema.optional(),
- policy: comparePolicySchema.optional(),
- mode: z.string().min(1).optional(),
- autoCli: z.boolean().optional(),
- sameName: z.boolean().optional(),
- timeoutSeconds: z.number().min(0).optional(),
- }),
- outcome: z
+ compare: testStandCompareNodeSchema,
+ outcome: testStandCompareOutcomeSchema,
+ error: z.union([z.string().min(1), z.null()]).optional(),
+ executionCell: testStandExecutionCellSchema.nullable().optional(),
+ harnessInstance: testStandHarnessInstanceSchema.nullable().optional(),
+ processModel: testStandProcessModelSchema.optional(),
+ suiteClass: z.enum(['single-compare', 'dual-plane-parity']).optional(),
+ primaryPlane: z.string().min(1).optional(),
+ requestedSimultaneous: z.boolean().optional(),
+ planes: z
.object({
- exitCode: z.number(),
- seconds: z.number().optional(),
- command: z.string().optional(),
- diff: z.boolean().optional(),
+ x64: testStandPlaneSessionSchema,
+ x32: testStandPlaneSessionSchema,
})
- .nullable(),
- error: z.union([z.string().min(1), z.null()]).optional(),
+ .optional(),
+ parity: testStandParitySummarySchema.optional(),
+}).superRefine((value, ctx) => {
+ if (value.schema === 'teststand-compare-session/v2') {
+ if (!value.suiteClass) {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'suiteClass is required for v2 sessions', path: ['suiteClass'] });
+ }
+ if (!value.primaryPlane) {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'primaryPlane is required for v2 sessions', path: ['primaryPlane'] });
+ }
+ if (typeof value.requestedSimultaneous !== 'boolean') {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'requestedSimultaneous is required for v2 sessions', path: ['requestedSimultaneous'] });
+ }
+ if (!value.planes) {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'planes is required for v2 sessions', path: ['planes'] });
+ }
+ if (!value.parity) {
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'parity is required for v2 sessions', path: ['parity'] });
+ }
+ }
});
const invokerEventSchema = z.object({
]