收束promotion候选证据

结论:按text22铁律完成promotion-candidates双层证据管理,baseline保持28/28/131/0,Python remap、tool DB、external user-M hard block继续locked。
This commit is contained in:
2026-06-18 19:32:28 +08:00
parent f2cc1e4c57
commit 00af30c074
18 changed files with 1129 additions and 5 deletions

View File

@@ -102,6 +102,7 @@ const runtimeProbeGateAlignmentPath = resolve(buildDir, "runtime-probe-gate-alig
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 evidenceExpansionCandidatesPath = resolve(buildDir, "evidence-expansion-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");
@@ -12055,6 +12056,127 @@ function promotionCandidateRows({
return [...evidenceReadyRows, ...inventoryReadyRows];
}
function evidenceExpansionCandidateRows({
summaryRows,
boundaryRows,
trackedMatrixByPath,
}) {
const promotedEvidencePaths = new Set(
VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.map((candidate) =>
sourcePathToInventoryPath(candidate.gcodePath)
),
);
const boundaryByPath = new Map(boundaryRows.map((row) => [row.path, row]));
return summaryRows
.map((row) => {
const [
path,
inventoryStatus,
reason,
className,
nativeStatus,
nativeExpectedFailure,
] = row.split("\t");
return {
path,
inventoryStatus,
reason,
className,
nativeStatus,
nativeExpectedFailure,
};
})
.filter((row) =>
row.inventoryStatus === "PASS" &&
row.reason === "-" &&
row.className === "main" &&
row.nativeStatus === "PASS" &&
!promotedEvidencePaths.has(row.path) &&
(boundaryByPath.get(row.path)?.blocked ?? "-") === "-"
)
.sort((left, right) => left.path.localeCompare(right.path))
.map((row) => {
const boundary = boundaryByPath.get(row.path);
const matrix = trackedMatrixByPath.get(row.path);
return [
"browser-diagnostics-expansion",
row.path,
boundary?.ini ?? "-",
row.inventoryStatus,
row.reason,
matrix?.layer4Node ?? "-",
matrix?.layer4Browser ?? "-",
row.className,
row.nativeStatus,
row.nativeExpectedFailure,
matrix?.blocked ?? boundary?.blocked ?? "-",
boundary?.dependencies ?? "-",
"0",
"needs_browser_diagnostics_binding_no_inventory_baseline_change",
"wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh && wasm-port/tests/browser/verify_ini_panel_browser.sh",
].map(tsvValue).join("\t");
});
}
function verifyEvidenceExpansionCandidateRows(rows, summaryRows, boundaryRows, trackedMatrixByPath) {
const expectedHeaders = [
"candidate_kind",
"path",
"ini",
"current_status",
"skip_kind",
"matrix_layer4_node",
"matrix_layer4_browser",
"class",
"native_status",
"native_expected_failure",
"blocked_kind",
"dependency_class",
"promotion_allowed",
"block_reason",
"recommended_next_command",
];
const parsedRows = parseTsv(
`${expectedHeaders.join("\t")}\n${rows.join("\n")}\n`,
expectedHeaders,
);
const boundaryByPath = new Map(boundaryRows.map((row) => [row.path, row]));
const expectedPaths = evidenceExpansionCandidateRows({
summaryRows,
boundaryRows,
trackedMatrixByPath,
}).map((row) => row.split("\t")[1]).sort();
assert.deepEqual(
parsedRows.map((row) => row.path).sort(),
expectedPaths,
"evidence expansion candidates must cover every non-hard-block PASS main candidate outside evidence-ready",
);
assert.equal(parsedRows.length, 13, "current evidence expansion candidate count drift");
for (const row of parsedRows) {
const boundary = boundaryByPath.get(row.path);
assert.ok(boundary, `${row.path}: evidence expansion candidate lacks boundary evidence`);
assert.equal(row.candidate_kind, "browser-diagnostics-expansion", `${row.path}: candidate kind drift`);
assert.equal(row.current_status, "PASS", `${row.path}: expansion candidate must be PASS`);
assert.equal(row.skip_kind, "-", `${row.path}: expansion candidate must not have a skip kind`);
assert.equal(row.class, "main", `${row.path}: expansion candidate must be main class`);
assert.equal(row.native_status, "PASS", `${row.path}: expansion candidate must have native PASS`);
assert.equal(row.blocked_kind, "-", `${row.path}: expansion candidate must not be blocked`);
assert.equal(row.promotion_allowed, "0", `${row.path}: expansion candidate must not claim baseline promotion`);
assert.equal(
row.block_reason,
"needs_browser_diagnostics_binding_no_inventory_baseline_change",
`${row.path}: expansion candidate block reason drift`,
);
assert.ok(
row.recommended_next_command.includes("verify_release_artifact_url_workflow_browser.sh"),
`${row.path}: expansion candidate lacks browser diagnostics command`,
);
}
return parsedRows;
}
function verifyPromotionCandidateRows(rows, summaryRows, boundaryRows) {
const expectedHeaders = [
"candidate_kind",
@@ -12633,6 +12755,17 @@ verifyPromotionCandidateRows(
summaryRows,
boundarySummaryRecords,
);
const evidenceExpansionCandidateRowsGenerated = evidenceExpansionCandidateRows({
summaryRows,
boundaryRows: boundarySummaryRecords,
trackedMatrixByPath,
});
verifyEvidenceExpansionCandidateRows(
evidenceExpansionCandidateRowsGenerated,
summaryRows,
boundarySummaryRecords,
trackedMatrixByPath,
);
writeFileSync(
promotionCandidatesPath,
`${[
@@ -12659,6 +12792,30 @@ writeFileSync(
].join("\n")}\n`,
);
writeFileSync(
evidenceExpansionCandidatesPath,
`${[
[
"candidate_kind",
"path",
"ini",
"current_status",
"skip_kind",
"matrix_layer4_node",
"matrix_layer4_browser",
"class",
"native_status",
"native_expected_failure",
"blocked_kind",
"dependency_class",
"promotion_allowed",
"block_reason",
"recommended_next_command",
].join("\t"),
...evidenceExpansionCandidateRowsGenerated,
].join("\n")}\n`,
);
writeFileSync(
boundarySummaryPath,
`${[