From 1d383b475ce4c8f8722d4c00062041d6e24ed85f Mon Sep 17 00:00:00 2001 From: wangdequan Date: Tue, 16 Jun 2026 10:43:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=A1=B9=E7=9B=AE=E5=8F=91?= =?UTF-8?q?=E5=B8=83=20readiness=20summary=20view=20model?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_COMPLETION_TRACKER.md | 4 +- text14.txt | 57 +++++++++++++++++++ wasm-port/docs/project-release-handoff.md | 12 ++-- wasm-port/runtime/sdk/README.md | 4 ++ wasm-port/runtime/sdk/src/index.js | 1 + .../sdk/src/project-release-readiness.js | 52 +++++++++++++++++ .../verify_project_release_handoff_docs.mjs | 2 + .../verify_project_release_gate_manifest.mjs | 49 ++++++++++++++++ .../tests/sdk/node/verify_sdk_surface.mjs | 3 + 9 files changed, 177 insertions(+), 7 deletions(-) diff --git a/PROJECT_COMPLETION_TRACKER.md b/PROJECT_COMPLETION_TRACKER.md index 36ff204..1e9fb6c 100644 --- a/PROJECT_COMPLETION_TRACKER.md +++ b/PROJECT_COMPLETION_TRACKER.md @@ -9,7 +9,7 @@ turn-by-turn continuation notes and next-batch execution records. ## Current Status - Active continuation file: `text14.txt` -- Latest completed batch: project release gate result matrix SDK API +- Latest completed batch: project release readiness summary view-model API - Latest relevant commit: use `git log -1 --oneline` after each committed batch - Working tree at tracker creation: clean - Required policy: LinuxCNC remains the only CNC semantic source @@ -43,7 +43,7 @@ The project is complete for the current scope when all of the following are true | Native nc_files baseline | Stable | Last recorded Layer 1: `total 107`, `pass 101`, `expected_fail 6`, `unexpected_fail 0`. | | Native sim configs baseline | Stable | Last recorded Layer 2: `total 159`, `pass 151`, `expected_fail 8`, `unexpected_fail 0`. | | OPFS/session persistence | Stable for current scope | Browser smoke passes, SDK re-exports OPFS/session helpers including `readMachineSessionReadiness()` and `createMachineSessionPersistenceSummary()`, the UI exposes `getMachineSessionPersistenceSummary()`, and `docs/opfs-session-persistence.md` defines the project-level release gate. | -| SDK/API surface | Stable for current scope | SDK re-exports core, OPFS/session readiness/load helpers, sim-config staging, project release gate manifest/result matrix, project release readiness report/artifact validation plus URL loading workflow, INI panel entry/launcher/control-page/shell/workflow overview helpers, the session readiness workflow report, and the shell API surface inventory with a Node surface smoke. | +| SDK/API surface | Stable for current scope | SDK re-exports core, OPFS/session readiness/load helpers, sim-config staging, project release gate manifest/result matrix/readiness summary view-model, project release readiness report/artifact validation plus URL loading workflow, INI panel entry/launcher/control-page/shell/workflow overview helpers, the session readiness workflow report, and the shell API surface inventory with a Node surface smoke. | | Browser/UI workflow | Stable for current scope | Workflow overview embedding mount DOM closure is complete, and INI panel session workflows plus read-only control/shell handoff expose, render, fetch, validate, and report OPFS/session readiness, OPFS/session persistence summary, release readiness artifact validation/rendering, and API surface inventory before loading or reading WASM session state. | | Workflow overview embedding | Stable for current scope | Report/display/render, DOM contract/readiness/renderer, mount result/display/render, mount DOM contract/readiness/renderer/wrapper exist. | | Host/runtime boundary proof | Stable blocked state | Host smoke passes; runtime families remain blocked and `docs/host-runtime-boundary-handoff.md` records host readiness, promotion blockers, dispatch, and evidence gates. | diff --git a/text14.txt b/text14.txt index 932a911..defcf9d 100644 --- a/text14.txt +++ b/text14.txt @@ -3429,3 +3429,60 @@ project_release_readiness_artifact_node_smoke=ok 继续只做实质能力推进。优先选择可执行 gate、SDK/API surface、或真实 browser workflow; 不要做只整理断言或局部常量化的批次。 + +四十四、2026-06-16 继续执行记录:project release readiness summary view-model API + +本轮继续按“每批必须产出可调用 API、可验证 workflow、可执行 gate、或真实 UI/browser 能力”推进, +把 project release readiness report 进一步封装成 dashboard/UI 可直接消费的 summary view-model。外部 +CI 或页面现在可以直接读取稳定 statusLine 和 rows,而不必自己解释 gate matrix、sim-config inventory +和 blocked runtime family 字段。 + +完成内容: + +- `runtime/sdk/src/project-release-readiness.js` 新增: + - `createProjectReleaseReadinessSummaryViewModel()`; +- 新 summary view-model 返回: + - `apiName: project-release-readiness-summary-view-model`; + - `viewModelVersion: 1`; + - `phase/ready`; + - `title/statusText/detailText/statusLine`; + - rows:`gate-results`、`unknown-gates`、`sim-config-inventory`、`blocked-runtime-families`、`missing`; +- 支持 ready、waiting、promoted blocked family 三类显示状态; +- `runtime/sdk/src/index.js` re-export 新 summary API; +- `verify_project_release_gate_manifest.mjs` 覆盖 ready summary、default waiting summary、blocked promotion row; +- `verify_sdk_surface.mjs` 覆盖 SDK export 和 ready statusLine; +- `runtime/sdk/README.md`、`docs/project-release-handoff.md`、`verify_project_release_handoff_docs.mjs` + 记录 summary API; +- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch 和 SDK/API surface 状态; +- 未新增控制按钮; +- 未执行 release gate/action-plan; +- 未解析 G-code; +- 未解释 canonical events; +- 未新增 JS CNC 语义; +- 未运行 opt-in runtime probes; +- 未 promotion blocked runtime family; +- 未改变 LinuxCNC interpreter、tool、parameter、planner、kinematics、remap 或 LinuxCNC-owned + runtime semantics。 + +验证已通过(先行 targeted): + +```bash +wasm-port/tests/sdk/node/verify_project_release_gate_manifest.sh +wasm-port/tests/sdk/node/verify_sdk_surface.sh +wasm-port/tests/docs/node/verify_project_release_handoff_docs.sh +wasm-port/tests/host/verify_project_release_readiness_artifact.sh wasm-port/tests/fixtures/project-release-readiness-ready.json +``` + +关键输出: + +```text +project_release_gate_manifest_node_smoke=ok +sdk_surface_node_smoke=ok +project_release_handoff_docs_node_smoke=ok +project_release_readiness_artifact_node_smoke=ok +``` + +下一步工作计划: + +继续只做实质能力推进。优先选择可执行 gate、SDK/API surface、或真实 browser workflow; +不要做只整理断言或局部常量化的批次。 diff --git a/wasm-port/docs/project-release-handoff.md b/wasm-port/docs/project-release-handoff.md index 523d904..aea05c1 100644 --- a/wasm-port/docs/project-release-handoff.md +++ b/wasm-port/docs/project-release-handoff.md @@ -40,11 +40,13 @@ continuation records are in `../text14.txt`. observed outputs onto passed/unknown gate rows, and `createProjectReleaseReadinessReport()` for a machine-readable release readiness report covering the same manifest, result matrix, sim-config - inventory baseline, and blocked runtime families. The report helper is - evidence driven and only reports `ready: true` when the caller supplies - release gate evidence such as `project_release_gate=ok`. The project release - gate writes the same report to `build/project-release-readiness.json` and - validates it with `verify_project_release_readiness_artifact.sh`. + inventory baseline, and blocked runtime families. + `createProjectReleaseReadinessSummaryViewModel()` turns that report into + stable status text and rows for dashboards. The report helper is evidence + driven and only reports `ready: true` when the caller supplies release gate + evidence such as `project_release_gate=ok`. The project release gate writes + the same report to `build/project-release-readiness.json` and validates it + with `verify_project_release_readiness_artifact.sh`. External tools can load that artifact with `parseProjectReleaseReadinessArtifactJson()` and validate it with `createProjectReleaseReadinessArtifactValidation()`. diff --git a/wasm-port/runtime/sdk/README.md b/wasm-port/runtime/sdk/README.md index 6c4475f..d22b549 100644 --- a/wasm-port/runtime/sdk/README.md +++ b/wasm-port/runtime/sdk/README.md @@ -55,6 +55,7 @@ import { createProjectReleaseGateResultMatrix, createProjectReleaseReadinessArtifactValidation, createProjectReleaseReadinessReport, + createProjectReleaseReadinessSummaryViewModel, createSessionSnapshot, defaultMachinePaths, gcodeFilenameFromProgramPath, @@ -200,6 +201,9 @@ readiness report that embeds the same manifest and result matrix beside the sim-config inventory baseline and blocked runtime families. It is evidence driven: the default report is `ready: false` until the caller supplies observed gate output such as `project_release_gate=ok` or explicit gate results. +`createProjectReleaseReadinessSummaryViewModel()` turns the report into stable +status text, a status line, and display rows for dashboards without executing +any gate. This helper does not execute shell commands and does not inspect or implement CNC behavior. It only packages project-level release evidence and blocked diff --git a/wasm-port/runtime/sdk/src/index.js b/wasm-port/runtime/sdk/src/index.js index 9a2495d..46ce265 100644 --- a/wasm-port/runtime/sdk/src/index.js +++ b/wasm-port/runtime/sdk/src/index.js @@ -5,6 +5,7 @@ export { createProjectReleaseGateResultMatrix, createProjectReleaseReadinessArtifactValidation, createProjectReleaseReadinessReport, + createProjectReleaseReadinessSummaryViewModel, parseProjectReleaseReadinessArtifactJson, } from "./project-release-readiness.js"; export { diff --git a/wasm-port/runtime/sdk/src/project-release-readiness.js b/wasm-port/runtime/sdk/src/project-release-readiness.js index 240c651..39178fd 100644 --- a/wasm-port/runtime/sdk/src/project-release-readiness.js +++ b/wasm-port/runtime/sdk/src/project-release-readiness.js @@ -214,6 +214,58 @@ export function createProjectReleaseReadinessReport({ }; } +export function createProjectReleaseReadinessSummaryViewModel( + report = createProjectReleaseReadinessReport(), +) { + const missing = Array.isArray(report?.missing) ? report.missing : []; + const gateResultMatrix = objectOrEmpty(report?.gateResultMatrix); + const simConfigInventory = objectOrEmpty(report?.simConfigInventory); + const blockedRuntimeFamilies = arrayOrEmpty(report?.blockedRuntimeFamilies); + const promotedBlockedFamilies = arrayOrEmpty(report?.promotedBlockedFamilies); + const ready = report?.ready === true; + const statusText = ready ? "Ready" : "Waiting"; + const detailText = ready ? "No blocking reasons" : (missing.length > 0 ? missing.join(", ") : "release evidence missing"); + return { + apiName: "project-release-readiness-summary-view-model", + viewModelVersion: 1, + phase: ready ? "ready" : "waiting", + ready, + title: "Project release readiness", + statusText, + detailText, + statusLine: `${statusText}: ${detailText}`, + rows: [ + { + id: "gate-results", + label: "Release gates", + value: `${gateResultMatrix.passedCount ?? 0}/${gateResultMatrix.gateCount ?? 0} passed`, + }, + { + id: "unknown-gates", + label: "Unknown gates", + value: `${gateResultMatrix.unknownCount ?? 0}`, + }, + { + id: "sim-config-inventory", + label: "Sim config inventory", + value: `unexpected_fail=${simConfigInventory.unexpectedFail ?? "unknown"}`, + }, + { + id: "blocked-runtime-families", + label: "Blocked runtime families", + value: promotedBlockedFamilies.length > 0 + ? `promoted: ${promotedBlockedFamilies.join(", ")}` + : (blockedRuntimeFamilies.join(", ") || "none"), + }, + { + id: "missing", + label: "Missing readiness", + value: missing.length > 0 ? missing.join(", ") : "none", + }, + ], + }; +} + export function parseProjectReleaseReadinessArtifactJson(text) { return JSON.parse(String(text)); } diff --git a/wasm-port/tests/docs/node/verify_project_release_handoff_docs.mjs b/wasm-port/tests/docs/node/verify_project_release_handoff_docs.mjs index 7b90ece..b2147eb 100644 --- a/wasm-port/tests/docs/node/verify_project_release_handoff_docs.mjs +++ b/wasm-port/tests/docs/node/verify_project_release_handoff_docs.mjs @@ -34,6 +34,7 @@ for (const phrase of [ "createProjectReleaseGateManifest()", "createProjectReleaseGateResultMatrix()", "createProjectReleaseReadinessReport()", + "createProjectReleaseReadinessSummaryViewModel()", "parseProjectReleaseReadinessArtifactJson()", "createProjectReleaseReadinessArtifactValidation()", "validateWorkflowOverviewReleaseReadinessArtifactJson()", @@ -101,6 +102,7 @@ for (const phrase of [ "createProjectReleaseGateManifest()", "createProjectReleaseGateResultMatrix()", "createProjectReleaseReadinessReport()", + "createProjectReleaseReadinessSummaryViewModel()", "parseProjectReleaseReadinessArtifactJson()", "createProjectReleaseReadinessArtifactValidation()", "loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl()", diff --git a/wasm-port/tests/sdk/node/verify_project_release_gate_manifest.mjs b/wasm-port/tests/sdk/node/verify_project_release_gate_manifest.mjs index 2d9d173..b730bf1 100644 --- a/wasm-port/tests/sdk/node/verify_project_release_gate_manifest.mjs +++ b/wasm-port/tests/sdk/node/verify_project_release_gate_manifest.mjs @@ -4,6 +4,7 @@ import { createProjectReleaseGateManifest, createProjectReleaseGateResultMatrix, createProjectReleaseReadinessReport, + createProjectReleaseReadinessSummaryViewModel, } from "../../../runtime/sdk/src/index.js"; const manifest = createProjectReleaseGateManifest(); @@ -85,5 +86,53 @@ assert.equal(report.gateResultMatrix.ready, true); assert.equal(report.gateResultMatrix.passedCount, manifest.gateCount); assert.deepEqual(report.gates.map(({ id }) => id), manifest.gateIds); assert.equal(report.gates.length, manifest.gateCount); +assert.deepEqual(createProjectReleaseReadinessSummaryViewModel(report), { + apiName: "project-release-readiness-summary-view-model", + viewModelVersion: 1, + phase: "ready", + ready: true, + title: "Project release readiness", + statusText: "Ready", + detailText: "No blocking reasons", + statusLine: "Ready: No blocking reasons", + rows: [ + { + id: "gate-results", + label: "Release gates", + value: "10/10 passed", + }, + { + id: "unknown-gates", + label: "Unknown gates", + value: "0", + }, + { + id: "sim-config-inventory", + label: "Sim config inventory", + value: "unexpected_fail=0", + }, + { + id: "blocked-runtime-families", + label: "Blocked runtime families", + value: "L4-USER-M-PROCESS, L4-TOOL-DB, L4-PYTHON-REMAP", + }, + { + id: "missing", + label: "Missing readiness", + value: "none", + }, + ], +}); +assert.equal( + createProjectReleaseReadinessSummaryViewModel(createProjectReleaseReadinessReport()).statusLine, + "Waiting: project-release-gate", +); +assert.equal( + createProjectReleaseReadinessSummaryViewModel(createProjectReleaseReadinessReport({ + gateResults: Object.fromEntries(manifest.gateIds.map((id) => [id, true])), + promotedRuntimeFamilies: ["L4-TOOL-DB"], + })).rows.find(({ id }) => id === "blocked-runtime-families")?.value, + "promoted: L4-TOOL-DB", +); console.log("project_release_gate_manifest_node_smoke=ok"); diff --git a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs index 20fb0c0..d65600f 100644 --- a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs +++ b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs @@ -36,6 +36,7 @@ import { createProjectReleaseGateResultMatrix, createProjectReleaseReadinessArtifactValidation, createProjectReleaseReadinessReport, + createProjectReleaseReadinessSummaryViewModel, parseProjectReleaseReadinessArtifactJson, createSessionSnapshot, defaultMachinePaths, @@ -89,6 +90,7 @@ const requiredExports = [ ["createProjectReleaseGateResultMatrix", createProjectReleaseGateResultMatrix], ["createProjectReleaseReadinessArtifactValidation", createProjectReleaseReadinessArtifactValidation], ["createProjectReleaseReadinessReport", createProjectReleaseReadinessReport], + ["createProjectReleaseReadinessSummaryViewModel", createProjectReleaseReadinessSummaryViewModel], ["parseProjectReleaseReadinessArtifactJson", parseProjectReleaseReadinessArtifactJson], [ "validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson", @@ -220,6 +222,7 @@ assert.equal(releaseReadinessReady.ready, true); assert.equal(releaseReadinessReady.releaseGate.passed, true); assert.deepEqual(releaseReadinessReady.gateManifest, createProjectReleaseGateManifest()); assert.equal(releaseReadinessReady.gateResultMatrix.rows.length, 10); +assert.equal(createProjectReleaseReadinessSummaryViewModel(releaseReadinessReady).statusLine, "Ready: No blocking reasons"); assert.equal( createProjectReleaseGateResultMatrix({ observedOutputs: ["project_release_gate=ok"],