From d789920d7f353ca94caa96c9f27cfe522a39abd2 Mon Sep 17 00:00:00 2001 From: wangdequan Date: Tue, 16 Jun 2026 13:34:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20release=20artifact=20JSON?= =?UTF-8?q?=20workflow=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_COMPLETION_TRACKER.md | 4 +- text14.txt | 62 ++++++++++++++++ wasm-port/docs/project-release-handoff.md | 3 + wasm-port/runtime/sdk/README.md | 6 ++ wasm-port/runtime/sdk/src/index.js | 1 + .../sdk/src/project-release-readiness.js | 74 +++++++++++++++++++ .../verify_project_release_handoff_docs.mjs | 2 + .../verify_project_release_gate_manifest.mjs | 50 +++++++++++++ .../tests/sdk/node/verify_sdk_surface.mjs | 12 +++ 9 files changed, 212 insertions(+), 2 deletions(-) diff --git a/PROJECT_COMPLETION_TRACKER.md b/PROJECT_COMPLETION_TRACKER.md index a1efbaa..0351c13 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 readiness artifact validation action-plan API +- Latest completed batch: project release readiness artifact JSON workflow 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/action-plan/readiness summary view-model, project release readiness report/artifact validation summary/action-plan 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/action-plan/readiness summary view-model, project release readiness report/artifact JSON workflow/artifact validation summary/action-plan 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, summarize, and report OPFS/session readiness, OPFS/session persistence summary, release readiness artifact validation/rendering/URL workflow summaries, 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 7b9dd52..6e9d757 100644 --- a/text14.txt +++ b/text14.txt @@ -3308,6 +3308,68 @@ ui_node_smokes=ok 继续只做实质能力推进。优先选择可执行 gate、SDK/API surface、或真实 browser workflow; 不要做只整理断言或局部常量化的批次。 +五十二、2026-06-16 继续执行记录:project release readiness artifact JSON workflow API + +本轮继续按“每批必须产出可调用 API、可验证 workflow、可执行 gate、或真实 UI/browser 能力”推进, +把 release readiness artifact JSON 文本处理提升为 non-throwing workflow API。外部 CI/dashboard 现在 +可以一次调用完成 parse、artifact validation、summary view-model 和 action-plan,不需要自行串联 SDK +helper 或捕获 JSON parse error。 + +完成内容: + +- `runtime/sdk/src/project-release-readiness.js` 新增: + - `createProjectReleaseReadinessArtifactJsonWorkflow()`; +- 新 workflow 返回: + - `apiName: project-release-readiness-artifact-json-workflow`; + - `workflowVersion: 1`; + - `phase/ready`; + - `parsed/parseError`; + - `artifactApiName`; + - `validation`; + - `summaryViewModel`; + - `actionPlan`; + - `missing`; + - display `rows[]`; +- ready artifact JSON 返回 parsed/ready workflow 和空 action-plan commands; +- stale artifact JSON 返回 parsed/blocked workflow 和 artifact validation action-plan; +- invalid JSON 返回 parsed=false 的 blocked workflow,不向外抛异常,并给出相同 next-command action-plan; +- `runtime/sdk/src/index.js` re-export 新 workflow API; +- `verify_project_release_gate_manifest.mjs` 覆盖 ready/stale/invalid JSON workflow; +- `verify_sdk_surface.mjs` 覆盖 SDK export、README 可发现性、ready summary 和 invalid parse; +- `runtime/sdk/README.md`、`docs/project-release-handoff.md`、`verify_project_release_handoff_docs.mjs` + 记录 JSON workflow 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 +``` + +关键输出: + +```text +project_release_gate_manifest_node_smoke=ok +sdk_surface_node_smoke=ok +project_release_handoff_docs_node_smoke=ok +``` + +下一步工作计划: + +继续只做实质能力推进。优先选择可执行 gate、SDK/API surface、或真实 browser workflow; +不要做只整理断言或局部常量化的批次。 + 五十一、2026-06-16 继续执行记录:project release readiness artifact validation action-plan API 本轮继续按“每批必须产出可调用 API、可验证 workflow、可执行 gate、或真实 UI/browser 能力”推进, diff --git a/wasm-port/docs/project-release-handoff.md b/wasm-port/docs/project-release-handoff.md index 2eef60b..596d0b2 100644 --- a/wasm-port/docs/project-release-handoff.md +++ b/wasm-port/docs/project-release-handoff.md @@ -59,6 +59,9 @@ continuation records are in `../text14.txt`. `createProjectReleaseReadinessArtifactValidationActionPlan()` turns a blocked artifact validation into the project release gate and artifact validation commands to run next, plus the missing evidence rows. + `createProjectReleaseReadinessArtifactJsonWorkflow()` is the one-call + non-throwing JSON text workflow for dashboards that need parse, validation, + summary, and action-plan output from the readiness artifact. Browser shells can also pass the JSON to `linuxCncIniPanelWorkflowOverviewApi.validateWorkflowOverviewReleaseReadinessArtifactJson()` through the workflow overview iframe and receive stable validation rows. They diff --git a/wasm-port/runtime/sdk/README.md b/wasm-port/runtime/sdk/README.md index dd4bcf1..2ae8382 100644 --- a/wasm-port/runtime/sdk/README.md +++ b/wasm-port/runtime/sdk/README.md @@ -56,6 +56,7 @@ import { createProjectReleaseGateActionPlan, createProjectReleaseGateManifest, createProjectReleaseGateResultMatrix, + createProjectReleaseReadinessArtifactJsonWorkflow, createProjectReleaseReadinessArtifactValidation, createProjectReleaseReadinessArtifactValidationActionPlan, createProjectReleaseReadinessArtifactValidationSummaryViewModel, @@ -237,6 +238,11 @@ browser shells without reinterpreting the artifact fields. artifact validation result into the exact project release gate and artifact validation commands to run next, plus the missing evidence list and shell script. Ready validations return no commands. +`createProjectReleaseReadinessArtifactJsonWorkflow()` is the non-throwing +one-call wrapper for dashboards that receive artifact JSON text. It parses, +validates, builds the validation summary, and builds the action plan. Invalid +JSON returns a blocked workflow with `parsed: false` and the same next-command +action plan instead of throwing. ## OPFS/session persistence exports diff --git a/wasm-port/runtime/sdk/src/index.js b/wasm-port/runtime/sdk/src/index.js index e58fb8d..a3641d2 100644 --- a/wasm-port/runtime/sdk/src/index.js +++ b/wasm-port/runtime/sdk/src/index.js @@ -4,6 +4,7 @@ export { createProjectReleaseGateActionPlan, createProjectReleaseGateManifest, createProjectReleaseGateResultMatrix, + createProjectReleaseReadinessArtifactJsonWorkflow, createProjectReleaseReadinessArtifactValidation, createProjectReleaseReadinessArtifactValidationActionPlan, createProjectReleaseReadinessArtifactValidationSummaryViewModel, diff --git a/wasm-port/runtime/sdk/src/project-release-readiness.js b/wasm-port/runtime/sdk/src/project-release-readiness.js index 7765998..1b4e17f 100644 --- a/wasm-port/runtime/sdk/src/project-release-readiness.js +++ b/wasm-port/runtime/sdk/src/project-release-readiness.js @@ -444,6 +444,80 @@ export function parseProjectReleaseReadinessArtifactJson(text) { return JSON.parse(String(text)); } +export function createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson = "" } = {}) { + try { + const artifact = parseProjectReleaseReadinessArtifactJson(artifactJson); + const validation = createProjectReleaseReadinessArtifactValidation(artifact); + const summaryViewModel = createProjectReleaseReadinessArtifactValidationSummaryViewModel(validation); + const actionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(validation); + return { + apiName: "project-release-readiness-artifact-json-workflow", + workflowVersion: 1, + phase: validation.ready === true ? "ready" : "blocked", + ready: validation.ready === true, + parsed: true, + parseError: null, + artifactApiName: validation.artifactApiName, + validation, + summaryViewModel, + actionPlan, + missing: validation.missing, + rows: [ + { + id: "parse", + label: "Artifact JSON parse", + value: "ready", + }, + { + id: "validation", + label: "Artifact validation", + value: validation.ready === true ? "ready" : "blocked", + }, + { + id: "next-command", + label: "Next command", + value: actionPlan.nextCommand ?? "none", + }, + ], + }; + } catch (error) { + const validation = createProjectReleaseReadinessArtifactValidation({}); + const summaryViewModel = createProjectReleaseReadinessArtifactValidationSummaryViewModel(validation); + const actionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(validation); + const parseError = error?.message ?? "artifact JSON parse error"; + return { + apiName: "project-release-readiness-artifact-json-workflow", + workflowVersion: 1, + phase: "blocked", + ready: false, + parsed: false, + parseError, + artifactApiName: null, + validation, + summaryViewModel, + actionPlan, + missing: ["artifact-json", ...validation.missing], + rows: [ + { + id: "parse", + label: "Artifact JSON parse", + value: "blocked", + }, + { + id: "validation", + label: "Artifact validation", + value: "blocked", + }, + { + id: "next-command", + label: "Next command", + value: actionPlan.nextCommand ?? "none", + }, + ], + }; + } +} + export function createProjectReleaseReadinessArtifactValidation(artifact = {}) { const artifactObject = objectOrEmpty(artifact); const releaseGate = objectOrEmpty(artifactObject.releaseGate); 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 ee34759..d09aefc 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 @@ -37,6 +37,7 @@ for (const phrase of [ "createProjectReleaseReadinessReport()", "createProjectReleaseReadinessSummaryViewModel()", "parseProjectReleaseReadinessArtifactJson()", + "createProjectReleaseReadinessArtifactJsonWorkflow()", "createProjectReleaseReadinessArtifactValidation()", "createProjectReleaseReadinessArtifactValidationActionPlan()", "createProjectReleaseReadinessArtifactValidationSummaryViewModel()", @@ -110,6 +111,7 @@ for (const phrase of [ "createProjectReleaseReadinessReport()", "createProjectReleaseReadinessSummaryViewModel()", "parseProjectReleaseReadinessArtifactJson()", + "createProjectReleaseReadinessArtifactJsonWorkflow()", "createProjectReleaseReadinessArtifactValidation()", "createProjectReleaseReadinessArtifactValidationActionPlan()", "createProjectReleaseReadinessArtifactValidationSummaryViewModel()", 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 ce98ea4..d39e15a 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 { createProjectReleaseGateActionPlan, createProjectReleaseGateManifest, createProjectReleaseGateResultMatrix, + createProjectReleaseReadinessArtifactJsonWorkflow, createProjectReleaseReadinessArtifactValidation, createProjectReleaseReadinessArtifactValidationActionPlan, createProjectReleaseReadinessArtifactValidationSummaryViewModel, @@ -180,6 +181,9 @@ const artifactValidationSummary = createProjectReleaseReadinessArtifactValidatio const artifactValidationActionPlan = createProjectReleaseReadinessArtifactValidationActionPlan( createProjectReleaseReadinessArtifactValidation(report), ); +const artifactJsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ + artifactJson: JSON.stringify(report), +}); assert.equal( artifactValidationSummary.apiName, "project-release-readiness-artifact-validation-summary-view-model", @@ -227,11 +231,35 @@ assert.deepEqual(artifactValidationActionPlan, { }, ], }); +assert.equal(artifactJsonWorkflow.apiName, "project-release-readiness-artifact-json-workflow"); +assert.equal(artifactJsonWorkflow.workflowVersion, 1); +assert.equal(artifactJsonWorkflow.phase, "ready"); +assert.equal(artifactJsonWorkflow.ready, true); +assert.equal(artifactJsonWorkflow.parsed, true); +assert.equal(artifactJsonWorkflow.parseError, null); +assert.equal(artifactJsonWorkflow.artifactApiName, "project-release-readiness-report"); +assert.equal(artifactJsonWorkflow.validation.ready, true); +assert.equal(artifactJsonWorkflow.summaryViewModel.statusLine, "Ready: Artifact evidence complete"); +assert.equal(artifactJsonWorkflow.actionPlan.commandCount, 0); +assert.deepEqual( + artifactJsonWorkflow.rows.map(({ id, value }) => [id, value]), + [ + ["parse", "ready"], + ["validation", "ready"], + ["next-command", "none"], + ], +); const staleArtifactValidationSummary = createProjectReleaseReadinessArtifactValidationSummaryViewModel( createProjectReleaseReadinessArtifactValidation({}), ); const staleArtifactValidation = createProjectReleaseReadinessArtifactValidation({}); const staleArtifactValidationActionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(staleArtifactValidation); +const staleArtifactJsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ + artifactJson: "{}", +}); +const invalidArtifactJsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ + artifactJson: "{not-json", +}); assert.equal(staleArtifactValidationSummary.phase, "blocked"); assert.match(staleArtifactValidationSummary.statusLine, /^Blocked: apiName, reportVersion/); assert.equal(staleArtifactValidationSummary.rows.find(({ id }) => id === "gate-action-plan")?.value, "missing"); @@ -254,5 +282,27 @@ assert.equal( staleArtifactValidationActionPlan.rows.find(({ id }) => id === "missing")?.value, staleArtifactValidation.missing.join(", "), ); +assert.equal(staleArtifactJsonWorkflow.parsed, true); +assert.equal(staleArtifactJsonWorkflow.ready, false); +assert.equal(staleArtifactJsonWorkflow.phase, "blocked"); +assert.equal(staleArtifactJsonWorkflow.actionPlan.commandCount, 2); +assert.deepEqual(staleArtifactJsonWorkflow.missing, staleArtifactValidation.missing); +assert.equal(invalidArtifactJsonWorkflow.parsed, false); +assert.equal(invalidArtifactJsonWorkflow.ready, false); +assert.equal(invalidArtifactJsonWorkflow.phase, "blocked"); +assert.match(invalidArtifactJsonWorkflow.parseError, /JSON/); +assert.equal(invalidArtifactJsonWorkflow.missing[0], "artifact-json"); +assert.equal( + invalidArtifactJsonWorkflow.actionPlan.nextCommand, + "wasm-port/tests/host/verify_project_release_gate.sh", +); +assert.deepEqual( + invalidArtifactJsonWorkflow.rows.map(({ id, value }) => [id, value]), + [ + ["parse", "blocked"], + ["validation", "blocked"], + ["next-command", "wasm-port/tests/host/verify_project_release_gate.sh"], + ], +); 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 37c1287..0f6face 100644 --- a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs +++ b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs @@ -37,6 +37,7 @@ import { createProjectReleaseGateActionPlan, createProjectReleaseGateManifest, createProjectReleaseGateResultMatrix, + createProjectReleaseReadinessArtifactJsonWorkflow, createProjectReleaseReadinessArtifactValidation, createProjectReleaseReadinessArtifactValidationActionPlan, createProjectReleaseReadinessArtifactValidationSummaryViewModel, @@ -94,6 +95,7 @@ const requiredExports = [ ["createProjectReleaseGateActionPlan", createProjectReleaseGateActionPlan], ["createProjectReleaseGateManifest", createProjectReleaseGateManifest], ["createProjectReleaseGateResultMatrix", createProjectReleaseGateResultMatrix], + ["createProjectReleaseReadinessArtifactJsonWorkflow", createProjectReleaseReadinessArtifactJsonWorkflow], ["createProjectReleaseReadinessArtifactValidation", createProjectReleaseReadinessArtifactValidation], [ "createProjectReleaseReadinessArtifactValidationActionPlan", @@ -343,6 +345,16 @@ assert.equal( .nextCommand, "wasm-port/tests/host/verify_project_release_gate.sh", ); +assert.equal( + createProjectReleaseReadinessArtifactJsonWorkflow({ + artifactJson: JSON.stringify(releaseReadinessArtifact), + }).summaryViewModel.statusLine, + "Ready: Artifact evidence complete", +); +assert.equal( + createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson: "not-json" }).parsed, + false, +); assert.deepEqual( createProjectReleaseReadinessArtifactValidation({}).missing, [