Skip to content

M2.17-M P0: reconcile #618/#620; canonical Data Model focused hydration + Explorer read SSOT #1277

M2.17-M P0: reconcile #618/#620; canonical Data Model focused hydration + Explorer read SSOT

M2.17-M P0: reconcile #618/#620; canonical Data Model focused hydration + Explorer read SSOT #1277

name: Smart Discovery Merge Execution Guard
on:
pull_request:
paths:
- "*.cs"
- "**/*.cs"
- "*.csproj"
- "**/*.csproj"
- "*.sln"
- "**/*.sln"
- "*.props"
- "**/*.props"
- "*.targets"
- "**/*.targets"
- "global.json"
- "*.xaml"
- "**/*.xaml"
- "app.manifest"
- "VERSION"
- ".release/**"
- ".github/workflows/**"
- "Assets/**"
- "Resources/**"
- "installer/**"
- "engine-patches/**"
- "landing/release-notes*.json"
- "landing/latest.json"
- "engines/**"
- "scripts/**"
- "tests/**"
- "evidence/**"
- "docs/INTEROPERABILITY_REFERENCE_CONTRACT.md"
- ".github/workflows/smart-discovery-*.yml"
workflow_dispatch:
permissions:
contents: read
actions: read
concurrency:
group: smart-discovery-merge-execution-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
verify-merge-execution-contract:
name: Verify P0-5h ordered merge contract
runs-on: ubuntu-latest
timeout-minutes: 23
steps:
- name: Checkout ARSAS branch
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Validate P0-5h source contract
shell: pwsh
run: |
$target = '.\evidence\smart-discovery-mainline-merge-target.json'
$writer = '.\scripts\new-smart-discovery-mainline-merge-manifest.ps1'
$preflight = '.\scripts\verify-smart-discovery-live-merge-preflight.ps1'
$postMerge = '.\scripts\verify-smart-discovery-post-merge-production.ps1'
$test = '.\tests\ARSAS.Tests\SmartDiscoveryMainlineMergeExecutionRegressionTests.cs'
$doc = '.\docs\P0-5H_MAINLINE_MERGE_POST_MERGE_VERIFICATION.md'
foreach ($path in @($target,$writer,$preflight,$postMerge,$test,$doc)) {
if (-not (Test-Path $path -PathType Leaf)) { throw "P0-5h source missing: $path" }
}
foreach ($script in @($writer,$preflight,$postMerge)) {
$tokens = $null
$errors = $null
$scriptAbsolute = (Resolve-Path -LiteralPath $script).Path
[System.Management.Automation.Language.Parser]::ParseFile($scriptAbsolute,[ref]$tokens,[ref]$errors) | Out-Null
if ($errors.Count -ne 0) {
$messages = @($errors | ForEach-Object { $_.Message }) -join '; '
throw "PowerShell parse failure in ${script}: $messages"
}
}
$json = Get-Content $target -Raw | ConvertFrom-Json
if ($json.Phase -ne 'P0-5h' -or $json.MergeMethod -ne 'merge') { throw 'P0-5h target does not lock merge-commit execution.' }
if ((@($json.MergeOrder) -join ',') -ne 'engine,arsas') { throw 'P0-5h target does not require engine-first order.' }
if (-not [bool]$json.ExecutionContract.RequireOnlyMergeManifestChangeAfterValidatedArsasHead) {
throw 'P0-5h target does not close the tracked-manifest self-reference boundary.'
}
$manifest = '.\evidence\smart-discovery-mainline-merge-manifest.json'
if (Test-Path $manifest -PathType Leaf) {
$m = Get-Content $manifest -Raw | ConvertFrom-Json
if ($m.Phase -ne 'P0-5h-merge-manifest' -or $m.Status -ne 'authorized-for-ordered-merge' -or $m.MergeMethod -ne 'merge') {
throw 'Tracked P0-5h merge manifest is invalid.'
}
if ((@($m.MergeOrder) -join ',') -ne 'engine,arsas') { throw 'Tracked merge manifest changed merge order.' }
if ([string]$m.Arsas.LiveMergeHeadSha) { throw 'Tracked manifest must not self-bind its own future commit SHA.' }
if ((@($m.Arsas.AllowedPostAuthorizationPaths) -join ',') -ne 'evidence/smart-discovery-mainline-merge-manifest.json') {
throw 'Tracked manifest widened the post-authorization ARSAS mutation boundary.'
}
}
- name: Validate offline canonical evidence producer/consumer fixtures
run: python3 scripts/test-ci-canonical-reuse.py
- id: pinned-engine
name: Resolve exact integration engine authority
uses: ./.github/actions/resolve-ariec-engine
with:
lock-path: engines/ARIEC61850.lock.json
- name: Require same-head canonical Build ARSAS regression proof
if: github.event_name == 'pull_request'
env:
GITHUB_TOKEN: ${{ github.token }}
PR_HEAD_BRANCH: ${{ github.event.pull_request.head.ref }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_MERGE_SHA: ${{ github.sha }}
PINNED_ENGINE_SHA: ${{ steps.pinned-engine.outputs.commit }}
REPOSITORY: ${{ github.repository }}
run: |
python3 scripts/verify-ci-canonical-reuse.py \
--repository "$REPOSITORY" \
--head-branch "$PR_HEAD_BRANCH" \
--head-sha "$PR_HEAD_SHA" \
--merge-sha "$PR_MERGE_SHA" \
--engine-sha "$PINNED_ENGINE_SHA" \
--wait-seconds 960 \
--allow-in-progress-artifact \
--output "$RUNNER_TEMP/ci-canonical-reuse-proof.json"
- name: Summarize exact canonical-regression reuse
if: github.event_name == 'pull_request'
run: |
python3 - <<'PY'
import json
import os
from pathlib import Path
proof = json.loads(
(Path(os.environ["RUNNER_TEMP"]) / "ci-canonical-reuse-proof.json").read_text()
)
with Path(os.environ["GITHUB_STEP_SUMMARY"]).open("a", encoding="utf-8") as out:
out.write("## Canonical ARSAS regression reuse — fail-closed PASS\\n\\n")
out.write(f"- canonical Build ARSAS run: {proof['canonicalRunId']}, attempt {proof['canonicalRunAttempt']}\\n")
out.write(f"- exact PR merge SHA: {proof['mergeSha']}\\n")
out.write(f"- exact engine SHA: {proof['engineSha']}\\n")
out.write(f"- full regression: {proof['passed']} passed, {proof['failed']} failed\\n")
out.write(f"- proof stage: {proof['proofStage']}\\n")
out.write(f"- canonical workflow completed: {proof['workflowCompleted']}\\n")
out.write(f"- packaging/smoke proven by this guard: {proof['packagingSmokeProven']}\\n")
out.write("- Build ARSAS remains the independent packaging/smoke check\\n")
out.write("- Source P0-5h ordered-merge contract: passed independently\\n")
PY
manual-regression:
name: Manual exact-SHA reusable full regression
if: github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/_ci-p1-windows-build-test.yml
with:
source_sha: ${{ github.sha }}
shadow_mode: true
secrets: {}