Strengthen split target conformance consumption

This commit is contained in:
Meta Vens 2026-07-09 01:39:26 +01:00
commit ef16b0c90b
5 changed files with 135 additions and 0 deletions

View file

@ -280,6 +280,13 @@ Exit criteria:
Recently cut:
- Split-target conformance consumption now verifies graduation state instead of
only split-target presence. The generic consumer supports
`--expect-split-target-status`, `--expect-split-target-blocker`, and
`--expect-split-target-proof`; the parity harness runs
`scripts/run-split-target-conformance-consumer-smoke.ps1`; and EveFlutter /
EveUnity consumers can now prove that the targets remain incubating for named
blockers while their current split-readiness proofs stay passed.
- Runtime owner conformance consumption now verifies runtime target health
instead of only runtime presence. The generic consumer supports
`--expect-runtime-status`, `--expect-runtime-feature`,

View file

@ -120,6 +120,18 @@ That script runs the export consumer from `flutter/eve_parity` and asserts the
runtime pack, Sai provider fixture, Flutter runtime targets, and `EveFlutter`
split target without reading `tools/parity/parity-manifest.json`.
Split-target consumer smoke:
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\run-split-target-conformance-consumer-smoke.ps1
```
That script asserts that EveFlutter and EveUnity are exported as incubating
split targets, that their current split-readiness proofs are passed, and that
their graduation blockers remain visible to consumers. A target being present
is not enough; future owner repos must be able to consume why it is or is not
ready to leave Eve incubation.
The Flutter widget smoke also exercises `EveProviderCatalog` and
`EveProviderPicker` against a conformance-export-shaped provider list. That is
the runtime-side provider picker proof; it consumes provider entries and plugin

View file

@ -17,6 +17,7 @@ try {
& (Join-Path $PSScriptRoot "run-conformance-consumer-smoke.ps1")
& (Join-Path $PSScriptRoot "run-plugin-owner-conformance-consumer-smoke.ps1")
& (Join-Path $PSScriptRoot "run-runtime-owner-conformance-consumer-smoke.ps1")
& (Join-Path $PSScriptRoot "run-split-target-conformance-consumer-smoke.ps1")
} finally {
Pop-Location
}

View file

@ -0,0 +1,53 @@
param(
[string] $SourceDirectory = "artifacts\conformance\latest",
[string] $SmokeDirectory = "artifacts\split-target-conformance-consumer-smoke"
)
$ErrorActionPreference = "Stop"
$projectRoot = Split-Path -Parent $PSScriptRoot
$sourcePath = if ([System.IO.Path]::IsPathRooted($SourceDirectory)) {
$SourceDirectory
} else {
Join-Path $projectRoot $SourceDirectory
}
$smokePath = if ([System.IO.Path]::IsPathRooted($SmokeDirectory)) {
$SmokeDirectory
} else {
Join-Path $projectRoot $SmokeDirectory
}
$exportPath = Join-Path $smokePath "export"
if (-not (Test-Path -LiteralPath (Join-Path $sourcePath "index.json"))) {
throw "Conformance export not found: $sourcePath"
}
if (Test-Path -LiteralPath $exportPath) {
Remove-Item -LiteralPath $exportPath -Recurse -Force
}
New-Item -ItemType Directory -Force -Path $smokePath | Out-Null
Copy-Item -LiteralPath $sourcePath -Destination $exportPath -Recurse
Push-Location $projectRoot
try {
node .\tools\conformance\consume-export.mjs $exportPath `
--expect-split-target EveFlutter `
--expect-split-target-status EveFlutter:incubating `
--expect-split-target-proof "EveFlutter:Provider picker consumes provider advertisements" `
--expect-split-target-proof "EveFlutter:Conformance pack can be consumed" `
--expect-split-target-proof "EveFlutter:Flutter lifecycle evidence is declared" `
--expect-split-target-blocker "EveFlutter:Tagged EveFlutter release" `
--expect-split-target EveUnity `
--expect-split-target-status EveUnity:incubating `
--expect-split-target-proof "EveUnity:Unity lifecycle evidence is declared" `
--expect-split-target-blocker "EveUnity:Tagged UPM release" `
--expect-split-target-blocker "EveUnity:Unity batchmode EditMode runner" `
--expect-split-target-blocker "EveUnity:Unity batchmode or editor capture artifact"
if ($LASTEXITCODE -ne 0) {
throw "Split target conformance consumer smoke failed with exit code $LASTEXITCODE"
}
} finally {
Pop-Location
}
Write-Host "Split target conformance consumer smoke passed: $exportPath"

View file

@ -25,6 +25,9 @@ if (!exportDirectory) {
" --expect-runtime-feature <runtimeId:feature>",
" --expect-runtime-command-schema <runtimeId:schema>",
" --expect-runtime-capture-status <runtimeId:status>",
" --expect-split-target-status <targetId:status>",
" --expect-split-target-blocker <targetId:blocker-substring>",
" --expect-split-target-proof <targetId:proof-substring>",
].join("\n"));
process.exit(2);
}
@ -208,6 +211,41 @@ function validateIndex(index, directory, expectations, errors) {
for (const expectedSplitTarget of expectations.splitTargets) {
if (!splitTargets.some(target => target.id === expectedSplitTarget)) errors.push(`splitTargets:${expectedSplitTarget}:missing`);
}
for (const expectation of expectations.splitTargetStatuses) {
const target = splitTargets.find(candidate => candidate.id === expectation.targetId);
if (!target) {
errors.push(`splitTargets:${expectation.targetId}:missing`);
continue;
}
if (target.status !== expectation.status) {
errors.push(`splitTargets:${expectation.targetId}:status:expected ${expectation.status} got ${target.status || ""}`);
}
}
for (const expectation of expectations.splitTargetBlockers) {
const target = splitTargets.find(candidate => candidate.id === expectation.targetId);
if (!target) {
errors.push(`splitTargets:${expectation.targetId}:missing`);
continue;
}
const blockers = Array.isArray(target.blockers) ? target.blockers : [];
if (!blockers.some(blocker => blocker.includes(expectation.blocker))) {
errors.push(`splitTargets:${expectation.targetId}:blocker:${expectation.blocker}:missing`);
}
}
for (const expectation of expectations.splitTargetProofs) {
const target = splitTargets.find(candidate => candidate.id === expectation.targetId);
if (!target) {
errors.push(`splitTargets:${expectation.targetId}:missing`);
continue;
}
const proofs = Array.isArray(target.proofs) ? target.proofs : [];
const proof = proofs.find(candidate => candidate.description?.includes(expectation.proof));
if (!proof) {
errors.push(`splitTargets:${expectation.targetId}:proof:${expectation.proof}:missing`);
} else if (proof.status !== "passed") {
errors.push(`splitTargets:${expectation.targetId}:proof:${expectation.proof}:expected passed got ${proof.status || ""}`);
}
}
if (!plugins.some(plugin => plugin.pluginId === "sai.vn" && plugin.abiFixturePath)) {
errors.push("plugins:sai.vn:abiFixturePath:missing");
@ -246,6 +284,9 @@ function parseArguments(args) {
runtimeCaptureStatuses: [],
scenarios: [],
splitTargets: [],
splitTargetStatuses: [],
splitTargetBlockers: [],
splitTargetProofs: [],
};
const optionTargets = new Map([
["--expect-pack", expectations.packs],
@ -264,6 +305,9 @@ function parseArguments(args) {
["--expect-runtime-feature", expectations.runtimeFeatures],
["--expect-runtime-command-schema", expectations.runtimeCommandSchemas],
["--expect-runtime-capture-status", expectations.runtimeCaptureStatuses],
["--expect-split-target-status", expectations.splitTargetStatuses],
["--expect-split-target-blocker", expectations.splitTargetBlockers],
["--expect-split-target-proof", expectations.splitTargetProofs],
]);
for (let index = 1; index < args.length; index += 1) {
@ -296,6 +340,12 @@ function parseArguments(args) {
target.push(parseRuntimeExpectation(value, "schema"));
} else if (option === "--expect-runtime-capture-status") {
target.push(parseRuntimeExpectation(value, "status"));
} else if (option === "--expect-split-target-status") {
target.push(parseSplitTargetExpectation(value, "status"));
} else if (option === "--expect-split-target-blocker") {
target.push(parseSplitTargetExpectation(value, "blocker"));
} else if (option === "--expect-split-target-proof") {
target.push(parseSplitTargetExpectation(value, "proof"));
} else {
target.push(value);
}
@ -341,6 +391,18 @@ function parseRuntimeExpectation(value, field) {
};
}
function parseSplitTargetExpectation(value, field) {
const separator = value.indexOf(":");
if (separator <= 0 || separator === value.length - 1) {
console.error(`Expected split target ${field} in <targetId:${field}> form, got: ${value}`);
process.exit(2);
}
return {
targetId: value.slice(0, separator),
[field]: value.slice(separator + 1),
};
}
function mergeRuntimeRecords(topLevelRuntimes, runtimeTargets) {
const byId = new Map();
for (const runtime of runtimeTargets) {