按text22收束promotion证据

结论:完成 evidence-ready / inventory-ready 双层 promotion candidate 管理,release/SDK gate 已纳入 virtual HAL promotion summary,baseline 保持 28/28/131/0,Python remap、tool DB、external user-M hard block 继续 locked。
This commit is contained in:
2026-06-18 17:20:29 +08:00
parent 014081f1f9
commit 1c94ea4527
29 changed files with 8500 additions and 121 deletions

View File

@@ -4,6 +4,7 @@ import { basename, dirname, posix, resolve } from "node:path";
import assert from "node:assert/strict";
import {
VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES,
analyzeIniRuntimeBoundaries,
createLinuxCncInterpSdk,
planSimConfigStaging,
@@ -100,6 +101,7 @@ const runtimeBoundaryNativeAlignmentSummaryPath = resolve(buildDir, "runtime-bou
const runtimeProbeGateAlignmentPath = resolve(buildDir, "runtime-probe-gate-alignment.tsv");
const nativeRuntimeProbeExecutionPlanPath = resolve(buildDir, "native-runtime-probe-execution-plan.tsv");
const nativeRuntimeProbePassEvidenceContractPath = resolve(buildDir, "native-runtime-probe-pass-evidence-contract.tsv");
const promotionCandidatesPath = resolve(buildDir, "promotion-candidates.tsv");
const blockedRuntimePromotionLockPath = resolve(buildDir, "blocked-runtime-promotion-lock.tsv");
const runtimeBoundaryPromotionReadinessPath = resolve(buildDir, "runtime-boundary-promotion-readiness.tsv");
const runtimeBoundaryPromotionBlockersPath = resolve(buildDir, "runtime-boundary-promotion-blockers.tsv");
@@ -155,6 +157,7 @@ const generatedSimConfigInventoryArtifactPaths = [
runtimeProbeGateAlignmentPath,
nativeRuntimeProbeExecutionPlanPath,
nativeRuntimeProbePassEvidenceContractPath,
promotionCandidatesPath,
blockedRuntimePromotionLockPath,
runtimeBoundaryPromotionReadinessPath,
runtimeBoundaryPromotionBlockersPath,
@@ -6087,7 +6090,7 @@ function verifyBoundaryPhaseCompletionSummaryRows(rows) {
const rowByCriterion = new Map(parsedRows.map((row) => [row.criterion, row]));
assert.equal(
rowByCriterion.get("wasm_inventory_artifact_documentation_coverage")?.count,
"54",
"55",
"WASM artifact documentation completion count must match generated artifact baseline",
);
assert.equal(
@@ -8609,7 +8612,7 @@ function verifyGeneratedArtifactDocumentationCoverage({
);
assert.equal(
artifactNames.length,
54,
55,
"generated sim-config inventory artifact list count drift",
);
assert.deepEqual(
@@ -8628,6 +8631,7 @@ function verifyGeneratedArtifactDocumentationCoverage({
"native-runtime-probe-summary.tsv",
"next-boundary-recommendations.tsv",
"next-boundary-worklist.tsv",
"promotion-candidates.tsv",
"python-remap-boundary-summary.tsv",
"python-remap-family-summary.tsv",
"python-remap-native-runtime-alignment.tsv",
@@ -8703,7 +8707,7 @@ function verifyGeneratedArtifactDocumentationCoverage({
"generated sim-config inventory artifacts must be listed in browser smoke",
);
assert.ok(
browserSmokeText.includes("wasmArtifactNames.length !== 54"),
browserSmokeText.includes("wasmArtifactNames.length !== 55"),
"browser smoke must keep generated WASM artifact fixed-count guard",
);
assert.ok(
@@ -11946,6 +11950,198 @@ function verifyHardBlockedInventorySkips(rows, pathMatrixByPath) {
}
}
function sourcePathToInventoryPath(sourcePath) {
const prefix = "linuxcnc/configs/sim/";
return sourcePath.startsWith(prefix) ? sourcePath.slice(prefix.length) : "";
}
function promotionCandidateRows({
summaryRows,
boundaryRows,
nextBoundaryRecords,
trackedMatrixByPath,
nativeByPath,
}) {
const summaryByPath = new Map(summaryRows.map((row) => {
const [
path,
inventoryStatus,
reason,
className,
nativeStatus,
nativeExpectedFailure,
] = row.split("\t");
return [path, {
path,
inventoryStatus,
reason,
className,
nativeStatus,
nativeExpectedFailure,
}];
}));
const boundaryByPath = new Map(boundaryRows.map((row) => [row.path, row]));
const nextBoundaryByBlocked = new Map(nextBoundaryRecords.map((row) => [row.blocked, row]));
const evidenceReadyRows = VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.map((candidate) => {
const inventoryPath = sourcePathToInventoryPath(candidate.gcodePath);
const summary = summaryByPath.get(inventoryPath);
const matrix = trackedMatrixByPath.get(inventoryPath);
const native = nativeByPath.get(inventoryPath);
const boundary = boundaryByPath.get(inventoryPath);
const virtualHalEvidenceReady = candidate.currentNodeInventoryStatus === "PASS" &&
candidate.currentMatrixBrowserStatus === "explicit-browser-diagnostics" &&
candidate.targetBrowserEvidence === "explicit-browser-diagnostics" &&
candidate.blockedKind === "-" &&
summary?.inventoryStatus === "PASS";
return [
"evidence-ready",
candidate.id,
inventoryPath,
sourcePathToInventoryPath(candidate.iniPath),
summary?.inventoryStatus ?? "-",
summary?.reason ?? "-",
matrix?.layer4Node ?? "-",
matrix?.layer4Browser ?? "-",
summary?.className ?? native?.class ?? "-",
summary?.nativeStatus ?? native?.status ?? "-",
summary?.nativeExpectedFailure ?? native?.expected_failure ?? "-",
matrix?.blocked ?? candidate.blockedKind ?? "-",
candidate.dependencyClass,
flagValue(virtualHalEvidenceReady),
"0",
virtualHalEvidenceReady ? "browser_release_evidence_ready_inventory_baseline_unchanged" : "virtual_hal_evidence_incomplete",
"wasm-port/tests/sdk/node/verify_sdk_surface.sh && wasm-port/tests/sdk/node/verify_project_release_gate_manifest.sh",
].map(tsvValue).join("\t");
});
const inventoryReadyRows = [...summaryByPath.values()]
.filter((row) => row.className === "main" && row.inventoryStatus === "SKIP")
.sort((left, right) => left.path.localeCompare(right.path))
.map((row) => {
const boundary = boundaryByPath.get(row.path);
const matrix = trackedMatrixByPath.get(row.path);
const boundaryWork = nextBoundaryByBlocked.get(row.reason);
const promotionAllowed = row.reason === "-" &&
boundary?.recommended_blocked === "-" &&
row.nativeStatus === "PASS";
const blockReason = promotionAllowed
? "-"
: (boundaryWork?.next_action ?? `blocked_by_${row.reason}`);
const recommendedNextCommand = promotionAllowed
? "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh"
: (boundaryWork?.required_native_proof ?? "no_direct_baseline_promotion_candidate");
return [
"inventory-ready",
row.path,
row.path,
boundary?.ini ?? "-",
row.inventoryStatus,
row.reason,
matrix?.layer4Node ?? "-",
matrix?.layer4Browser ?? "-",
row.className,
row.nativeStatus,
row.nativeExpectedFailure,
matrix?.blocked ?? row.reason,
boundary?.dependencies ?? "-",
"0",
flagValue(promotionAllowed),
blockReason,
recommendedNextCommand,
].map(tsvValue).join("\t");
});
return [...evidenceReadyRows, ...inventoryReadyRows];
}
function verifyPromotionCandidateRows(rows, summaryRows, boundaryRows) {
const expectedHeaders = [
"candidate_kind",
"candidate_id",
"path",
"ini",
"current_status",
"skip_kind",
"matrix_layer4_node",
"matrix_layer4_browser",
"class",
"native_status",
"native_expected_failure",
"blocked_kind",
"dependency_class",
"virtual_hal_evidence_ready",
"promotion_allowed",
"block_reason",
"recommended_next_command",
];
const parsedRows = parseTsv(
`${expectedHeaders.join("\t")}\n${rows.join("\n")}\n`,
expectedHeaders,
);
const expectedSkippedMain = summaryRows
.map((row) => {
const [path, inventoryStatus, reason, className] = row.split("\t");
return { path, inventoryStatus, reason, className };
})
.filter((row) => row.inventoryStatus === "SKIP" && row.className === "main")
.map((row) => row.path)
.sort();
const evidenceReadyPaths = VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES
.map((candidate) => sourcePathToInventoryPath(candidate.gcodePath))
.sort();
const boundaryByPath = new Map(boundaryRows.map((row) => [row.path, row]));
const parsedEvidenceReady = parsedRows.filter((row) => row.candidate_kind === "evidence-ready");
const parsedInventoryReady = parsedRows.filter((row) => row.candidate_kind === "inventory-ready");
assert.deepEqual(
parsedEvidenceReady.map((row) => row.path).sort(),
evidenceReadyPaths,
"promotion-candidates must cover virtual HAL evidence-ready rows",
);
assert.deepEqual(
parsedInventoryReady.map((row) => row.path).sort(),
expectedSkippedMain,
"promotion-candidates must cover every skipped main inventory candidate row",
);
assert.equal(
parsedInventoryReady.filter((row) => row.promotion_allowed === "1").length,
0,
"current baseline has no direct skipped-main inventory promotion candidate",
);
for (const row of parsedEvidenceReady) {
assert.equal(row.current_status, "PASS", `${row.path}: evidence-ready row must be a current inventory PASS`);
assert.equal(row.skip_kind, "-", `${row.path}: evidence-ready row must not have a skip kind`);
assert.equal(row.blocked_kind, "-", `${row.path}: evidence-ready row must not be hard-blocked`);
assert.equal(row.virtual_hal_evidence_ready, "1", `${row.path}: evidence-ready row lacks virtual HAL evidence`);
assert.equal(row.promotion_allowed, "0", `${row.path}: evidence-ready row must not claim inventory promotion`);
assert.equal(row.matrix_layer4_node, "INV", `${row.path}: evidence-ready row should remain Node INV`);
assert.equal(row.matrix_layer4_browser, "-", `${row.path}: evidence-ready row should record explicit diagnostics outside matrix browser REP`);
assert.equal(row.block_reason, "browser_release_evidence_ready_inventory_baseline_unchanged");
assert.ok(
row.recommended_next_command.includes("verify_sdk_surface.sh"),
`${row.path}: evidence-ready row lacks virtual HAL gate command`,
);
}
for (const row of parsedInventoryReady) {
assert.equal(row.current_status, "SKIP", `${row.path}: promotion candidate status drift`);
assert.equal(row.class, "main", `${row.path}: promotion candidate must be main class`);
assert.equal(row.blocked_kind, row.skip_kind, `${row.path}: skipped inventory blocked kind drift`);
assert.equal(row.virtual_hal_evidence_ready, "0", `${row.path}: skipped inventory row must not claim virtual HAL evidence ready`);
assert.ok(
["L4-PYTHON-REMAP", "L4-TOOL-DB", "L4-USER-M-PROCESS", "UPSTREAM-DEMO"].includes(row.skip_kind),
`${row.path}: direct promotion candidate must remain hard-blocked or upstream-demo`,
);
const boundary = boundaryByPath.get(row.path);
assert.ok(boundary, `${row.path}: promotion candidate lacks boundary evidence`);
if (row.skip_kind.startsWith("L4-")) {
assert.notEqual(row.recommended_next_command, "-", `${row.path}: blocked row lacks next proof command`);
assert.notEqual(row.block_reason, "-", `${row.path}: blocked row lacks block reason`);
}
}
return parsedRows;
}
for (const record of nativeRecords) {
const skipReason = blockedKind(record, pathMatrixByPath);
if (skipReason) {
@@ -12425,6 +12621,44 @@ writeFileSync(
].join("\n")}\n`,
);
const promotionCandidateRowsGenerated = promotionCandidateRows({
summaryRows,
boundaryRows: boundarySummaryRecords,
nextBoundaryRecords,
trackedMatrixByPath,
nativeByPath: new Map(nativeRecords.map((record) => [record.path, record])),
});
verifyPromotionCandidateRows(
promotionCandidateRowsGenerated,
summaryRows,
boundarySummaryRecords,
);
writeFileSync(
promotionCandidatesPath,
`${[
[
"candidate_kind",
"candidate_id",
"path",
"ini",
"current_status",
"skip_kind",
"matrix_layer4_node",
"matrix_layer4_browser",
"class",
"native_status",
"native_expected_failure",
"blocked_kind",
"dependency_class",
"virtual_hal_evidence_ready",
"promotion_allowed",
"block_reason",
"recommended_next_command",
].join("\t"),
...promotionCandidateRowsGenerated,
].join("\n")}\n`,
);
writeFileSync(
boundarySummaryPath,
`${[