按接续文件text31持续推进

结论:已将五项evidence expansion从API/smoke推进到real simulation diagnostics panel和release URL/INI workflow完整列表可见面;baseline保持82/82/77/0,promotionAllowed保持false。
This commit is contained in:
2026-06-20 08:26:55 +08:00
parent fab42a8bdb
commit 8a1c4699b1
13 changed files with 265 additions and 4 deletions

View File

@@ -728,6 +728,23 @@ evidence expansion report has `candidateCount=5` and `readyCandidateCount=5`,
including the two TRT rows above. The inventory baseline remains
`executed=82 passed=82 skipped=77 unexpected_fail=0`.
## 2026-06-20 Evidence Expansion UI Surface
The evidence expansion data is now visible outside the raw diagnostics JSON:
```text
real-browser-simulation-evidence-expansion-summary
evidence-expansion-full-candidate-list
evidence-expansion-full-gcode-list
```
The real simulation diagnostics panel renders `5/5 ready`, the full five-row
candidate list, source-file count, promotion lock state, and unchanged
inventory state. The project release URL workflow summary and INI workflow
overview keep their existing three-row preview fields for compatibility, and
also expose the full candidate and G-code lists so shell callers can inspect
all five ready evidence-expansion rows without opening the raw artifact.
## Boundary Statement
This analysis relies on the improved virtual HAL only for Web simulation

View File

