收口 INI 面板 persistence summary 发布门禁

This commit is contained in:
2026-06-16 09:00:29 +08:00
parent 65e95327b3
commit d3ee5d49ff
21 changed files with 1458 additions and 46 deletions

View File

@@ -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 shell API surface inventory
- Latest completed batch: project release gate validation closure
- 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
@@ -42,9 +42,9 @@ The project is complete for the current scope when all of the following are true
| Sim config inventory | Stable with skips | `executed=28`, `passed=28`, `skipped=131`, `unexpected_fail=0`; `docs/sim-configs-coverage-handoff.md` records the release-gate baseline. |
| 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 `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, INI panel 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, and report OPFS/session readiness before loading or reading WASM session state. |
| 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, 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, and report OPFS/session readiness, OPFS/session persistence summary, 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. |
| 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. |
@@ -111,9 +111,9 @@ Completion criteria:
Work items:
- Audit `runtime/sdk/src/index.js`. Done.
- Export stable helpers that external callers should use. Done for core, OPFS/session, sim-config staging, and INI panel shell/workflow overview helpers.
- Export stable helpers that external callers should use. Done for core, OPFS/session, sim-config staging, INI panel entry/launcher/control-page/shell/workflow overview helpers.
- Add or update SDK smoke for export shape and manifest compatibility. Done via `tests/sdk/node/verify_sdk_surface.sh`.
- Update `runtime/sdk/README.md` with usage examples and unsupported areas. Initial SDK surface update done; final docs pass still pending.
- Update `runtime/sdk/README.md` with usage examples and unsupported areas. Done for the current SDK surface.
Completion criteria:

View File

@@ -2135,3 +2135,639 @@ host_wasm_opfs_browser_smokes=ok
继续以实质能力推进为主。下一批可把 shell API surface inventory 渲染为 browser-visible summary
row 或挂载到 workflow overview embedding report方便验收页面直接显示 API surface 覆盖;仍保持只读,
不新增控制按钮,不解析 G-code不扩大 LinuxCNC 语义边界。
二十七、2026-06-16 继续执行记录INI panel SDK shell/control-page negotiation surface
本轮继续以功能实质性推进为主,把已经稳定存在于 UI shell 的 entry manifest、launcher link、
control-page browser API、shell integration negotiation 与 workflow overview contract helper 纳入
`runtime/sdk/src/index.js` 稳定导出。外部调用者现在可以只从 SDK 入口完成 launch/control-page/shell
协商,不需要导入 `runtime/ui/ini-panel/` 私有路径。
完成内容:
- `wasm-port/runtime/sdk/src/index.js` re-export
- `INI_PANEL_ENTRIES`
- `getIniPanelEntryManifest()`
- `getIniPanelEntryByHref()`
- `getVisibleIniPanelEntries()`
- `createIniPanelLauncherLinkViewModel()`
- `createControlPageBrowserApiSchema()`
- `createControlPageBrowserApiManifest()`
- `createControlPageBrowserApiMethods()`
- `createIniPanelShellControlPageContract()`
- `isSupportedIniPanelControlPageApiManifest()`
- `createIniPanelShellIntegrationSchema()`
- `createIniPanelShellIntegrationManifest()`
- `createIniPanelShellIntegrationReadiness()`
- `createIniPanelShellIntegrationWorkflowPlan()`
- `isSupportedIniPanelShellIntegrationManifest()`
- `createIniPanelShellWorkflowOverviewContract()`
- `wasm-port/tests/sdk/node/verify_sdk_surface.mjs` 覆盖:
- 新 SDK export shape
- SDK README drift
- entry manifest 与 visible entries 一致;
- launcher link view-model shape
- control-page manifest/schema/methods 支持判断;
- shell integration manifest/readiness/workflow plan ready
- workflow overview contract 包含 API surface inventory method
- `wasm-port/runtime/sdk/README.md` 的 stable imports 示例和 INI panel shell handoff exports
记录新增 SDK surface
- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch 与 SDK/API surface 状态;
- 未新增控制按钮;
- 未执行 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/tests/sdk/node/verify_sdk_surface.sh
wasm-port/tools/verify_vendor_sync.sh
wasm-port/tools/verify_no_standalone_cnc_semantics.sh
wasm-port/tests/ui/node/verify_ui_node_smokes.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
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
sdk_surface_node_smoke=ok
vendor sync up to date
standalone CNC semantics guard complete
ui_node_smokes=ok
interp_wasm_node_smoke=ok
sim_configs_wasm_node_inventory_unexpected_fail=0
browser_ini_launch_smoke=ok
browser_ini_workflow_overview_smoke=ok
browser_ini_shell_integration_workflow_smoke=ok
host_wasm_opfs_browser_smokes=ok
```
下一步工作计划:
继续以实质能力推进为主。下一批可把 shell API surface inventory 渲染为 browser-visible summary
row 或接入 workflow overview embedding report让验收页面直接显示 API surface 覆盖;仍保持只读,
不新增控制按钮,不解析 G-code不扩大 LinuxCNC 语义边界。
二十八、2026-06-16 继续执行记录INI panel workflow overview API surface summary row
本轮继续以功能实质性推进为主,把上一批可调用的 shell API surface inventory 接入真实 workflow
overview 和外部 shell 可见的只读 summary/render path。验收页面现在不只能够通过 API 读取
`createIniPanelShellApiSurfaceInventory()`,还会在 workflow summary DOM rows 中显示
`api-surface-inventory` 行,直接暴露 API surface 覆盖状态。
完成内容:
- `createIniPanelShellSessionHandoffWorkflowSummary()` 新增可选 `apiSurfaceInventory` 输入;
- workflow summary 输出新增:
- `apiSurfaceInventory` 摘要对象;
- `api-surface-inventory` display row
- `createIniPanelShellViewModel()` 构建流程调整为:
- 先生成基础 workflow summary
- 生成 session readiness workflow report
- 生成 shell API surface inventory
- 再生成包含 API surface inventory 行的最终 workflow summary/display/render-state
- `workflow-overview.html` 现有渲染路径自动显示 `api-surface-inventory` row
- Browser smoke 覆盖真实 DOM
- workflow overview 主 DOM row count
- `data-handoff-workflow-value="api-surface-inventory"`
- launch iframe workflow overview embedding row count
- external shell workflow overview embedding row count
- external shell 手动注入 `apiSurfaceInventory` 后的 workflow DOM mount row count
- SDK smoke 覆盖 `createIniPanelShellViewModel()` 的 workflow summary 包含
`api-surface-inventory: ready: 5 rows`
- `runtime/sdk/README.md`、`docs/panel-entry.md`、`docs/project-release-handoff.md` 记录:
- API surface inventory 可以作为 workflow summary row
- browser overview 和外部 shell 可直接显示 API 覆盖;
- 未新增控制按钮;
- 未执行 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
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/sdk/node/verify_sdk_surface.sh
wasm-port/tests/ui/node/verify_ini_panel_entry_docs.sh
wasm-port/tests/docs/node/verify_project_release_handoff_docs.sh
wasm-port/tests/ui/node/verify_ini_panel_shell_integration_manifest.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/host/verify_host_smokes.sh
```
关键输出:
```text
vendor sync up to date
standalone CNC semantics guard complete
ui_node_smokes=ok
browser_ini_workflow_overview_smoke=ok
browser_ini_shell_integration_workflow_smoke=ok
sdk_surface_node_smoke=ok
ini_panel_entry_docs_node_smoke=ok
project_release_handoff_docs_node_smoke=ok
ini_panel_shell_integration_manifest_node_smoke=ok
interp_wasm_node_smoke=ok
sim_configs_wasm_node_inventory_unexpected_fail=0
host_wasm_opfs_browser_smokes=ok
```
下一步工作计划:
继续以实质能力推进为主。下一批可把 OPFS/session persistence 也做成类似的 browser-visible
summary row 或 report汇总 machine files、session snapshot、readonly status、handoff readiness
仍保持只读,不新增控制按钮,不解析 G-code不扩大 LinuxCNC 语义边界。
二十九、2026-06-16 继续执行记录INI panel OPFS/session persistence summary
本轮继续以功能实质性推进为主,为 OPFS/session persistence 增加可复用、可由浏览器真实流程读取的
只读 summary helper。外部调用者和 INI panel 页面现在可以通过稳定 API 一次查看 machine files、
session snapshot、session readiness、session load、readonly status、handoff readiness 的汇总 rows。
完成内容:
- `panel-state-summary.js` 新增 `createMachineSessionPersistenceSummary()`
- persistence summary 输出:
- `apiName: "machine-session-persistence-summary"`
- `summaryVersion`
- `phase`
- `ready`
- `checks`
- `missing`
- `counts`
- rows
- `opfs`
- `machine-files`
- `session-snapshot`
- `session-readiness`
- `session-load`
- `readonly-status`
- `handoff-readiness`
- `app.js` 暴露:
- `linuxCncIniPanelApi.getMachineSessionPersistenceSummary()`
- legacy `window.getMachineSessionPersistenceSummary()`
- `ui-shell.js` re-export `createMachineSessionPersistenceSummary()`
- `runtime/sdk/src/index.js` re-export `createMachineSessionPersistenceSummary()`
- `verify_ini_panel_state_summary.mjs` 覆盖 ready summary 与 missing summary
- `verify_ini_panel_ui_shell.mjs` 覆盖 ui-shell export
- `verify_sdk_surface.mjs` 覆盖 SDK export 与 session-load row
- `ini_panel_smoke.html` 覆盖真实 browser OPFS/session persistence workflow 后的 summary
- `ready === true`
- machine files row
- session load row
- `runtime/sdk/README.md`、`docs/panel-entry.md`、`docs/project-release-handoff.md` 记录该 helper 和
browser API
- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch 与 OPFS/session persistence 状态;
- 未新增控制按钮;
- 未执行 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
wasm-port/tests/ui/node/verify_ini_panel_state_summary.sh
wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh
wasm-port/tests/sdk/node/verify_sdk_surface.sh
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh
wasm-port/tests/ui/node/verify_ui_node_smokes.sh
wasm-port/tests/ui/node/verify_ini_panel_entry_docs.sh
wasm-port/tests/docs/node/verify_project_release_handoff_docs.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/host/verify_host_smokes.sh
```
关键输出:
```text
vendor sync up to date
standalone CNC semantics guard complete
ini_panel_state_summary_node_smoke=ok
ini_panel_ui_shell_node_smoke=ok
sdk_surface_node_smoke=ok
browser_ini_opfs_smoke=ok
ui_node_smokes=ok
ini_panel_entry_docs_node_smoke=ok
project_release_handoff_docs_node_smoke=ok
interp_wasm_node_smoke=ok
sim_configs_wasm_node_inventory_unexpected_fail=0
host_wasm_opfs_browser_smokes=ok
```
下一步工作计划:
继续以实质能力推进为主。下一批可把 `createMachineSessionPersistenceSummary()` 接入 shell handoff
workflow summary 或 workflow overview API surface inventory让外部 shell 在一个 overview 中同时看到
API surface 与 OPFS/session persistence 状态;仍保持只读,不新增控制按钮,不解析 G-code不扩大
LinuxCNC 语义边界。
三十、2026-06-16 继续执行记录INI panel shell workflow persistence summary row
本轮继续以功能实质性推进为主,把 OPFS/session persistence summary 接入 shell handoff workflow
summary 和 workflow overview render path。外部 shell 现在可以在同一个 overview 中同时显示
`persistence-summary` 与 `api-surface-inventory` rows直接看到 OPFS/session persistence 状态和 API
surface 覆盖。
完成内容:
- `createIniPanelShellSessionHandoffWorkflowSummary()` 新增可选 `persistenceSummary` 输入;
- workflow summary 输出新增:
- `persistenceSummary` 摘要对象;
- `persistence-summary` display row
- `createIniPanelShellViewModel()` 默认生成 `shellPersistenceSummary`,并将其纳入最终
shell workflow summary/display/render-state
- `createIniPanelShellViewModel()` 暴露 `shellPersistenceSummary` 和
`createMachineSessionPersistenceSummary`
- Workflow overview browser DOM 默认显示:
- `persistence-summary: waiting: 5 missing`
- `api-surface-inventory: ready: 5 rows`
- External shell browser workflow smoke 在真实 panel/control-page workflow 后读取
`linuxCncIniPanelApi.getMachineSessionPersistenceSummary()`,再注入
`getShellSessionHandoffWorkflowSummary({ persistenceSummary })`,验证:
- `persistence-summary: ready: 7 rows`
- workflow DOM mount row count
- SDK smoke 覆盖 `createIniPanelShellViewModel()` 的 workflow summary 包含
`persistence-summary` row
- `runtime/sdk/README.md`、`docs/panel-entry.md`、`docs/project-release-handoff.md` 记录该 workflow
summary row
- `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/tests/ui/node/verify_ini_panel_entry_docs.sh
wasm-port/tests/docs/node/verify_project_release_handoff_docs.sh
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_ui_node_smokes.sh
wasm-port/tests/sdk/node/verify_sdk_surface.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_entry_docs_node_smoke=ok
project_release_handoff_docs_node_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
ui_node_smokes=ok
sdk_surface_node_smoke=ok
browser_ini_workflow_overview_smoke=ok
browser_ini_shell_integration_workflow_smoke=ok
host_wasm_opfs_browser_smokes=ok
```
下一步工作计划:
继续以实质能力推进为主。下一批可补齐 release/project docs smoke 对 `persistence-summary` row 的显式
断言,或开始收口最终提交前的全量 project release gate仍保持只读不新增控制按钮不解析 G-code
不扩大 LinuxCNC 语义边界。
三十一、2026-06-16 继续执行记录INI panel launch/workflow persistence summary API
本轮继续以功能实质性推进为主,把 `createMachineSessionPersistenceSummary()` 从 SDK/UI helper 推进为
真实 launch API 和 workflow overview API surface。外部 shell 现在可以从页面 API 直接构造 OPFS/session
persistence summary不需要导入私有模块或绕过 browser namespace。
完成内容:
- `createIniPanelLaunchApiManifest().methods` 新增 `getMachineSessionPersistenceSummary`
- `createIniPanelShellWorkflowOverviewContract().methodNames` 新增
`getWorkflowOverviewPersistenceSummary`
- `launch.html` 暴露:
- `linuxCncIniPanelLaunchApi.getMachineSessionPersistenceSummary()`
- `workflow-overview.html` 暴露:
- `linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewPersistenceSummary()`
- Browser launch smoke 覆盖 launch API persistence summary API name 与 rows
- Browser workflow overview smoke 覆盖 workflow overview API persistence summary API name 与 rows
- UI Node smoke 覆盖 launch manifest、workflow overview contract/readiness 和 shell integration manifest
- `docs/panel-entry.md`、`docs/project-release-handoff.md` 记录 launch/workflow overview API 暴露该 helper
- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch
- 未新增控制按钮;
- 未执行 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/tests/ui/node/verify_ini_panel_entry_docs.sh
wasm-port/tests/docs/node/verify_project_release_handoff_docs.sh
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_launch_api_manifest.sh
wasm-port/tests/ui/node/verify_ini_panel_shell_integration_manifest.sh
wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh
wasm-port/tests/ui/node/verify_ui_node_smokes.sh
wasm-port/tests/sdk/node/verify_sdk_surface.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_entry_docs_node_smoke=ok
project_release_handoff_docs_node_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
ini_panel_launch_api_manifest_node_smoke=ok
ini_panel_shell_integration_manifest_node_smoke=ok
ini_panel_ui_shell_node_smoke=ok
ui_node_smokes=ok
sdk_surface_node_smoke=ok
browser_ini_launch_smoke=ok
browser_ini_workflow_overview_smoke=ok
host_wasm_opfs_browser_smokes=ok
```
下一步工作计划:
继续以实质能力推进为主。下一批建议运行完整 project release gate 并根据结果只修实质性 gate 缺口;
仍保持只读,不新增控制按钮,不解析 G-code不扩大 LinuxCNC 语义边界。
三十二、2026-06-16 继续执行记录INI panel API inventory persistence summary rows
本轮继续以功能实质性推进为主,把 OPFS/session persistence summary 纳入 shell API surface inventory。
外部 shell 现在通过 `getShellApiSurfaceInventory()` 或
`getWorkflowOverviewApiSurfaceInventory()` 可以同时看到 API 方法覆盖、session readiness report rows
和 persistence summary rows。
完成内容:
- `createIniPanelShellApiSurfaceInventory()` 新增可选 `persistenceSummary` 输入;
- inventory `counts` 新增 `persistenceSummaryRows`
- inventory `apiNames` 新增 `persistenceSummary`
- inventory `entries` 新增 `persistence-summary`
- inventory `rows` 新增 `persistence-summary`
- `createIniPanelShellViewModel()` 将 `shellPersistenceSummary` 注入 `shellApiSurfaceInventory`
- Browser launch smoke 覆盖 `shellApiSurfaceInventory.counts.persistenceSummaryRows`
- Browser workflow overview smoke 覆盖 workflow overview API inventory 的 persistence summary rows
- Browser shell integration workflow smoke 在真实 panel summary 下把 persistence summary 注入
`getShellApiSurfaceInventory()` 并验证 row count
- SDK/UI node smoke 覆盖 workflow summary 的 API inventory row 从 `ready: 5 rows` 推进为
`ready: 6 rows`
- `runtime/sdk/README.md`、`docs/panel-entry.md` 记录 inventory 包含 persistence summary row counts
- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch
- 未新增控制按钮;
- 未执行 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/tests/ui/node/verify_ini_panel_entry_docs.sh
wasm-port/tests/docs/node/verify_project_release_handoff_docs.sh
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_ini_panel_shell_integration_manifest.sh
wasm-port/tests/ui/node/verify_ui_node_smokes.sh
wasm-port/tests/sdk/node/verify_sdk_surface.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_entry_docs_node_smoke=ok
project_release_handoff_docs_node_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
ini_panel_ui_shell_node_smoke=ok
ini_panel_shell_integration_manifest_node_smoke=ok
ui_node_smokes=ok
sdk_surface_node_smoke=ok
browser_ini_launch_smoke=ok
browser_ini_workflow_overview_smoke=ok
browser_ini_shell_integration_workflow_smoke=ok
host_wasm_opfs_browser_smokes=ok
```
下一步工作计划:
继续以实质能力推进为主。下一批建议运行完整 project release gate若通过则整理最终提交若失败
只修实质性 gate 缺口;仍保持只读,不新增控制按钮,不解析 G-code不扩大 LinuxCNC 语义边界。
三十三、2026-06-16 继续执行记录INI panel persistence summary display/render state
本轮继续以功能实质性推进为主,把 OPFS/session persistence summary 从数据 report 推进为可直接显示的
display view-model 和 render-state。外部 shell 现在可以拿到稳定标题、状态、明细、rows、statusLine
和 dataset 字段,不需要自行拼接 persistence 状态文案。
完成内容:
- `panel-state-summary.js` 新增:
- `createMachineSessionPersistenceDisplayViewModel()`
- `createMachineSessionPersistenceRenderState()`
- persistence render-state 输出:
- `apiName: "machine-session-persistence-render-state"`
- `renderStateVersion`
- `phase`
- `ready`
- `title`
- `statusText`
- `detailText`
- `statusLine`
- `rows`
- `dataset.persistencePhase`
- `dataset.persistenceReady`
- `dataset.persistenceScope`
- `app.js` 暴露:
- `linuxCncIniPanelApi.getMachineSessionPersistenceDisplayViewModel()`
- `linuxCncIniPanelApi.getMachineSessionPersistenceRenderState()`
- legacy window getters
- `ui-shell.js` re-export 新 display/render helpers
- `runtime/sdk/src/index.js` re-export 新 display/render helpers
- `verify_ini_panel_state_summary.mjs` 覆盖 ready display view-model、ready render-state 和 waiting
render-state
- `ini_panel_smoke.html` 覆盖真实 browser OPFS/session workflow 后的 display/render state
- `verify_sdk_surface.mjs` 覆盖 SDK export 和 render-state API name
- `docs/panel-entry.md`、`docs/project-release-handoff.md`、`runtime/sdk/README.md` 记录新 helper
- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch
- 未新增控制按钮;
- 未执行 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/tests/docs/node/verify_project_release_handoff_docs.sh
wasm-port/tests/ui/node/verify_ui_node_smokes.sh
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_state_summary.sh
wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh
wasm-port/tests/sdk/node/verify_sdk_surface.sh
wasm-port/tests/ui/node/verify_ini_panel_entry_docs.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
project_release_handoff_docs_node_smoke=ok
ui_node_smokes=ok
vendor sync up to date
standalone CNC semantics guard complete
interp_wasm_node_smoke=ok
sim_configs_wasm_node_inventory_unexpected_fail=0
ini_panel_state_summary_node_smoke=ok
ini_panel_ui_shell_node_smoke=ok
sdk_surface_node_smoke=ok
ini_panel_entry_docs_node_smoke=ok
browser_ini_opfs_smoke=ok
host_wasm_opfs_browser_smokes=ok
```
下一步工作计划:
继续以实质能力推进为主。下一批建议运行完整 project release gate若通过则整理最终提交若失败
只修实质性 gate 缺口;仍保持只读,不新增控制按钮,不解析 G-code不扩大 LinuxCNC 语义边界。
三十四、2026-06-16 继续执行记录project release gate validation closure
本轮按上一批计划运行完整 project release gate把当前 OPFS/session persistence display/render helper、
SDK/API surface、browser/UI workflow、docs smoke、host/runtime boundary smoke 一次性收口到可交付验证状态。
完成内容:
- 运行 `wasm-port/tests/host/verify_project_release_gate.sh`
- 验证当前未提交实现可通过统一发布门禁;
- 确认 browser INI panel、control page、launch、workflow overview、shell integration workflow smoke 仍通过;
- 确认 SDK surface、OPFS/session docs、sim-config coverage docs、host/runtime boundary docs、project release handoff docs
均在 host aggregate gate 中通过;
- 确认 `browser_interp_smoke=ok` 仍通过;
- 确认 sim config inventory 仍为:
- `executed=28`
- `passed=28`
- `skipped=131`
- `unexpected_fail=0`
- 确认 blocked runtime family 未 promotion
- `L4-USER-M-PROCESS`
- `L4-TOOL-DB`
- `L4-PYTHON-REMAP`
- 未新增控制按钮;
- 未执行 action-plan
- 未解析 G-code
- 未解释 canonical events
- 未新增 JS CNC 语义;
- 未运行 opt-in runtime probes
- 未改变 LinuxCNC interpreter、tool、parameter、planner、kinematics、remap 或 LinuxCNC-owned
runtime semantics。
验证已通过:
```bash
wasm-port/tests/host/verify_project_release_gate.sh
```
关键输出:
```text
vendor sync up to date
standalone CNC semantics guard complete
interp_wasm_node_smoke=ok
sim_configs_wasm_node_inventory_unexpected_fail=0
browser_ini_opfs_smoke=ok
browser_ini_control_page_smoke=ok
browser_ini_launch_smoke=ok
browser_ini_workflow_overview_smoke=ok
browser_ini_shell_integration_workflow_smoke=ok
ui_node_smokes=ok
ini_wasm_node_smoke=ok
sim_configs_wasm_node_smoke=ok
nc_files_wasm_node_smoke=ok
tp_wasm_node_smoke=ok
opfs_file_service_node_smoke=ok
sdk_surface_node_smoke=ok
opfs_session_docs_node_smoke=ok
sim_configs_coverage_docs_node_smoke=ok
host_runtime_boundary_docs_node_smoke=ok
project_release_handoff_docs_node_smoke=ok
browser_interp_smoke=ok
host_wasm_opfs_browser_smokes=ok
project_release_gate=ok
```
下一步工作计划:
整理并提交当前批次。提交后若工作树 clean则当前 scope 已达到 `PROJECT_COMPLETION_TRACKER.md`
定义的发布验证闭环;后续只在新 scope 请求或真实 LinuxCNC host runtime 可用时继续推进 blocked runtime family。

View File

@@ -76,6 +76,9 @@ import {
createIniPanelShellViewModel,
getIniPanelEntryByHref,
getVisibleIniPanelEntries,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionControlPageController,
createMachineSessionReadonlyStatus,
createMachineSessionReadonlyStatusApiManifest,
@@ -138,6 +141,17 @@ needs a read-only `ready`/`blocked` readiness report before loading a machine
session into WASM. `createMachineSessionReadinessFieldState()` and
`machineSessionReadinessLogLines()` turn that report into stable fields and
status text without parsing G-code or executing LinuxCNC behavior.
Use `createMachineSessionPersistenceSummary()` or
`linuxCncIniPanelApi.getMachineSessionPersistenceSummary()` when a browser
panel or outer shell needs one read-only OPFS/session persistence summary with
machine-file, session snapshot, session readiness, session load, readonly
status, and handoff readiness rows. The launch page exposes the same helper as
`linuxCncIniPanelLaunchApi.getMachineSessionPersistenceSummary()`, and the
workflow overview page exposes it as
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewPersistenceSummary()`.
Use `createMachineSessionPersistenceDisplayViewModel()` and
`createMachineSessionPersistenceRenderState()` when that summary needs stable
display text, rows, status line, and dataset fields for caller-owned DOM.
Use `createIniPanelShellControlPageContract()` or `controlPage.contract` when
an outer shell needs a fast contract check for `createController`,
`loadSessionState`, `readStatus`, `refresh`, `renderView`, the readonly status
@@ -306,9 +320,16 @@ the same report through
Use `createIniPanelShellApiSurfaceInventory()` or
`linuxCncIniPanelLaunchApi.getShellApiSurfaceInventory()` when an outer shell
needs a machine-readable inventory of launch, control-page, workflow overview,
persistence, and session readiness report API counts. The workflow overview
page exposes the same inventory through
persistence capabilities, session readiness report rows, and persistence
summary rows. The workflow overview page exposes the same inventory through
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewApiSurfaceInventory()`.
When provided to `createIniPanelShellSessionHandoffWorkflowSummary()`, the
inventory is also rendered as the read-only `api-surface-inventory` workflow
summary row for browser overview pages and external shells. The same workflow
summary accepts `persistenceSummary` from
`createMachineSessionPersistenceSummary()` and renders it as the
`persistence-summary` row, so a shell overview can show API coverage and
OPFS/session persistence state together.
Use
`createIniPanelShellSessionHandoffWorkflowDisplayViewModel()` or
`linuxCncIniPanelLaunchApi.getShellSessionHandoffWorkflowDisplayViewModel()`

View File

@@ -32,7 +32,16 @@ continuation records are in `../text14.txt`.
- SDK callers should import stable helpers from `runtime/sdk/src/index.js`,
including `createIniPanelShellApiSurfaceInventory()` for API discovery and
`createIniPanelShellSessionReadinessWorkflowReport()` when they need
machine-readable session readiness phase and missing reasons.
machine-readable session readiness phase and missing reasons. The workflow
overview exposes the API surface inventory as a read-only summary row.
- OPFS/session callers can use `createMachineSessionPersistenceSummary()` or
`linuxCncIniPanelApi.getMachineSessionPersistenceSummary()` to inspect
machine files, session snapshot, session readiness, session load, readonly
status, and shell handoff readiness as stable rows. Shell handoff workflow
summaries can include that report as the `persistence-summary` row beside the
API surface inventory row, and launch/workflow-overview APIs expose the same
helper for external shells. The summary also has display and render-state
helpers for caller-owned DOM.
- OPFS/session persistence is host-side storage glue. Parameter and tool-table
behavior still comes from the LinuxCNC-backed interpreter SDK calls.
- Sim-config inventory promotion remains evidence-driven and must keep

View File

@@ -23,22 +23,41 @@ Use `src/index.js` for stable imports:
```js
import {
INI_PANEL_ENTRIES,
analyzeIniRuntimeBoundaries,
createControlPageBrowserApiManifest,
createControlPageBrowserApiMethods,
createControlPageBrowserApiSchema,
createIniPanelLaunchApiManifest,
createIniPanelLauncherLinkViewModel,
createIniPanelShellApiSurfaceInventory,
createIniPanelShellControlPageContract,
createIniPanelShellIntegrationManifest,
createIniPanelShellIntegrationReadiness,
createIniPanelShellIntegrationSchema,
createIniPanelShellIntegrationWorkflowPlan,
createIniPanelShellSessionReadinessWorkflowReport,
createIniPanelShellViewModel,
createIniPanelShellWorkflowOverviewContract,
createIniPanelShellWorkflowOverviewEmbeddingMountDomContract,
createIniPanelShellWorkflowOverviewEmbeddingMountDomReadiness,
createLinuxCncIniSdk,
createLinuxCncInterpSdk,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionSnapshotPayload,
createSessionSnapshot,
defaultMachinePaths,
gcodeFilenameFromProgramPath,
gcodeProgramPath,
getIniPanelEntryByHref,
getIniPanelEntryManifest,
getOpfsRoot,
getVisibleIniPanelEntries,
isSupportedIniPanelControlPageApiManifest,
isSupportedIniPanelLaunchApiManifest,
isSupportedIniPanelShellIntegrationManifest,
loadMachineSessionFromOpfs,
loadMachineSessionSnapshot,
loadMachineTextFiles,
@@ -189,13 +208,42 @@ effects still come from the LinuxCNC-backed interpreter SDK methods they call.
The SDK entrypoint also re-exports the stable INI panel shell handoff surface
for external browser shells:
- `INI_PANEL_ENTRIES`, `getIniPanelEntryManifest()`,
`getIniPanelEntryByHref()`, `getVisibleIniPanelEntries()`, and
`createIniPanelLauncherLinkViewModel()` for discovering launch pages and
rendering shell-owned launcher links from the stable entry manifest.
- `createIniPanelLaunchApiManifest()` and
`isSupportedIniPanelLaunchApiManifest()` for launch API negotiation.
- `createControlPageBrowserApiSchema()`,
`createControlPageBrowserApiManifest()`,
`createControlPageBrowserApiMethods()`,
`createIniPanelShellControlPageContract()`, and
`isSupportedIniPanelControlPageApiManifest()` for read-only control-page API
negotiation.
- `createIniPanelShellIntegrationSchema()`,
`createIniPanelShellIntegrationManifest()`,
`createIniPanelShellIntegrationReadiness()`,
`createIniPanelShellIntegrationWorkflowPlan()`, and
`isSupportedIniPanelShellIntegrationManifest()` for checking launch and
control-page compatibility before embedding.
- `createIniPanelShellViewModel()` for a complete read-only shell integration
bundle.
- `createMachineSessionPersistenceSummary()` for a machine-readable OPFS/session
persistence summary covering machine files, session snapshot, session
readiness, session load, readonly status, and shell handoff readiness rows.
`createMachineSessionPersistenceDisplayViewModel()` and
`createMachineSessionPersistenceRenderState()` turn the summary into stable
display and render data.
`createIniPanelShellSessionHandoffWorkflowSummary()` can include this as the
read-only `persistence-summary` row.
- `createIniPanelShellWorkflowOverviewContract()` for discovering the workflow
overview iframe API contract.
- `createIniPanelShellApiSurfaceInventory()` for a machine-readable inventory
of launch, control-page, workflow overview, persistence, and session
readiness report API counts.
readiness report API counts, including persistence summary row counts.
`createIniPanelShellViewModel()` also includes
this inventory as a read-only workflow summary row so browser overview pages
and external shells can display API coverage without private imports.
- `createIniPanelShellSessionReadinessWorkflowReport()` for a machine-readable
session readiness workflow report with phase, missing reasons, status line,
and stable rows.

View File

@@ -54,12 +54,21 @@ export { loadMachineSessionFromOpfs } from "../../opfs/linuxcnc-machine-session-
export { readMachineSessionReadiness } from "../../opfs/machine-session-readiness.js";
export {
INI_PANEL_ENTRIES,
createControlPageBrowserApiManifest,
createControlPageBrowserApiMethods,
createControlPageBrowserApiSchema,
createIniPanelLaunchApiManifest,
createIniPanelLaunchApiSchema,
createIniPanelLauncherLinkViewModel,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createIniPanelShellIntegrationManifest,
createIniPanelShellIntegrationReadiness,
createIniPanelShellIntegrationSchema,
createIniPanelShellIntegrationWorkflowPlan,
createIniPanelShellControlPageContract,
createIniPanelShellSessionHandoffCompatibilityReport,
createIniPanelShellSessionHandoffPackage,
createIniPanelShellSessionHandoffPackageMountDisplayViewModel,
@@ -84,6 +93,10 @@ export {
createIniPanelShellWorkflowOverviewEmbeddingRenderState,
createIniPanelShellWorkflowOverviewEmbeddingReport,
createIniPanelShellWorkflowOverviewReadiness,
getIniPanelEntryByHref,
getIniPanelEntryManifest,
getVisibleIniPanelEntries,
isSupportedIniPanelControlPageApiManifest,
isSupportedIniPanelLaunchApiManifest,
isSupportedIniPanelShellIntegrationManifest,
isSupportedIniPanelShellSessionHandoffPackage,

View File

@@ -46,6 +46,9 @@ import {
} from "./session-workflow.js";
import {
createMachineSessionControlView,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionStateSnapshot,
createMachineSessionStateBundle,
createMachineSessionStateReport,
@@ -171,6 +174,25 @@ function getMachineSessionWorkflowStatus() {
return createMachineSessionWorkflowStatus(window.linuxCncIniPanelMachineSessionState);
}
function getMachineSessionPersistenceSummary(options = {}) {
return createMachineSessionPersistenceSummary({
state: window.linuxCncIniPanelMachineSessionState,
...options,
});
}
function getMachineSessionPersistenceDisplayViewModel(options = {}) {
return createMachineSessionPersistenceDisplayViewModel(
getMachineSessionPersistenceSummary(options),
);
}
function getMachineSessionPersistenceRenderState(options = {}) {
return createMachineSessionPersistenceRenderState(
getMachineSessionPersistenceDisplayViewModel(options),
);
}
function getMachineSessionStateBundle() {
return createMachineSessionStateBundle(window.linuxCncIniPanelMachineSessionState);
}
@@ -203,6 +225,9 @@ window.linuxCncIniPanelApi = {
getMachineSessionStateReport,
getMachineSessionStateReportExport,
getMachineSessionWorkflowStatus,
getMachineSessionPersistenceSummary,
getMachineSessionPersistenceDisplayViewModel,
getMachineSessionPersistenceRenderState,
renderMachineSessionControlView: renderCurrentMachineSessionControlView,
};
window.getMachineSessionControlView = getMachineSessionControlView;
@@ -210,6 +235,9 @@ window.getMachineSessionStateBundle = getMachineSessionStateBundle;
window.getMachineSessionStateReport = getMachineSessionStateReport;
window.getMachineSessionStateReportExport = getMachineSessionStateReportExport;
window.getMachineSessionWorkflowStatus = getMachineSessionWorkflowStatus;
window.getMachineSessionPersistenceSummary = getMachineSessionPersistenceSummary;
window.getMachineSessionPersistenceDisplayViewModel = getMachineSessionPersistenceDisplayViewModel;
window.getMachineSessionPersistenceRenderState = getMachineSessionPersistenceRenderState;
window.renderMachineSessionControlView = renderCurrentMachineSessionControlView;
window.linuxCncIniPanelMachineSessionState = panelMachineSessionState;
renderCurrentMachineSessionControlView();

View File

@@ -116,6 +116,7 @@
mountIniPanelShellSessionHandoff,
mountIniPanelShellSessionHandoffFromControlPage,
readIniPanelShellSessionHandoffStatusFromControlPage,
createMachineSessionPersistenceSummary,
createIniPanelShellSessionHandoffWorkflowSummary,
createIniPanelShellSessionReadinessWorkflowReport,
createIniPanelShellSessionHandoffWorkflowDisplayViewModel,
@@ -229,6 +230,9 @@
...(options ?? {}),
})
),
getMachineSessionPersistenceSummary: (options) => (
createMachineSessionPersistenceSummary(options)
),
getShellSessionHandoffWorkflowSummary: (options) => (
createIniPanelShellSessionHandoffWorkflowSummary(options ?? {
mountWorkflow: {

View File

@@ -156,6 +156,156 @@ export function createMachineSessionWorkflowStatus(state = {}) {
};
}
export function createMachineSessionPersistenceSummary({
state = {},
report = createMachineSessionStateReport(state),
workflowStatus = createMachineSessionWorkflowStatus(state),
readonlyStatus = null,
handoffSummary = null,
handoffWorkflowSummary = null,
} = {}) {
const readiness = report.readiness ?? {};
const machineFiles = state.machineFiles ?? {};
const session = report.session ?? {};
const loaded = report.loaded ?? {};
const sessionReadiness = report.sessionReadiness ?? workflowStatus.sessionReadiness ?? null;
const opfsReady = String(readiness.opfs ?? "").toLowerCase().includes("ready");
const machineFileLabels = [
machineFiles.iniOpfsPath || session.ini ? "ini" : null,
machineFiles.parameterOpfsPath || session.parameters ? "parameters" : null,
machineFiles.toolTableOpfsPath || session.toolTable ? "tool-table" : null,
machineFiles.gcodeOpfsPath || session.gcode ? "g-code" : null,
].filter(Boolean);
const machineFilesReady = machineFileLabels.length > 0;
const snapshotReady = Boolean(session.snapshotLabel);
const sessionReadinessReady = sessionReadiness?.ready === true;
const sessionLoadReady = Boolean(loaded.iniWasmPath);
const readonlyStatusValue = readonlyStatus
? (readonlyStatus.ready === true ? "ready" : readonlyStatus.phase ?? "available")
: "not-provided";
const handoffValue = handoffWorkflowSummary
? (handoffWorkflowSummary.ready === true ? "ready" : handoffWorkflowSummary.phase ?? "blocked")
: (
handoffSummary
? (handoffSummary.ready === true ? "ready" : handoffSummary.phase ?? "blocked")
: "not-provided"
);
const checks = {
opfs: opfsReady,
machineFiles: machineFilesReady,
sessionSnapshot: snapshotReady,
sessionReadiness: sessionReadinessReady,
sessionLoad: sessionLoadReady,
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "machine-session-persistence-summary",
summaryVersion: 1,
phase: ready ? "ready" : "waiting",
ready,
checks,
missing,
counts: {
machineFiles: machineFileLabels.length,
missing: missing.length,
},
rows: [
{
id: "opfs",
label: "OPFS",
value: readiness.opfs ?? "missing",
},
{
id: "machine-files",
label: "Machine files",
value: machineFileLabels.length > 0 ? machineFileLabels.join(", ") : "missing",
},
{
id: "session-snapshot",
label: "Session snapshot",
value: session.snapshotLabel ?? "missing",
},
{
id: "session-readiness",
label: "Session readiness",
value: sessionReadiness
? (sessionReadiness.ready ? "ready" : `blocked: ${sessionReadiness.missing?.join(", ") || "unknown"}`)
: "missing",
},
{
id: "session-load",
label: "Session load",
value: loaded.iniWasmPath ? `loaded: ${loaded.iniWasmPath}` : "missing",
},
{
id: "readonly-status",
label: "Readonly status",
value: readonlyStatusValue,
},
{
id: "handoff-readiness",
label: "Handoff readiness",
value: handoffValue,
},
],
};
}
export function createMachineSessionPersistenceDisplayViewModel(
summary = createMachineSessionPersistenceSummary(),
) {
const missing = Array.isArray(summary?.missing) ? summary.missing : [];
const rows = Array.isArray(summary?.rows)
? summary.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
return {
phase: summary?.phase === "ready" ? "ready" : "waiting",
title: "OPFS/session persistence",
statusText: summary?.ready ? "Ready" : "Waiting",
detailText: missing.length > 0 ? missing.join(", ") : "No missing persistence requirements",
rows,
};
}
export function createMachineSessionPersistenceRenderState(
displayViewModel = createMachineSessionPersistenceDisplayViewModel(),
) {
const rows = Array.isArray(displayViewModel?.rows)
? displayViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = displayViewModel?.phase === "ready" && displayViewModel?.statusText === "Ready";
const statusText = displayViewModel?.statusText ?? (ready ? "Ready" : "Waiting");
const detailText = displayViewModel?.detailText ?? "No missing persistence requirements";
return {
apiName: "machine-session-persistence-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "waiting",
ready,
title: displayViewModel?.title ?? "OPFS/session persistence",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
persistencePhase: ready ? "ready" : "waiting",
persistenceReady: ready ? "true" : "false",
persistenceScope: "opfs-session",
},
};
}
export function createMachineSessionWorkflowOverview(report = {}) {
const readiness = report.readiness ?? {};
const loaded = report.loaded ?? {};

View File

@@ -28,6 +28,9 @@ import {
createMachineSessionReadonlyStatusApiManifest,
readMachineSessionReadonlyStatus,
} from "./readonly-status-api.js";
import {
createMachineSessionPersistenceSummary,
} from "./panel-state-summary.js";
export {
controlPageStatusText,
createControlPageRefreshState,
@@ -58,6 +61,17 @@ export {
export {
renderMachineSessionControlView,
} from "./control-view-renderer.js";
export {
createMachineSessionControlView,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionStateBundle,
createMachineSessionStateReport,
createMachineSessionStateReportExport,
createMachineSessionWorkflowOverview,
createMachineSessionWorkflowStatus,
} from "./panel-state-summary.js";
export function getVisibleIniPanelEntries() {
return getIniPanelEntryManifest();
@@ -159,6 +173,7 @@ export function createIniPanelLaunchApiManifest(entries = getVisibleIniPanelEntr
"mountShellSessionHandoff",
"mountShellSessionHandoffFromControlPage",
"readShellSessionHandoffStatusFromControlPage",
"getMachineSessionPersistenceSummary",
"getShellSessionHandoffWorkflowSummary",
"getShellSessionReadinessWorkflowReport",
"getShellApiSurfaceInventory",
@@ -1428,6 +1443,8 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({
statusLine: "Blocked: readonly status unavailable",
missingStatusFields: [],
},
persistenceSummary = null,
apiSurfaceInventory = null,
} = {}) {
const sessionReadiness = readonlyStatusResult?.readonlyStatus?.sessionReadiness ?? null;
const sessionReadinessMissing = Array.isArray(sessionReadiness?.missing)
@@ -1456,6 +1473,32 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({
blockingReasons.push(`readonly-status:${readonlyDetail}`);
}
const ready = blockingReasons.length === 0;
const apiSurfaceRows = Array.isArray(apiSurfaceInventory?.rows)
? apiSurfaceInventory.rows
: [];
const apiSurfaceValue = apiSurfaceInventory
? (
apiSurfaceInventory.ready
? `ready: ${apiSurfaceRows.length} rows`
: `blocked: ${apiSurfaceInventory.phase ?? "unknown"}`
)
: "missing";
const apiSurfaceCounts = apiSurfaceInventory?.counts && typeof apiSurfaceInventory.counts === "object"
? { ...apiSurfaceInventory.counts }
: null;
const persistenceRows = Array.isArray(persistenceSummary?.rows)
? persistenceSummary.rows
: [];
const persistenceMissing = Array.isArray(persistenceSummary?.missing)
? persistenceSummary.missing
: [];
const persistenceValue = persistenceSummary
? (
persistenceSummary.ready
? `ready: ${persistenceRows.length} rows`
: `${persistenceSummary.phase ?? "waiting"}: ${persistenceMissing.length} missing`
)
: "missing";
return {
apiName: "ini-panel-shell-session-handoff-workflow-summary",
@@ -1490,6 +1533,22 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({
missing: sessionReadinessMissing,
}
: null,
apiSurfaceInventory: apiSurfaceInventory
? {
phase: apiSurfaceInventory.phase ?? (apiSurfaceInventory.ready ? "ready" : "blocked"),
ready: apiSurfaceInventory.ready === true,
counts: apiSurfaceCounts,
apiNames: apiSurfaceInventory.apiNames ? { ...apiSurfaceInventory.apiNames } : null,
}
: null,
persistenceSummary: persistenceSummary
? {
phase: persistenceSummary.phase ?? (persistenceSummary.ready ? "ready" : "waiting"),
ready: persistenceSummary.ready === true,
counts: persistenceSummary.counts ? { ...persistenceSummary.counts } : null,
missing: persistenceMissing,
}
: null,
blockingReasons,
rows: [
{
@@ -1520,6 +1579,16 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({
? readonlyStatusResult.missingStatusFields.join(", ")
: "none",
},
{
id: "persistence-summary",
label: "Persistence summary",
value: persistenceValue,
},
{
id: "api-surface-inventory",
label: "API surface inventory",
value: apiSurfaceValue,
},
{
id: "blocking-reasons",
label: "Blocking reasons",
@@ -1609,6 +1678,7 @@ export function createIniPanelShellApiSurfaceInventory({
controlPageApiManifest = createControlPageBrowserApiManifest(),
workflowOverviewContract = createIniPanelShellWorkflowOverviewContract(),
sessionReadinessWorkflowReport = createIniPanelShellSessionReadinessWorkflowReport(),
persistenceSummary = createMachineSessionPersistenceSummary(),
} = {}) {
const launchMethods = Array.isArray(launchApiManifest?.methods) ? launchApiManifest.methods : [];
const controlPageMethods = Array.isArray(controlPageApiManifest?.methods) ? controlPageApiManifest.methods : [];
@@ -1621,11 +1691,15 @@ export function createIniPanelShellApiSurfaceInventory({
const sessionReadinessRows = Array.isArray(sessionReadinessWorkflowReport?.rows)
? sessionReadinessWorkflowReport.rows
: [];
const persistenceSummaryRows = Array.isArray(persistenceSummary?.rows)
? persistenceSummary.rows
: [];
const ready = Boolean(
launchApiManifest?.apiName
&& controlPageApiManifest?.apiName
&& workflowOverviewContract?.apiName
&& sessionReadinessWorkflowReport?.apiName,
&& sessionReadinessWorkflowReport?.apiName
&& persistenceSummary?.apiName,
);
return {
@@ -1639,12 +1713,14 @@ export function createIniPanelShellApiSurfaceInventory({
workflowOverviewMethods: workflowOverviewMethods.length,
persistenceCapabilities: persistenceCapabilities.length,
sessionReadinessRows: sessionReadinessRows.length,
persistenceSummaryRows: persistenceSummaryRows.length,
},
apiNames: {
launch: launchApiManifest?.apiName ?? null,
controlPage: controlPageApiManifest?.apiName ?? null,
workflowOverview: workflowOverviewContract?.apiName ?? null,
sessionReadinessReport: sessionReadinessWorkflowReport?.apiName ?? null,
persistenceSummary: persistenceSummary?.apiName ?? null,
},
entries: [
{
@@ -1671,6 +1747,12 @@ export function createIniPanelShellApiSurfaceInventory({
apiName: sessionReadinessWorkflowReport?.apiName ?? null,
count: sessionReadinessRows.length,
},
{
id: "persistence-summary",
label: "Persistence summary",
apiName: persistenceSummary?.apiName ?? null,
count: persistenceSummaryRows.length,
},
{
id: "persistence-capabilities",
label: "Persistence capabilities",
@@ -1699,6 +1781,11 @@ export function createIniPanelShellApiSurfaceInventory({
label: "Session readiness report",
value: sessionReadinessWorkflowReport?.apiName ?? "missing",
},
{
id: "persistence-summary",
label: "Persistence summary",
value: persistenceSummary?.apiName ?? "missing",
},
{
id: "persistence-capabilities",
label: "Persistence capabilities",
@@ -1777,6 +1864,7 @@ export function createIniPanelShellWorkflowOverviewContract() {
"getWorkflowOverviewSummary",
"getWorkflowOverviewSessionReadinessReport",
"getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
@@ -2668,7 +2756,10 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
shellSessionHandoffPackageMountDisplayViewModel,
);
const shellSessionHandoffMountDomContract = createIniPanelShellSessionHandoffMountDomContract();
const shellSessionHandoffWorkflowSummary = createIniPanelShellSessionHandoffWorkflowSummary({
const shellSessionHandoffReadonlyStatusResult = readIniPanelShellSessionHandoffStatusFromControlPage({
handoffSummary: shellSessionHandoffSummary,
});
const baseShellSessionHandoffWorkflowSummary = createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow: {
phase: shellSessionHandoffPackageMountRenderState.phase,
ready: shellSessionHandoffPackageMountRenderState.ready,
@@ -2679,12 +2770,27 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
ready: shellSessionHandoffPackageMountState.ready,
statusLine: shellSessionHandoffPackageMountState.statusLine,
},
readonlyStatusResult: readIniPanelShellSessionHandoffStatusFromControlPage({
handoffSummary: shellSessionHandoffSummary,
}),
readonlyStatusResult: shellSessionHandoffReadonlyStatusResult,
});
const shellSessionHandoffWorkflowDomContract = createIniPanelShellSessionHandoffWorkflowDomContract();
const shellWorkflowOverviewContract = createIniPanelShellWorkflowOverviewContract();
const shellSessionReadinessWorkflowReport = createIniPanelShellSessionReadinessWorkflowReport({
workflowSummary: shellSessionHandoffWorkflowSummary,
workflowSummary: baseShellSessionHandoffWorkflowSummary,
});
const shellPersistenceSummary = createMachineSessionPersistenceSummary();
const shellApiSurfaceInventory = createIniPanelShellApiSurfaceInventory({
launchApiManifest: shellIntegrationManifest.launchApiManifest,
controlPageApiManifest: shellIntegrationManifest.controlPageApiManifest,
workflowOverviewContract: shellWorkflowOverviewContract,
sessionReadinessWorkflowReport: shellSessionReadinessWorkflowReport,
persistenceSummary: shellPersistenceSummary,
});
const shellSessionHandoffWorkflowSummary = createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow: baseShellSessionHandoffWorkflowSummary.mountWorkflow,
controlPageMountWorkflow: baseShellSessionHandoffWorkflowSummary.controlPageMountWorkflow,
readonlyStatusResult: shellSessionHandoffReadonlyStatusResult,
persistenceSummary: shellPersistenceSummary,
apiSurfaceInventory: shellApiSurfaceInventory,
});
const shellSessionHandoffWorkflowDisplayViewModel = createIniPanelShellSessionHandoffWorkflowDisplayViewModel(
shellSessionHandoffWorkflowSummary,
@@ -2692,14 +2798,6 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
const shellSessionHandoffWorkflowRenderState = createIniPanelShellSessionHandoffWorkflowRenderState(
shellSessionHandoffWorkflowDisplayViewModel,
);
const shellSessionHandoffWorkflowDomContract = createIniPanelShellSessionHandoffWorkflowDomContract();
const shellWorkflowOverviewContract = createIniPanelShellWorkflowOverviewContract();
const shellApiSurfaceInventory = createIniPanelShellApiSurfaceInventory({
launchApiManifest: shellIntegrationManifest.launchApiManifest,
controlPageApiManifest: shellIntegrationManifest.controlPageApiManifest,
workflowOverviewContract: shellWorkflowOverviewContract,
sessionReadinessWorkflowReport: shellSessionReadinessWorkflowReport,
});
return {
pages: entries.map(({ id, href, title }) => ({
id,
@@ -2734,6 +2832,7 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
shellSessionHandoffWorkflowRenderState,
shellSessionHandoffWorkflowDomContract,
shellWorkflowOverviewContract,
shellPersistenceSummary,
shellApiSurfaceInventory,
launchApiSchema: createIniPanelLaunchApiSchema(),
launchApiManifest: createIniPanelLaunchApiManifest(entries),
@@ -2764,6 +2863,7 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
mountShellSessionHandoffFromControlPage: mountIniPanelShellSessionHandoffFromControlPage,
readShellSessionHandoffStatusFromControlPage: readIniPanelShellSessionHandoffStatusFromControlPage,
createShellSessionHandoffWorkflowSummary: createIniPanelShellSessionHandoffWorkflowSummary,
createMachineSessionPersistenceSummary,
createShellSessionReadinessWorkflowReport: createIniPanelShellSessionReadinessWorkflowReport,
createShellApiSurfaceInventory: createIniPanelShellApiSurfaceInventory,
createShellSessionHandoffWorkflowDisplayViewModel: createIniPanelShellSessionHandoffWorkflowDisplayViewModel,

View File

@@ -96,6 +96,7 @@
createIniPanelShellWorkflowOverviewEmbeddingDomContract,
createIniPanelShellWorkflowOverviewEmbeddingDomReadiness,
mountIniPanelShellWorkflowOverviewEmbedding,
createMachineSessionPersistenceSummary,
renderIniPanelShellWorkflowOverviewEmbeddingState,
mountIniPanelShellWorkflowOverviewEmbeddingState,
createIniPanelShellWorkflowOverviewEmbeddingMountDisplayViewModel,
@@ -129,6 +130,9 @@
sessionReadinessWorkflowReport: shellViewModel.shellSessionReadinessWorkflowReport,
})
),
getWorkflowOverviewPersistenceSummary: (options) => (
createMachineSessionPersistenceSummary(options)
),
getWorkflowOverviewDomContract: (options) => (
createIniPanelShellSessionHandoffWorkflowDomContract(options)
),

View File

@@ -101,6 +101,7 @@
!launchApi?.getShellSessionHandoffPackageMountRenderState ||
!launchApi?.getShellSessionReadinessWorkflowReport ||
!launchApi?.getShellApiSurfaceInventory ||
!launchApi?.getMachineSessionPersistenceSummary ||
!launchApi?.renderShellSessionHandoffMountState ||
!launchApi?.getWorkflowOverviewContract ||
!launchApi?.getWorkflowOverviewReadiness ||
@@ -182,6 +183,7 @@
const shellSessionHandoffPackageMountRenderState = launchApi.getShellSessionHandoffPackageMountRenderState();
const shellSessionReadinessWorkflowReport = launchApi.getShellSessionReadinessWorkflowReport();
const shellApiSurfaceInventory = launchApi.getShellApiSurfaceInventory();
const launchPersistenceSummary = launchApi.getMachineSessionPersistenceSummary();
const workflowOverviewContract = launchApi.getWorkflowOverviewContract();
assertEqual(
shellIntegrationSchema.manifestVersion,
@@ -448,6 +450,21 @@
3,
"shell API surface inventory session readiness rows",
);
assertEqual(
shellApiSurfaceInventory.counts.persistenceSummaryRows,
7,
"shell API surface inventory persistence summary rows",
);
assertEqual(
launchPersistenceSummary.apiName,
"machine-session-persistence-summary",
"launch API persistence summary API",
);
assertEqual(
launchPersistenceSummary.rows.length,
7,
"launch API persistence summary rows",
);
assertEqual(
workflowOverviewContract.pageHref,
"./workflow-overview.html",
@@ -709,12 +726,12 @@
assertEqual(workflowOverviewEmbedding.pageHref, "./workflow-overview.html", "workflow overview embedding page");
assertEqual(workflowOverviewEmbedding.ready, false, "workflow overview embedding default readiness");
assertEqual(workflowOverviewEmbedding.renderState.dataset.handoffScope, "workflow", "workflow overview embedding scope");
assertEqual(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 5, "workflow overview embedding rows");
assertEqual(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 8, "workflow overview embedding rows");
assertEqual(workflowOverviewEmbedding.error, null, "workflow overview embedding error");
assertEqual(workflowOverviewEmbeddingReport.apiName, "ini-panel-shell-workflow-overview-embedding-report", "workflow overview embedding report API name");
assertEqual(workflowOverviewEmbeddingReport.ready, false, "workflow overview embedding report readiness");
assertEqual(workflowOverviewEmbeddingReport.missingMethods.join(","), "", "workflow overview embedding report missing methods");
assertEqual(workflowOverviewEmbeddingReport.renderRowCount, 5, "workflow overview embedding report row count");
assertEqual(workflowOverviewEmbeddingReport.renderRowCount, 8, "workflow overview embedding report row count");
assertEqual(workflowOverviewEmbeddingReport.rows.length, 6, "workflow overview embedding report rows");
assertEqual(workflowOverviewEmbeddingDisplay.title, "Workflow overview embedding", "workflow overview embedding display title");
assertEqual(workflowOverviewEmbeddingDisplay.statusText, "Blocked", "workflow overview embedding display status");

View File

@@ -372,11 +372,11 @@ TOOL_TABLE = browser-shell-tool.tbl
assertEqual(workflowOverviewReadiness.missing.join(","), "", "shell workflow overview iframe missing methods");
assertEqual(workflowOverviewEmbedding.apiName, "ini-panel-shell-workflow-overview-embedding", "shell workflow overview embedding API");
assertEqual(workflowOverviewEmbedding.renderState.dataset.handoffScope, "workflow", "shell workflow overview embedding scope");
assertEqual(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 5, "shell workflow overview embedding rows");
assertEqual(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 8, "shell workflow overview embedding rows");
assertEqual(workflowOverviewEmbedding.error, null, "shell workflow overview embedding error");
assertEqual(workflowOverviewEmbeddingReport.ready, false, "shell workflow overview embedding report readiness");
assertEqual(workflowOverviewEmbeddingReport.rows.length, 6, "shell workflow overview embedding report rows");
assertEqual(workflowOverviewEmbeddingReport.renderRowCount, 5, "shell workflow overview embedding report row count");
assertEqual(workflowOverviewEmbeddingReport.renderRowCount, 8, "shell workflow overview embedding report row count");
assertEqual(workflowOverviewEmbeddingReport.error, null, "shell workflow overview embedding report error");
assertEqual(workflowOverviewEmbeddingDisplay.statusText, "Blocked", "shell workflow overview embedding display status");
assertEqual(workflowOverviewEmbeddingDisplay.rows.length, 6, "shell workflow overview embedding display rows");
@@ -508,16 +508,27 @@ TOOL_TABLE = browser-shell-tool.tbl
const readonlyStatusResult = launchApi.readShellSessionHandoffStatusFromControlPage({
controlPageApi,
});
const workflowSummaryResult = launchApi.getShellSessionHandoffWorkflowSummary({
const baseWorkflowSummaryResult = launchApi.getShellSessionHandoffWorkflowSummary({
mountWorkflow: readyMountWorkflow,
controlPageMountWorkflow: readyControlPageMountWorkflow,
readonlyStatusResult,
});
const sessionReadinessWorkflowReport = launchApi.getShellSessionReadinessWorkflowReport({
workflowSummary: workflowSummaryResult,
workflowSummary: baseWorkflowSummaryResult,
});
const shellApiSurfaceInventory = launchApi.getShellApiSurfaceInventory({
sessionReadinessWorkflowReport,
persistenceSummary: panelDoc.defaultView.linuxCncIniPanelApi.getMachineSessionPersistenceSummary(),
});
const persistenceSummary = panelDoc.defaultView.linuxCncIniPanelApi.getMachineSessionPersistenceSummary({
readonlyStatus,
});
const workflowSummaryResult = launchApi.getShellSessionHandoffWorkflowSummary({
mountWorkflow: readyMountWorkflow,
controlPageMountWorkflow: readyControlPageMountWorkflow,
readonlyStatusResult,
persistenceSummary,
apiSurfaceInventory: shellApiSurfaceInventory,
});
const workflowDisplayResult = launchApi.getShellSessionHandoffWorkflowDisplayViewModel(
workflowSummaryResult,
@@ -576,6 +587,21 @@ TOOL_TABLE = browser-shell-tool.tbl
3,
"shell handoff API surface inventory session readiness rows",
);
assertEqual(
shellApiSurfaceInventory.counts.persistenceSummaryRows,
7,
"shell handoff API surface inventory persistence summary rows",
);
assertEqual(
workflowSummaryResult.rows.some((row) => row.id === "persistence-summary" && row.value === "ready: 7 rows"),
true,
"shell handoff workflow summary persistence summary row",
);
assertEqual(
workflowSummaryResult.rows.some((row) => row.id === "api-surface-inventory" && row.value === "ready: 6 rows"),
true,
"shell handoff workflow summary API surface inventory row",
);
assertEqual(
workflowSummaryResult.sessionReadiness.ready,
true,
@@ -595,7 +621,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, 6, "shell handoff workflow DOM mount rows");
assertEqual(workflowDomMountResult.renderResult.rowCount, 8, "shell handoff workflow DOM mount rows");
assertEqual(
document.querySelector("[data-external-shell-workflow]").dataset.handoffScope,
"workflow",

View File

@@ -376,6 +376,9 @@ TOOL_TABLE = browser-tool.tbl
!uiApi?.getMachineSessionStateReport ||
!uiApi?.getMachineSessionStateReportExport ||
!uiApi?.getMachineSessionWorkflowStatus ||
!uiApi?.getMachineSessionPersistenceSummary ||
!uiApi?.getMachineSessionPersistenceDisplayViewModel ||
!uiApi?.getMachineSessionPersistenceRenderState ||
!uiApi?.renderMachineSessionControlView
) {
throw new Error("INI panel API namespace did not expose state getters");
@@ -813,6 +816,44 @@ TOOL_TABLE = browser-tool.tbl
2,
"UI machine session workflow status canonical event count",
);
const machineSessionPersistenceSummary = uiApi.getMachineSessionPersistenceSummary();
assertEqual(
machineSessionPersistenceSummary.apiName,
"machine-session-persistence-summary",
"UI machine session persistence summary API name",
);
assertEqual(
machineSessionPersistenceSummary.ready,
true,
"UI machine session persistence summary readiness",
);
assertEqual(
machineSessionPersistenceSummary.rows.find((row) => row.id === "machine-files")?.value,
"ini, parameters, tool-table, g-code",
"UI machine session persistence summary machine files",
);
assertEqual(
machineSessionPersistenceSummary.rows.find((row) => row.id === "session-load")?.value,
"loaded: /work/session-machine.ini",
"UI machine session persistence summary session load",
);
const machineSessionPersistenceDisplay = uiApi.getMachineSessionPersistenceDisplayViewModel();
assertEqual(
machineSessionPersistenceDisplay.statusText,
"Ready",
"UI machine session persistence display status",
);
const machineSessionPersistenceRenderState = uiApi.getMachineSessionPersistenceRenderState();
assertEqual(
machineSessionPersistenceRenderState.statusLine,
"Ready: No missing persistence requirements",
"UI machine session persistence render-state status",
);
assertEqual(
machineSessionPersistenceRenderState.dataset.persistenceScope,
"opfs-session",
"UI machine session persistence render-state scope",
);
const machineSessionStateBundle = uiApi.getMachineSessionStateBundle();
assertEqual(
machineSessionStateBundle.report.status.lastAction,

View File

@@ -33,6 +33,7 @@
!workflowApi?.getWorkflowOverviewSummary ||
!workflowApi?.getWorkflowOverviewSessionReadinessReport ||
!workflowApi?.getWorkflowOverviewApiSurfaceInventory ||
!workflowApi?.getWorkflowOverviewPersistenceSummary ||
!workflowApi?.getWorkflowOverviewDomContract ||
!workflowApi?.getWorkflowOverviewDomReadiness ||
!workflowApi?.renderWorkflowOverview ||
@@ -60,6 +61,7 @@
const summary = workflowApi.getWorkflowOverviewSummary();
const sessionReadinessReport = workflowApi.getWorkflowOverviewSessionReadinessReport();
const apiSurfaceInventory = workflowApi.getWorkflowOverviewApiSurfaceInventory();
const persistenceSummary = workflowApi.getWorkflowOverviewPersistenceSummary();
const domContract = workflowApi.getWorkflowOverviewDomContract();
const domReadiness = workflowApi.getWorkflowOverviewDomReadiness();
const renderResult = workflowApi.renderWorkflowOverview();
@@ -93,19 +95,30 @@
"ini-panel-shell-api-surface-inventory",
"workflow overview API surface inventory API name",
);
assertEqual(apiSurfaceInventory.rows.length, 5, "workflow overview API surface inventory rows");
assertEqual(apiSurfaceInventory.rows.length, 6, "workflow overview API surface inventory rows");
assertEqual(
apiSurfaceInventory.counts.persistenceSummaryRows,
7,
"workflow overview API surface inventory persistence summary rows",
);
assertEqual(
persistenceSummary.apiName,
"machine-session-persistence-summary",
"workflow overview persistence summary API name",
);
assertEqual(persistenceSummary.rows.length, 7, "workflow overview persistence summary rows");
assertEqual(displayViewModel.title, "Shell handoff workflow", "workflow overview display title");
assertEqual(renderState.renderStateVersion, 1, "workflow overview render-state version");
assertEqual(renderState.dataset.handoffScope, "workflow", "workflow overview render-state scope");
assertEqual(domContract.selectors.mount, "[data-handoff-workflow]", "workflow overview DOM contract mount selector");
assertEqual(domReadiness.ready, true, "workflow overview DOM readiness");
assertEqual(renderResult.rendered, true, "workflow overview render result");
assertEqual(renderResult.rowCount, 5, "workflow overview render row count");
assertEqual(renderResult.rowCount, 8, "workflow overview render row count");
assertEqual(mountResult.ready, false, "workflow overview mount result readiness");
assertEqual(mountResult.renderResult.rendered, true, "workflow overview mount result rendered");
assertEqual(embeddingReport.apiName, "ini-panel-shell-workflow-overview-embedding-report", "workflow overview embedding report API name");
assertEqual(embeddingReport.ready, false, "workflow overview embedding report readiness");
assertEqual(embeddingReport.renderRowCount, 5, "workflow overview embedding report row count");
assertEqual(embeddingReport.renderRowCount, 8, "workflow overview embedding report row count");
assertEqual(embeddingReport.rows.length, 6, "workflow overview embedding report rows");
assertEqual(embeddingDisplay.title, "Workflow overview embedding", "workflow overview embedding display title");
assertEqual(embeddingDisplay.statusText, "Blocked", "workflow overview embedding display status");
@@ -191,6 +204,16 @@
true,
"workflow overview DOM blocking reasons row",
);
assertEqual(
workflowDoc.querySelector('[data-handoff-workflow-value="api-surface-inventory"]').textContent,
"ready: 6 rows",
"workflow overview DOM API surface inventory row",
);
assertEqual(
workflowDoc.querySelector('[data-handoff-workflow-value="persistence-summary"]').textContent,
"waiting: 5 missing",
"workflow overview DOM persistence summary row",
);
document.getElementById("status").textContent = "browser_ini_workflow_overview_smoke=ok";
console.log("browser_ini_workflow_overview_smoke=ok");

View File

@@ -4,22 +4,41 @@ import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import {
INI_PANEL_ENTRIES,
analyzeIniRuntimeBoundaries,
createControlPageBrowserApiManifest,
createControlPageBrowserApiMethods,
createControlPageBrowserApiSchema,
createIniPanelLaunchApiManifest,
createIniPanelLauncherLinkViewModel,
createIniPanelShellApiSurfaceInventory,
createIniPanelShellControlPageContract,
createIniPanelShellIntegrationManifest,
createIniPanelShellIntegrationReadiness,
createIniPanelShellIntegrationSchema,
createIniPanelShellIntegrationWorkflowPlan,
createIniPanelShellSessionReadinessWorkflowReport,
createIniPanelShellViewModel,
createIniPanelShellWorkflowOverviewContract,
createIniPanelShellWorkflowOverviewEmbeddingMountDomContract,
createIniPanelShellWorkflowOverviewEmbeddingMountDomReadiness,
createLinuxCncIniSdk,
createLinuxCncInterpSdk,
createMachineSessionSnapshotPayload,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createSessionSnapshot,
defaultMachinePaths,
gcodeFilenameFromProgramPath,
gcodeProgramPath,
getIniPanelEntryByHref,
getIniPanelEntryManifest,
getOpfsRoot,
getVisibleIniPanelEntries,
isSupportedIniPanelControlPageApiManifest,
isSupportedIniPanelLaunchApiManifest,
isSupportedIniPanelShellIntegrationManifest,
loadMachineSessionFromOpfs,
loadMachineSessionSnapshot,
loadMachineTextFiles,
@@ -56,6 +75,13 @@ const requiredExports = [
["planIniFileContextStaging", planIniFileContextStaging],
["planSimConfigStaging", planSimConfigStaging],
["analyzeIniRuntimeBoundaries", analyzeIniRuntimeBoundaries],
["getIniPanelEntryManifest", getIniPanelEntryManifest],
["getIniPanelEntryByHref", getIniPanelEntryByHref],
["getVisibleIniPanelEntries", getVisibleIniPanelEntries],
["createIniPanelLauncherLinkViewModel", createIniPanelLauncherLinkViewModel],
["createMachineSessionPersistenceDisplayViewModel", createMachineSessionPersistenceDisplayViewModel],
["createMachineSessionPersistenceRenderState", createMachineSessionPersistenceRenderState],
["createMachineSessionPersistenceSummary", createMachineSessionPersistenceSummary],
["getOpfsRoot", getOpfsRoot],
["saveTextFile", saveTextFile],
["loadTextFile", loadTextFile],
@@ -80,11 +106,22 @@ const requiredExports = [
["loadMachineToolTableFromOpfs", loadMachineToolTableFromOpfs],
["loadMachineSessionFromOpfs", loadMachineSessionFromOpfs],
["readMachineSessionReadiness", readMachineSessionReadiness],
["createControlPageBrowserApiSchema", createControlPageBrowserApiSchema],
["createControlPageBrowserApiManifest", createControlPageBrowserApiManifest],
["createControlPageBrowserApiMethods", createControlPageBrowserApiMethods],
["createIniPanelShellControlPageContract", createIniPanelShellControlPageContract],
["isSupportedIniPanelControlPageApiManifest", isSupportedIniPanelControlPageApiManifest],
["createIniPanelLaunchApiManifest", createIniPanelLaunchApiManifest],
["isSupportedIniPanelLaunchApiManifest", isSupportedIniPanelLaunchApiManifest],
["createIniPanelShellIntegrationSchema", createIniPanelShellIntegrationSchema],
["createIniPanelShellIntegrationManifest", createIniPanelShellIntegrationManifest],
["createIniPanelShellIntegrationReadiness", createIniPanelShellIntegrationReadiness],
["createIniPanelShellIntegrationWorkflowPlan", createIniPanelShellIntegrationWorkflowPlan],
["isSupportedIniPanelShellIntegrationManifest", isSupportedIniPanelShellIntegrationManifest],
["createIniPanelShellViewModel", createIniPanelShellViewModel],
["createIniPanelShellApiSurfaceInventory", createIniPanelShellApiSurfaceInventory],
["createIniPanelShellSessionReadinessWorkflowReport", createIniPanelShellSessionReadinessWorkflowReport],
["createIniPanelShellWorkflowOverviewContract", createIniPanelShellWorkflowOverviewContract],
[
"createIniPanelShellWorkflowOverviewEmbeddingMountDomContract",
createIniPanelShellWorkflowOverviewEmbeddingMountDomContract,
@@ -116,12 +153,80 @@ assert.equal(sessionSnapshotPath("sdk-session"), "linuxcnc/sessions/sdk-session/
assert.equal(normalizeOpfsPath("linuxcnc/machines/sdk-mill/tool.tbl"), "linuxcnc/machines/sdk-mill/tool.tbl");
assert.equal(gcodeFilenameFromProgramPath("linuxcnc/gcode/demo.ngc"), "demo.ngc");
assert.deepEqual(getIniPanelEntryManifest(), INI_PANEL_ENTRIES);
assert.deepEqual(getVisibleIniPanelEntries(), INI_PANEL_ENTRIES);
assert.deepEqual(getIniPanelEntryByHref("./control-page.html"), {
id: "control-view",
title: "Open read-only control view",
href: "./control-page.html",
});
assert.deepEqual(createIniPanelLauncherLinkViewModel(), [
{
entryId: "edit-run",
href: "./index.html",
label: "Open edit and run panel",
},
{
entryId: "control-view",
href: "./control-page.html",
label: "Open read-only control view",
},
{
entryId: "workflow-overview",
href: "./workflow-overview.html",
label: "Open shell handoff overview",
},
]);
assert.equal(
createMachineSessionPersistenceSummary({
state: {
badges: { opfs: "OPFS: ready" },
fields: { sessionSnapshot: "sdk-session/snapshot.json", sessionIni: "/work/session-machine.ini" },
sessionLoad: { iniWasmPath: "/work/session-machine.ini" },
sessionReadiness: { phase: "ready", ready: true, missing: [] },
},
}).rows.find(({ id }) => id === "session-load")?.value,
"loaded: /work/session-machine.ini",
);
assert.equal(
createMachineSessionPersistenceRenderState(
createMachineSessionPersistenceDisplayViewModel(createMachineSessionPersistenceSummary()),
).apiName,
"machine-session-persistence-render-state",
);
const controlPageApiSchema = createControlPageBrowserApiSchema();
const controlPageApiManifest = createControlPageBrowserApiManifest();
assert.equal(controlPageApiSchema.apiName, "ini-panel-control-page");
assert.equal(isSupportedIniPanelControlPageApiManifest(controlPageApiManifest), true);
assert.deepEqual(controlPageApiManifest.methods, createControlPageBrowserApiMethods());
assert.equal(
createIniPanelShellControlPageContract().readonlyStatusApiManifest.apiName,
"machine-session-readonly-status",
);
const launchManifest = createIniPanelLaunchApiManifest();
assert.equal(isSupportedIniPanelLaunchApiManifest(launchManifest), true);
assert.equal(
launchManifest.methods.includes("mountWorkflowOverviewEmbeddingMountState"),
true,
);
assert.deepEqual(
launchManifest.visibleEntries,
getVisibleIniPanelEntries().map(({ id, href, title }) => ({ id, href, title })),
);
const shellIntegrationManifest = createIniPanelShellIntegrationManifest();
assert.equal(createIniPanelShellIntegrationSchema().apiName, "ini-panel-shell-integration");
assert.equal(isSupportedIniPanelShellIntegrationManifest(shellIntegrationManifest), true);
assert.equal(createIniPanelShellIntegrationReadiness(shellIntegrationManifest).ready, true);
assert.equal(createIniPanelShellIntegrationWorkflowPlan({
manifest: shellIntegrationManifest,
}).ready, true);
assert.equal(
createIniPanelShellWorkflowOverviewContract().methodNames.includes("getWorkflowOverviewApiSurfaceInventory"),
true,
);
const shellViewModel = createIniPanelShellViewModel();
assert.equal(
@@ -140,6 +245,19 @@ assert.equal(
createIniPanelShellApiSurfaceInventory().apiName,
"ini-panel-shell-api-surface-inventory",
);
assert.equal(shellViewModel.shellApiSurfaceInventory.ready, true);
assert.equal(
shellViewModel.shellSessionHandoffWorkflowSummary.rows.find(
({ id }) => id === "persistence-summary",
)?.value,
"waiting: 5 missing",
);
assert.equal(
shellViewModel.shellSessionHandoffWorkflowSummary.rows.find(
({ id }) => id === "api-surface-inventory",
)?.value,
"ready: 6 rows",
);
assert.equal(
shellViewModel.mountWorkflowOverviewEmbeddingMountState,
mountIniPanelShellWorkflowOverviewEmbeddingMountState,

View File

@@ -167,6 +167,9 @@ const requiredShellExports = [
"createIniPanelShellViewModel",
"getIniPanelEntryByHref",
"getVisibleIniPanelEntries",
"createMachineSessionPersistenceDisplayViewModel",
"createMachineSessionPersistenceRenderState",
"createMachineSessionPersistenceSummary",
"isSupportedIniPanelControlPageApiManifest",
"isSupportedIniPanelLaunchApiManifest",
"isSupportedIniPanelShellIntegrationManifest",

View File

@@ -69,6 +69,7 @@ assert.deepEqual(manifest, {
"mountShellSessionHandoff",
"mountShellSessionHandoffFromControlPage",
"readShellSessionHandoffStatusFromControlPage",
"getMachineSessionPersistenceSummary",
"getShellSessionHandoffWorkflowSummary",
"getShellSessionReadinessWorkflowReport",
"getShellApiSurfaceInventory",
@@ -227,6 +228,7 @@ assert.match(launchText, /\brenderShellSessionHandoffMountState\b/);
assert.match(launchText, /\bmountShellSessionHandoff\b/);
assert.match(launchText, /\bmountShellSessionHandoffFromControlPage\b/);
assert.match(launchText, /\breadShellSessionHandoffStatusFromControlPage\b/);
assert.match(launchText, /\bgetMachineSessionPersistenceSummary\b/);
assert.match(launchText, /\bgetShellSessionHandoffWorkflowSummary\b/);
assert.match(launchText, /\bgetShellSessionReadinessWorkflowReport\b/);
assert.match(launchText, /\bgetShellApiSurfaceInventory\b/);

View File

@@ -179,7 +179,7 @@ assert.deepEqual(readiness, {
counts: {
pages: 3,
launcherLinks: 3,
launchMethods: 57,
launchMethods: 58,
controlPageMethods: 11,
persistenceCapabilities: 3,
},
@@ -242,7 +242,7 @@ assert.deepEqual(handoffSummary, {
counts: {
pages: 3,
launcherLinks: 3,
launchMethods: 57,
launchMethods: 58,
controlPageMethods: 11,
persistenceCapabilities: 3,
},
@@ -779,6 +779,7 @@ assert.deepEqual(createIniPanelShellWorkflowOverviewContract(), {
"getWorkflowOverviewSummary",
"getWorkflowOverviewSessionReadinessReport",
"getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
@@ -827,6 +828,7 @@ assert.deepEqual(
[
"getWorkflowOverviewDisplayViewModel",
"getWorkflowOverviewSummary",
"getWorkflowOverviewPersistenceSummary",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
@@ -1246,7 +1248,7 @@ assert.deepEqual(createIniPanelShellIntegrationReadiness(blockedManifest), {
counts: {
pages: 3,
launcherLinks: 3,
launchMethods: 57,
launchMethods: 58,
controlPageMethods: 11,
persistenceCapabilities: 3,
},

View File

@@ -3,6 +3,9 @@ import assert from "node:assert/strict";
import {
createIniPanelStateSummary,
createMachineSessionControlView,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionStateSnapshot,
createMachineSessionStateBundle,
createMachineSessionStateReport,
@@ -566,6 +569,145 @@ const expectedBundleReport = {
},
};
const readyPersistenceSummary = createMachineSessionPersistenceSummary({
state: {
badges: {
ini: "INI WASM: ready",
interp: "Interpreter WASM: ready",
opfs: "OPFS: ready",
},
machineFiles: {
iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini",
parameterOpfsPath: "linuxcnc/machines/xyzab-tdr/linuxcnc.var",
toolTableOpfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl",
gcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc",
},
fields: {
sessionSnapshot: "ui-machine-session/ui-machine-session.json",
sessionIni: "/work/session-machine.ini",
sessionParameters: "/work/session-linuxcnc.var",
sessionToolTable: "/work/session-tool.tbl",
sessionGcode: "linuxcnc/gcode/ui-session.ngc",
},
sessionLoad: {
iniWasmPath: "/work/session-machine.ini",
parameterWasmPath: "/work/session-linuxcnc.var",
toolTableWasmPath: "/work/session-tool.tbl",
},
sessionReadiness: sessionReadinessFixture,
},
readonlyStatus: {
phase: "ready",
ready: true,
},
handoffWorkflowSummary: {
phase: "ready",
ready: true,
},
});
assert.deepEqual(
readyPersistenceSummary,
{
apiName: "machine-session-persistence-summary",
summaryVersion: 1,
phase: "ready",
ready: true,
checks: {
opfs: true,
machineFiles: true,
sessionSnapshot: true,
sessionReadiness: true,
sessionLoad: true,
},
missing: [],
counts: {
machineFiles: 4,
missing: 0,
},
rows: [
{
id: "opfs",
label: "OPFS",
value: "OPFS: ready",
},
{
id: "machine-files",
label: "Machine files",
value: "ini, parameters, tool-table, g-code",
},
{
id: "session-snapshot",
label: "Session snapshot",
value: "ui-machine-session/ui-machine-session.json",
},
{
id: "session-readiness",
label: "Session readiness",
value: "ready",
},
{
id: "session-load",
label: "Session load",
value: "loaded: /work/session-machine.ini",
},
{
id: "readonly-status",
label: "Readonly status",
value: "ready",
},
{
id: "handoff-readiness",
label: "Handoff readiness",
value: "ready",
},
],
},
);
assert.deepEqual(
createMachineSessionPersistenceSummary().missing,
["opfs", "machineFiles", "sessionSnapshot", "sessionReadiness", "sessionLoad"],
);
assert.deepEqual(
createMachineSessionPersistenceDisplayViewModel(readyPersistenceSummary),
{
phase: "ready",
title: "OPFS/session persistence",
statusText: "Ready",
detailText: "No missing persistence requirements",
rows: readyPersistenceSummary.rows,
},
);
assert.deepEqual(
createMachineSessionPersistenceRenderState(
createMachineSessionPersistenceDisplayViewModel(readyPersistenceSummary),
),
{
apiName: "machine-session-persistence-render-state",
renderStateVersion: 1,
phase: "ready",
ready: true,
title: "OPFS/session persistence",
statusText: "Ready",
detailText: "No missing persistence requirements",
statusLine: "Ready: No missing persistence requirements",
rows: readyPersistenceSummary.rows,
dataset: {
persistencePhase: "ready",
persistenceReady: "true",
persistenceScope: "opfs-session",
},
},
);
assert.equal(
createMachineSessionPersistenceRenderState().statusLine,
"Waiting: opfs, machineFiles, sessionSnapshot, sessionReadiness, sessionLoad",
);
assert.deepEqual(
createMachineSessionWorkflowOverview(expectedBundleReport),
expectedWorkflowOverview,

View File

@@ -67,6 +67,9 @@ import {
createControlPageRefreshState,
createControlPageSessionLoadState,
createMachineSessionControlPageController,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
getIniPanelEntryByHref,
getIniPanelEntryManifest,
getVisibleIniPanelEntries,
@@ -104,6 +107,9 @@ assert.deepEqual(createControlPageSessionLoadState({ phase: "waiting-panel" }),
});
assert.equal(getIniPanelEntryByHref("./index.html")?.id, "edit-run");
assert.equal(typeof createMachineSessionControlPageController, "function");
assert.equal(typeof createMachineSessionPersistenceDisplayViewModel, "function");
assert.equal(typeof createMachineSessionPersistenceRenderState, "function");
assert.equal(typeof createMachineSessionPersistenceSummary, "function");
assert.equal(typeof createMachineSessionReadonlyStatus, "function");
assert.equal(typeof createMachineSessionReadonlyStatusApiManifest, "function");
assert.equal(typeof createControlPageBrowserApiManifest, "function");
@@ -667,6 +673,7 @@ assert.deepEqual(shellViewModel.shellWorkflowOverviewContract, {
"getWorkflowOverviewSummary",
"getWorkflowOverviewSessionReadinessReport",
"getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
@@ -1113,13 +1120,17 @@ 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.deepEqual(workflowSummaryResult.apiSurfaceInventory, null);
assert.deepEqual(workflowSummaryResult.persistenceSummary, null);
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.rows.find(({ id }) => id === "persistence-summary")?.value, "missing");
assert.equal(workflowSummaryResult.rows.find(({ id }) => id === "api-surface-inventory")?.value, "missing");
assert.equal(workflowSummaryResult.rows.length, 8);
assert.equal(workflowSummaryResult.blockingReasons[0], "mount:blocked");
const sessionReadinessWorkflowReport = createIniPanelShellSessionReadinessWorkflowReport({
workflowSummary: workflowSummaryResult,
@@ -1137,7 +1148,18 @@ assert.equal(shellViewModel.shellSessionReadinessWorkflowReport.rows.length, 3);
assert.equal(shellViewModel.shellApiSurfaceInventory.apiName, "ini-panel-shell-api-surface-inventory");
assert.equal(shellViewModel.shellApiSurfaceInventory.ready, true);
assert.equal(shellViewModel.shellApiSurfaceInventory.counts.sessionReadinessRows, 3);
assert.equal(shellViewModel.shellApiSurfaceInventory.rows.length, 5);
assert.equal(shellViewModel.shellApiSurfaceInventory.counts.persistenceSummaryRows, 7);
assert.equal(shellViewModel.shellApiSurfaceInventory.rows.length, 6);
assert.equal(shellViewModel.shellPersistenceSummary.ready, false);
assert.equal(
shellViewModel.shellSessionHandoffWorkflowSummary.rows.find(({ id }) => id === "persistence-summary")?.value,
"waiting: 5 missing",
);
assert.equal(shellViewModel.shellSessionHandoffWorkflowSummary.apiSurfaceInventory.ready, true);
assert.equal(
shellViewModel.shellSessionHandoffWorkflowSummary.rows.find(({ id }) => id === "api-surface-inventory")?.value,
"ready: 6 rows",
);
const readyWorkflowSummaryResult = createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow: {
phase: "ready",
@@ -1157,7 +1179,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, 6);
assert.equal(workflowDisplayViewModel.rows.length, 8);
const readyWorkflowDisplayViewModel = createIniPanelShellSessionHandoffWorkflowDisplayViewModel(
readyWorkflowSummaryResult,
);
@@ -1172,7 +1194,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, 6);
assert.equal(workflowRenderState.rows.length, 8);
const readyWorkflowRenderState = createIniPanelShellSessionHandoffWorkflowRenderState(
readyWorkflowDisplayViewModel,
);
@@ -1215,13 +1237,15 @@ assert.deepEqual(
{
rendered: true,
statusLine: "Blocked: mount:blocked",
rowCount: 6,
rowCount: 8,
rowIds: [
"mount-workflow",
"control-page-mount-workflow",
"readonly-status-workflow",
"session-readiness",
"readonly-status-missing-fields",
"persistence-summary",
"api-surface-inventory",
"blocking-reasons",
],
dataset: {
@@ -1242,7 +1266,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, 6);
assert.equal(workflowDomMountResult.renderResult.rowCount, 8);
assert.equal(workflowDomMountResult.renderResult.dataset.handoffScope, "workflow");
assert.deepEqual(createIniPanelShellWorkflowOverviewContract(), shellViewModel.shellWorkflowOverviewContract);
assert.deepEqual(createIniPanelShellWorkflowOverviewReadiness(), {
@@ -1259,6 +1283,7 @@ const workflowOverviewApi = {
getWorkflowOverviewSummary: () => workflowSummaryResult,
getWorkflowOverviewSessionReadinessReport: () => sessionReadinessWorkflowReport,
getWorkflowOverviewApiSurfaceInventory: () => shellViewModel.shellApiSurfaceInventory,
getWorkflowOverviewPersistenceSummary: () => shellViewModel.shellPersistenceSummary,
getWorkflowOverviewDomContract: createIniPanelShellSessionHandoffWorkflowDomContract,
getWorkflowOverviewDomReadiness: createIniPanelShellSessionHandoffWorkflowDomReadiness,
renderWorkflowOverview: renderIniPanelShellSessionHandoffWorkflowState,
@@ -1291,7 +1316,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, 6);
assert.equal(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 8);
assert.equal(workflowOverviewEmbedding.error, null);
const workflowOverviewEmbeddingReport = createIniPanelShellWorkflowOverviewEmbeddingReport(workflowOverviewEmbedding);
assert.deepEqual(workflowOverviewEmbeddingReport, {
@@ -1307,7 +1332,7 @@ assert.deepEqual(workflowOverviewEmbeddingReport, {
contract: shellViewModel.shellWorkflowOverviewContract,
missingMethods: [],
mountPhase: "blocked",
renderRowCount: 6,
renderRowCount: 8,
error: null,
blockingReasons: ["embedding:blocked", "mount:blocked"],
rows: [
@@ -1334,7 +1359,7 @@ assert.deepEqual(workflowOverviewEmbeddingReport, {
{
id: "render-row-count",
label: "Render row count",
value: "6",
value: "8",
},
{
id: "error",