From eb50e6b4552a44a0bc127e1a2f28a449fbbec8cb Mon Sep 17 00:00:00 2001 From: wangdequan Date: Tue, 16 Jun 2026 06:52:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B1=95=E7=A4=BA=20INI=20=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=20shell=20workflow=20session=20readiness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_COMPLETION_TRACKER.md | 4 +- text14.txt | 64 +++++++++++++++++++ wasm-port/docs/panel-entry.md | 4 +- wasm-port/runtime/ui/ini-panel/ui-shell.js | 21 ++++++ ...anel_shell_integration_workflow_smoke.html | 12 +++- .../ui/node/verify_ini_panel_ui_shell.mjs | 29 ++++++--- 6 files changed, 120 insertions(+), 14 deletions(-) diff --git a/PROJECT_COMPLETION_TRACKER.md b/PROJECT_COMPLETION_TRACKER.md index 98bdded..c5647d3 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: INI panel readonly session readiness handoff +- Latest completed batch: INI panel shell workflow session readiness display - 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 @@ -44,7 +44,7 @@ The project is complete for the current scope when all of the following are true | 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 `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, and INI panel shell/workflow overview helpers 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 OPFS/session readiness before loading or reading WASM session state. | +| 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 and render OPFS/session readiness 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. | | Documentation/release gate | Stable for current scope | `docs/project-release-handoff.md` links README, panel entry, SDK, OPFS/session, sim-config, host/runtime, source reuse, drift, and tracker acceptance paths. | diff --git a/text14.txt b/text14.txt index 45ba53e..0c4219a 100644 --- a/text14.txt +++ b/text14.txt @@ -1844,3 +1844,67 @@ host_wasm_opfs_browser_smokes=ok 继续以实质能力推进为主。下一批可把 `sessionReadiness` 纳入 shell handoff workflow display/render rows, 让外部 shell 的已挂载 handoff 面板直接展示 ready/blocked 原因;仍保持只读,不新增控制按钮,不解析 G-code,不扩大 LinuxCNC 语义边界。 + +二十三、2026-06-16 继续执行记录:INI panel shell workflow session readiness display + +本轮继续以功能实质性推进为主,把 `sessionReadiness` 从只读 status 进一步接入 shell handoff +workflow summary/display/render rows。现在外部 shell 的已挂载 workflow 面板可以直接显示 machine-session +ready/blocked 状态与 missing 原因,不需要进入 editor 页面或读取底层 state bundle。 + +完成内容: + +- `wasm-port/runtime/ui/ini-panel/ui-shell.js` 的 + `createIniPanelShellSessionHandoffWorkflowSummary()` 新增: + - `sessionReadiness` 摘要; + - `session-readiness` display/render row; + - ready 状态显示为 `ready`; + - blocked 状态显示为 `blocked: `; +- workflow display view-model 与 render-state 自动继承新增 row; +- workflow DOM renderer/mount result 的 row count 和 row ids 覆盖新增 `session-readiness` 行; +- workflow overview embedding report 记录新的 render row count; +- `wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html` 覆盖真实 external shell + workflow summary、render-state 和 DOM mount 中的 session readiness 行; +- `wasm-port/docs/panel-entry.md` 记录 workflow summary rows 已包含 machine-session ready/blocked state; +- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch 与 Browser/UI workflow 状态; +- 未新增控制按钮; +- 未执行 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。 + +验证已通过: + +```bash +git diff --check +wasm-port/tools/verify_vendor_sync.sh +wasm-port/tools/verify_no_standalone_cnc_semantics.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh +wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh +wasm-port/tests/ui/node/verify_ui_node_smokes.sh +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh +wasm-port/tests/host/verify_host_smokes.sh +``` + +关键输出: + +```text +ini_panel_ui_shell_node_smoke=ok +ui_node_smokes=ok +browser_ini_shell_integration_workflow_smoke=ok +vendor sync up to date +standalone CNC semantics guard complete +interp_wasm_node_smoke=ok +sim_configs_wasm_node_inventory_unexpected_fail=0 +host_wasm_opfs_browser_smokes=ok +``` + +下一步工作计划: + +继续以实质能力推进为主。下一批可为 `sessionReadiness` display row 增加独立 machine-readable +workflow report/helper,或者把同一展示能力接入 workflow overview 页面自身;仍保持只读,不新增控制按钮, +不解析 G-code,不扩大 LinuxCNC 语义边界。 diff --git a/wasm-port/docs/panel-entry.md b/wasm-port/docs/panel-entry.md index 93143f1..2702886 100644 --- a/wasm-port/docs/panel-entry.md +++ b/wasm-port/docs/panel-entry.md @@ -293,8 +293,8 @@ the expected handoff status fields as a structured ready/blocked result. Use `createIniPanelShellSessionHandoffWorkflowSummary()` or `linuxCncIniPanelLaunchApi.getShellSessionHandoffWorkflowSummary()` when an outer shell needs one stable end-to-end summary that combines mount workflow, -control-page mount workflow, readonly status result, and current blocking -reasons into display rows. Use +control-page mount workflow, readonly status result, machine-session +ready/blocked state, and current blocking reasons into display rows. Use `createIniPanelShellSessionHandoffWorkflowDisplayViewModel()` or `linuxCncIniPanelLaunchApi.getShellSessionHandoffWorkflowDisplayViewModel()` when an outer shell needs that end-to-end summary compressed into stable diff --git a/wasm-port/runtime/ui/ini-panel/ui-shell.js b/wasm-port/runtime/ui/ini-panel/ui-shell.js index 62f861f..84dd3c2 100644 --- a/wasm-port/runtime/ui/ini-panel/ui-shell.js +++ b/wasm-port/runtime/ui/ini-panel/ui-shell.js @@ -1427,6 +1427,15 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({ missingStatusFields: [], }, } = {}) { + const sessionReadiness = readonlyStatusResult?.readonlyStatus?.sessionReadiness ?? null; + const sessionReadinessMissing = Array.isArray(sessionReadiness?.missing) + ? [...sessionReadiness.missing] + : []; + const sessionReadinessValue = sessionReadiness + ? `${sessionReadiness.ready ? "ready" : "blocked"}${ + sessionReadinessMissing.length > 0 ? `: ${sessionReadinessMissing.join(", ")}` : "" + }` + : "missing"; const blockingReasons = []; if (mountWorkflow?.ready !== true) { blockingReasons.push(`mount:${mountWorkflow?.phase ?? "blocked"}`); @@ -1472,6 +1481,13 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({ ? [...readonlyStatusResult.missingStatusFields] : [], }, + sessionReadiness: sessionReadiness + ? { + phase: sessionReadiness.phase ?? (sessionReadiness.ready ? "ready" : "blocked"), + ready: sessionReadiness.ready === true, + missing: sessionReadinessMissing, + } + : null, blockingReasons, rows: [ { @@ -1489,6 +1505,11 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({ label: "Readonly status workflow", value: readonlyStatusResult?.statusLine ?? "missing", }, + { + id: "session-readiness", + label: "Session readiness", + value: sessionReadinessValue, + }, { id: "readonly-status-missing-fields", label: "Readonly missing fields", diff --git a/wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html b/wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html index a8704df..1f4f40f 100644 --- a/wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html +++ b/wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html @@ -548,6 +548,16 @@ TOOL_TABLE = browser-shell-tool.tbl ); assertEqual(workflowSummaryResult.phase, "ready", "shell handoff workflow summary phase"); assertEqual(workflowSummaryResult.ready, true, "shell handoff workflow summary readiness"); + assertEqual( + workflowSummaryResult.sessionReadiness.ready, + true, + "shell handoff workflow summary session readiness", + ); + assertEqual( + workflowRenderState.rows.some((row) => row.id === "session-readiness" && row.value === "ready"), + true, + "shell handoff workflow render-state session readiness row", + ); assertEqual(workflowSummaryResult.blockingReasons.join(","), "", "shell handoff workflow summary blocking reasons"); assertEqual(workflowDisplayResult.phase, "ready", "shell handoff workflow display phase"); assertEqual(workflowDisplayResult.statusText, "Ready", "shell handoff workflow display status"); @@ -557,7 +567,7 @@ TOOL_TABLE = browser-shell-tool.tbl assertEqual(workflowRenderState.dataset.handoffScope, "workflow", "shell handoff workflow render-state scope"); assertEqual(externalWorkflowDomReadiness.ready, true, "shell handoff workflow DOM readiness"); assertEqual(workflowDomMountResult.phase, "ready", "shell handoff workflow DOM mount phase"); - assertEqual(workflowDomMountResult.renderResult.rowCount, 5, "shell handoff workflow DOM mount rows"); + assertEqual(workflowDomMountResult.renderResult.rowCount, 6, "shell handoff workflow DOM mount rows"); assertEqual( document.querySelector("[data-external-shell-workflow]").dataset.handoffScope, "workflow", diff --git a/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs b/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs index 2ff81cd..23d9167 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs @@ -1045,7 +1045,11 @@ const readonlyStatusResult = readIniPanelShellSessionHandoffStatusFromControlPag handoffSummary: shellViewModel.shellSessionHandoffSummary, readonlyStatus: createMachineSessionReadonlyStatus({ stateBundle: { overview: { phase: "loaded" } }, - workflowStatus: { lastAction: "load-session", run: { status: "not-run" } }, + workflowStatus: { + lastAction: "load-session", + run: { status: "not-run" }, + sessionReadiness: { phase: "ready", ready: true, missing: [] }, + }, controlView: { sections: [] }, }), }); @@ -1099,7 +1103,13 @@ assert.equal(workflowSummaryResult.apiName, "ini-panel-shell-session-handoff-wor assert.equal(workflowSummaryResult.summaryVersion, 1); assert.equal(workflowSummaryResult.phase, "blocked"); assert.equal(workflowSummaryResult.ready, false); -assert.equal(workflowSummaryResult.rows.length, 5); +assert.deepEqual(workflowSummaryResult.sessionReadiness, { + phase: "ready", + ready: true, + missing: [], +}); +assert.equal(workflowSummaryResult.rows.find(({ id }) => id === "session-readiness")?.value, "ready"); +assert.equal(workflowSummaryResult.rows.length, 6); assert.equal(workflowSummaryResult.blockingReasons[0], "mount:blocked"); const readyWorkflowSummaryResult = createIniPanelShellSessionHandoffWorkflowSummary({ mountWorkflow: { @@ -1120,7 +1130,7 @@ assert.equal(workflowDisplayViewModel.phase, "blocked"); assert.equal(workflowDisplayViewModel.title, "Shell handoff workflow"); assert.equal(workflowDisplayViewModel.statusText, "Blocked"); assert.equal(workflowDisplayViewModel.detailText, "mount:blocked"); -assert.equal(workflowDisplayViewModel.rows.length, 5); +assert.equal(workflowDisplayViewModel.rows.length, 6); const readyWorkflowDisplayViewModel = createIniPanelShellSessionHandoffWorkflowDisplayViewModel( readyWorkflowSummaryResult, ); @@ -1135,7 +1145,7 @@ assert.equal(workflowRenderState.renderStateVersion, 1); assert.equal(workflowRenderState.phase, "blocked"); assert.equal(workflowRenderState.statusLine, "Blocked: mount:blocked"); assert.equal(workflowRenderState.dataset.handoffScope, "workflow"); -assert.equal(workflowRenderState.rows.length, 5); +assert.equal(workflowRenderState.rows.length, 6); const readyWorkflowRenderState = createIniPanelShellSessionHandoffWorkflowRenderState( readyWorkflowDisplayViewModel, ); @@ -1178,11 +1188,12 @@ assert.deepEqual( { rendered: true, statusLine: "Blocked: mount:blocked", - rowCount: 5, + rowCount: 6, rowIds: [ "mount-workflow", "control-page-mount-workflow", "readonly-status-workflow", + "session-readiness", "readonly-status-missing-fields", "blocking-reasons", ], @@ -1204,7 +1215,7 @@ assert.equal(workflowDomMountResult.apiName, "ini-panel-shell-session-handoff-wo assert.equal(workflowDomMountResult.workflowVersion, 1); assert.equal(workflowDomMountResult.phase, "blocked"); assert.equal(workflowDomMountResult.ready, false); -assert.equal(workflowDomMountResult.renderResult.rowCount, 5); +assert.equal(workflowDomMountResult.renderResult.rowCount, 6); assert.equal(workflowDomMountResult.renderResult.dataset.handoffScope, "workflow"); assert.deepEqual(createIniPanelShellWorkflowOverviewContract(), shellViewModel.shellWorkflowOverviewContract); assert.deepEqual(createIniPanelShellWorkflowOverviewReadiness(), { @@ -1251,7 +1262,7 @@ assert.equal(workflowOverviewEmbedding.apiName, "ini-panel-shell-workflow-overvi assert.equal(workflowOverviewEmbedding.embeddingVersion, 1); assert.equal(workflowOverviewEmbedding.ready, false); assert.equal(workflowOverviewEmbedding.renderState.statusLine, "Blocked: mount:blocked"); -assert.equal(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 5); +assert.equal(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 6); assert.equal(workflowOverviewEmbedding.error, null); const workflowOverviewEmbeddingReport = createIniPanelShellWorkflowOverviewEmbeddingReport(workflowOverviewEmbedding); assert.deepEqual(workflowOverviewEmbeddingReport, { @@ -1267,7 +1278,7 @@ assert.deepEqual(workflowOverviewEmbeddingReport, { contract: shellViewModel.shellWorkflowOverviewContract, missingMethods: [], mountPhase: "blocked", - renderRowCount: 5, + renderRowCount: 6, error: null, blockingReasons: ["embedding:blocked", "mount:blocked"], rows: [ @@ -1294,7 +1305,7 @@ assert.deepEqual(workflowOverviewEmbeddingReport, { { id: "render-row-count", label: "Render row count", - value: "5", + value: "6", }, { id: "error",