@@ -3225,6 +3225,7 @@ export function createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel
);
const preferredEvidenceExpansion = evidenceExpansionRows[0] ?? {};
const evidenceExpansionPreviewRows = evidenceExpansionRows.slice(0, 3);
const evidenceExpansionFullRows = evidenceExpansionRows;
const ready = workflow?.ready === true;
const statusText = ready ? "Ready" : "Blocked";
const detailText = ready
@@ -3386,6 +3387,20 @@ export function createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel
).join(", ")
: "not provided",
},
{
id: "evidence-expansion-full-candidate-list",
label: "Evidence expansion full candidate list",
value: evidenceExpansionFullRows.length > 0
? evidenceExpansionFullRows.map((row) => row.id).join(", ")
: "not provided",
},
{
id: "evidence-expansion-full-gcode-list",
label: "Evidence expansion full G-code list",
value: evidenceExpansionFullRows.length > 0
? evidenceExpansionFullRows.map((row) => row.gcodePath).join(", ")
: "not provided",
},
{
id: "evidence-expansion-artifact",
label: "Evidence expansion artifact",

View File

@@ -2606,6 +2606,9 @@ export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWo
const evidenceExpansionPreviewRows = Array.isArray(evidenceExpansionRows)
? evidenceExpansionRows.slice(0, 3)
: [];
const evidenceExpansionFullRows = Array.isArray(evidenceExpansionRows)
? evidenceExpansionRows
: [];
const ready = workflow?.ready === true;
const promotionFamilyRows = (
workflow?.validation?.virtualHalPromotionFamilyRows
@@ -2800,6 +2803,20 @@ export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWo
).join(", ")
: "not provided",
},
{
id: "evidence-expansion-full-candidate-list",
label: "Evidence expansion full candidate list",
value: evidenceExpansionFullRows.length > 0
? evidenceExpansionFullRows.map((row) => row.id).join(", ")
: "not provided",
},
{
id: "evidence-expansion-full-gcode-list",
label: "Evidence expansion full G-code list",
value: evidenceExpansionFullRows.length > 0
? evidenceExpansionFullRows.map((row) => row.gcodePath).join(", ")
: "not provided",
},
{
id: "hard-block-runtime-lock",
label: "Hard-block runtime lock",

View File

@@ -1757,6 +1757,7 @@ M2
<div><span>Shortcut</span><strong data-diagnostics="shortcut">-</strong></div>
<div class="promotion-family-panel" data-promotion-family-rows></div>
<div class="promotion-candidate-panel" data-promotion-candidate-summary></div>
<div class="promotion-candidate-panel" data-evidence-expansion-summary></div>
<div class="tool-table-mini" data-axis-shell="tool-table">
<table aria-label="Loaded tool table">
<thead>
@@ -2788,6 +2789,67 @@ M2
return summary;
}
function createVirtualHalEvidenceExpansionSummary(
report = createVirtualHalSimConfigEvidenceExpansionReport(),
) {
const rows = Array.isArray(report.rows) ? report.rows : [];
const readyRows = rows.filter((row) => row.complete === true);
const blockedRows = rows.filter((row) => row.complete !== true);
const promotionAllowedRows = rows.filter((row) => row.promotionAllowed === true);
const preferredRow = rows[0] ?? null;
const ready = report.complete === true &&
report.inventoryBaselineUnchanged === true &&
report.promotionAllowed === false &&
readyRows.length === rows.length &&
blockedRows.length === 0 &&
promotionAllowedRows.length === 0;
return {
apiName: "real-browser-simulation-evidence-expansion-summary",
summaryVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
candidateCount: rows.length,
readyCandidateCount: readyRows.length,
preferredCandidateId: preferredRow?.id ?? null,
candidateIds: rows.map((row) => row.id),
gcodePaths: rows.map((row) => row.gcodePath),
sourceFileCount: new Set(rows.flatMap((row) => row.sourceFiles ?? [])).size,
promotionAllowedCount: promotionAllowedRows.length,
inventoryBaselineUnchanged: report.inventoryBaselineUnchanged === true,
rows: [
{ id: "candidate-count", label: "Expansion", value: `${readyRows.length}/${rows.length} ready` },
{ id: "preferred-candidate", label: "First case", value: preferredRow?.id ?? "missing" },
{ id: "candidate-list", label: "Cases", value: rows.map((row) => row.id).join(", ") || "missing" },
{ id: "source-files", label: "Source files", value: `${new Set(rows.flatMap((row) => row.sourceFiles ?? [])).size}` },
{ id: "promotion-allowed", label: "Allowed", value: `${promotionAllowedRows.length} baseline changes` },
{ id: "inventory-baseline", label: "Inventory", value: report.inventoryBaselineUnchanged === true ? "unchanged" : "changing" },
],
};
}
function renderEvidenceExpansionSummary(summary = createVirtualHalEvidenceExpansionSummary()) {
const container = document.querySelector("[data-evidence-expansion-summary]");
if (!container) {
return summary;
}
container.textContent = "";
document.body.dataset.evidenceExpansionReady = summary.ready ? "true" : "false";
document.body.dataset.evidenceExpansionCount = String(summary.candidateCount);
document.body.dataset.evidenceExpansionReadyCount = String(summary.readyCandidateCount);
for (const row of summary.rows) {
const item = document.createElement("div");
item.dataset.evidenceExpansionSummaryRow = row.id;
const label = document.createElement("span");
label.textContent = row.label;
const value = document.createElement("strong");
value.dataset.evidenceExpansionSummaryValue = row.id;
value.textContent = row.value;
item.append(label, value);
container.append(item);
}
return summary;
}
function renderMachineStatusDom(machineStatus) {
const statusMap = {
"spindle-state": machineStatus.spindle.state,
@@ -2828,8 +2890,10 @@ M2
renderLimitsHomeState(createVirtualHalLimitsHomeState());
renderMillturnUserMProcessState();
const promotionCandidateReport = createVirtualHalSimConfigPromotionCandidateReport();
const evidenceExpansionReport = createVirtualHalSimConfigEvidenceExpansionReport();
renderPromotionFamilyRows(promotionCandidateReport);
renderPromotionCandidateSummary(createVirtualHalPromotionCandidateSummary(promotionCandidateReport));
renderEvidenceExpansionSummary(createVirtualHalEvidenceExpansionSummary(evidenceExpansionReport));
document.querySelector("[data-axis-machine-control-state]")?.setAttribute("data-state", "ready");
return cloneVirtualHalState();
}
@@ -4333,6 +4397,7 @@ M2
getVirtualHalSimConfigSourceCoverageReport: () => createVirtualHalSimConfigSourceCoverageReport(),
getVirtualHalSimConfigPromotionCandidateReport: () => createVirtualHalSimConfigPromotionCandidateReport(),
getVirtualHalSimConfigEvidenceExpansionReport: () => createVirtualHalSimConfigEvidenceExpansionReport(),
getVirtualHalEvidenceExpansionSummary: () => renderEvidenceExpansionSummary(),
getVirtualHalPromotionCandidateSummary: () => renderPromotionCandidateSummary(),
getVirtualHalPromotionFamilyRows: () => renderPromotionFamilyRows(),
getVirtualHalSimConfigMacroLoadFixtureReport: () => createVirtualHalSimConfigMacroLoadFixtureReport(),

View File

@@ -1039,6 +1039,16 @@ TOOL_TABLE = browser-shell-tool.tbl
"3, 3, 3",
"shell workflow overview release artifact URL workflow evidence expansion source count list",
);
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "evidence-expansion-full-candidate-list")?.value,
"woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins",
"shell workflow overview release artifact URL workflow evidence expansion full candidate list",
);
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "evidence-expansion-full-gcode-list")?.value,
"linuxcnc/configs/sim/woodpecker/on_abort.ngc, linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ngc, linuxcnc/configs/sim/axis/vismach/melfa-sim/example.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc",
"shell workflow overview release artifact URL workflow evidence expansion full gcode list",
);
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowRenderResult.rowIds.includes("hard-block-runtime-lock"),
true,

View File

@@ -739,6 +739,16 @@
"3, 3, 3",
"workflow overview release artifact URL workflow evidence expansion source count list",
);
assertEqual(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "evidence-expansion-full-candidate-list")?.value,
"woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins",
"workflow overview release artifact URL workflow evidence expansion full candidate list",
);
assertEqual(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "evidence-expansion-full-gcode-list")?.value,
"linuxcnc/configs/sim/woodpecker/on_abort.ngc, linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ngc, linuxcnc/configs/sim/axis/vismach/melfa-sim/example.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc",
"workflow overview release artifact URL workflow evidence expansion full gcode list",
);
assertEqual(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "evidence-expansion-artifact")?.value,
"wasm-port/build/wasm/sim-configs-inventory/evidence-expansion-candidates.tsv",
@@ -1030,6 +1040,16 @@
"3, 3, 3",
"workflow overview fixed URL workflow form evidence expansion source count list row",
);
assertEqual(
workflowDoc.querySelector('[data-workflow-overview-release-readiness-artifact-url-workflow-value="evidence-expansion-full-candidate-list"]').textContent,
"woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins",
"workflow overview fixed URL workflow form evidence expansion full candidate list row",
);
assertEqual(
workflowDoc.querySelector('[data-workflow-overview-release-readiness-artifact-url-workflow-value="evidence-expansion-full-gcode-list"]').textContent,
"linuxcnc/configs/sim/woodpecker/on_abort.ngc, linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ngc, linuxcnc/configs/sim/axis/vismach/melfa-sim/example.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc",
"workflow overview fixed URL workflow form evidence expansion full gcode list row",
);
assertEqual(
workflowDoc.querySelector('[data-workflow-overview-release-readiness-artifact-url-workflow-value="virtual-hal-promotion-source-file-count"]').textContent,
"17 source files",

View File

@@ -698,6 +698,15 @@
promotionCandidateSummary.preferredIniPath !== "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini" ||
doc.body.dataset.promotionCandidateReady !== "true" ||
doc.body.dataset.promotionCandidatePreferred !== "qtdragon-multi-joint-on-abort" ||
doc.body.dataset.evidenceExpansionReady !== "true" ||
doc.body.dataset.evidenceExpansionCount !== "5" ||
doc.body.dataset.evidenceExpansionReadyCount !== "5" ||
api.getVirtualHalEvidenceExpansionSummary?.().ready !== true ||
api.getVirtualHalEvidenceExpansionSummary?.().candidateIds?.join(", ") !== "woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins" ||
doc.querySelector('[data-evidence-expansion-summary-value="candidate-count"]')?.textContent !== "5/5 ready" ||
doc.querySelector('[data-evidence-expansion-summary-value="candidate-list"]')?.textContent !== "woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins" ||
doc.querySelector('[data-evidence-expansion-summary-value="promotion-allowed"]')?.textContent !== "0 baseline changes" ||
doc.querySelector('[data-evidence-expansion-summary-value="inventory-baseline"]')?.textContent !== "unchanged" ||
doc.querySelector('[data-promotion-candidate-summary-value="preferred-candidate"]')?.textContent !== "qtdragon-multi-joint-on-abort" ||
doc.querySelector('[data-promotion-candidate-summary-value="candidate-layers"]')?.textContent !== "evidence-ready=8 inventory-ready=2" ||
doc.querySelector('[data-promotion-candidate-summary-value="inventory-baseline"]')?.textContent !== "82/82 pass; 77 skip" ||

View File

@@ -72,6 +72,7 @@ for (const phrase of [
"Web Simulation Improvements From Virtual HAL",
"2026-06-20 Remaining Skip Promotion Audit",
"2026-06-20 Five-Axis TRT Evidence Expansion",
"2026-06-20 Evidence Expansion UI Surface",
"remaining_skipped_main_program_promotion_allowed=0",
"direct_inventory_promotion_rows=0",
"axis/vismach/millturn/example.ngc",
@@ -80,6 +81,9 @@ for (const phrase of [
"trt-xyzac-switchkins",
"candidateCount=5",
"readyCandidateCount=5",
"real-browser-simulation-evidence-expansion-summary",
"evidence-expansion-full-candidate-list",
"evidence-expansion-full-gcode-list",
"Browser and Node simulation no longer need host `halcmd`, `halrun`, or a",
"servo-period stepping",
"8 diagnostics-ready candidates across 3 families and 17 source files",

View File

@@ -300,6 +300,14 @@ assert.equal(
readySummary.rows.find(({ id }) => id === "evidence-expansion-source-count-list")?.value,
"3, 3, 3",
);
assert.equal(
readySummary.rows.find(({ id }) => id === "evidence-expansion-full-candidate-list")?.value,
"woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins",
);
assert.equal(
readySummary.rows.find(({ id }) => id === "evidence-expansion-full-gcode-list")?.value,
"linuxcnc/configs/sim/woodpecker/on_abort.ngc, linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ngc, linuxcnc/configs/sim/axis/vismach/melfa-sim/example.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc",
);
assert.equal(
readySummary.rows.find(({ id }) => id === "evidence-expansion-artifact")?.value,
"wasm-port/build/wasm/sim-configs-inventory/evidence-expansion-candidates.tsv",
@@ -380,6 +388,8 @@ assert.deepEqual(
["evidence-expansion-candidate-list", "woodpecker-on-abort, puma-cube, melfa-example"],
["evidence-expansion-gcode-list", "linuxcnc/configs/sim/woodpecker/on_abort.ngc, linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ngc, linuxcnc/configs/sim/axis/vismach/melfa-sim/example.ngc"],
["evidence-expansion-source-count-list", "3, 3, 3"],
["evidence-expansion-full-candidate-list", "woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins"],
["evidence-expansion-full-gcode-list", "linuxcnc/configs/sim/woodpecker/on_abort.ngc, linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ngc, linuxcnc/configs/sim/axis/vismach/melfa-sim/example.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc"],
["evidence-expansion-artifact", "wasm-port/build/wasm/sim-configs-inventory/evidence-expansion-candidates.tsv"],
["promotion-candidate-allowed", "0"],
["hard-block-runtime-locked-rows", "1"],

View File

@@ -561,6 +561,8 @@ assert.deepEqual(
["evidence-expansion-candidate-list", "not provided"],
["evidence-expansion-gcode-list", "not provided"],
["evidence-expansion-source-count-list", "not provided"],
["evidence-expansion-full-candidate-list", "not provided"],
["evidence-expansion-full-gcode-list", "not provided"],
["evidence-expansion-artifact", "wasm-port/build/wasm/sim-configs-inventory/evidence-expansion-candidates.tsv"],
["promotion-candidate-allowed", "0"],
["hard-block-runtime-locked-rows", "0"],

View File

@@ -2110,6 +2110,14 @@ assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "evidence-expansion-source-count-list")?.value,
"3, 3, 3",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "evidence-expansion-full-candidate-list")?.value,
"woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "evidence-expansion-full-gcode-list")?.value,
"linuxcnc/configs/sim/woodpecker/on_abort.ngc, linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ngc, linuxcnc/configs/sim/axis/vismach/melfa-sim/example.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc, linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-baseline")?.value,
"executed=82 passed=82 skipped=77 unexpected_fail=0",
@@ -2858,7 +2866,7 @@ const releaseArtifactUrlWorkflowMountResult =
rowsNode: releaseArtifactUrlWorkflowRowsNode,
});
assert.equal(releaseArtifactUrlWorkflowRenderResult.rendered, true);
assert.equal(releaseArtifactUrlWorkflowRenderResult.rowCount, 53);
assert.equal(releaseArtifactUrlWorkflowRenderResult.rowCount, 55);
assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("browser-diagnostics"),
true,
@@ -2903,12 +2911,20 @@ assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("evidence-expansion-source-count-list"),
true,
);
assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("evidence-expansion-full-candidate-list"),
true,
);
assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("evidence-expansion-full-gcode-list"),
true,
);
assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("mount-result"),
true,
);
assert.equal(releaseArtifactUrlWorkflowMountResult.ready, true);
assert.equal(releaseArtifactUrlWorkflowMountResult.renderResult.rowCount, 53);
assert.equal(releaseArtifactUrlWorkflowMountResult.renderResult.rowCount, 55);
const releaseArtifactUrlWorkflowMissingDom = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({
artifactUrl: "/project-release-readiness.json",
fetchRef: async () => ({