diff --git a/PROJECT_COMPLETION_TRACKER.md b/PROJECT_COMPLETION_TRACKER.md index 05c9652..3213cd9 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: `text32.txt` -- Latest completed batch: evidence expansion UI surface +- Latest completed batch: evidence expansion filter query/hash preset - 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 @@ -45,7 +45,7 @@ The project is complete for the current scope when all of the following are true | Simulation test program library | Active | Built-in browser simulation programs live in `wasm-port/runtime/ui/simulation/programs/`, one module per program, exported through `programs/index.js`; `verify_real_simulation_programs.sh` checks directory-backed inventory, IDs, defaults, and playback contracts. | | Vendor/source guard | Stable | `verify_vendor_sync.sh` and standalone semantic guard are required every batch. | | Interpreter WASM smoke | Stable | `interp_wasm_node_smoke=ok`. | -| Sim config inventory | Stable with skips | `executed=82`, `passed=82`, `skipped=77`, `unexpected_fail=0`; `docs/sim-configs-coverage-handoff.md` records the release-gate baseline. The 2026-06-20 remaining-skip audit found 2 skipped main-program rows and 0 rows with `promotion_allowed=1`, so the baseline must not change without new LinuxCNC-owned native/Node/browser proof. Browser diagnostics evidence expansion now includes five ready source-derived REP candidates: `woodpecker-on-abort`, `puma-cube`, `melfa-example`, `trt-boat-xyzac`, and `trt-xyzac-switchkins`, all with `promotionAllowed=false`; the real simulation diagnostics panel and release URL workflow summaries expose the five-row full candidate/G-code lists. | +| Sim config inventory | Stable with skips | `executed=82`, `passed=82`, `skipped=77`, `unexpected_fail=0`; `docs/sim-configs-coverage-handoff.md` records the release-gate baseline. The 2026-06-20 remaining-skip audit found 2 skipped main-program rows and 0 rows with `promotion_allowed=1`, so the baseline must not change without new LinuxCNC-owned native/Node/browser proof. Browser diagnostics evidence expansion now includes eleven ready source-derived REP candidates, including the full current TRT table-rotary-tilting batch, all with `promotionAllowed=false`; the real simulation diagnostics panel and release URL workflow summaries expose the eleven-row full candidate/G-code lists plus three-family/source-count drilldown, and the INI workflow overview now has a separate evidence-expansion family/source filter with summary/action-plan helpers plus query/hash UI-state presets for external shell reads. | | Native nc_files baseline | Stable | Last recorded Layer 1: `total 107`, `pass 101`, `expected_fail 6`, `unexpected_fail 0`. | | Native sim configs baseline | Stable | Last recorded Layer 2: `total 159`, `pass 151`, `expected_fail 8`, `unexpected_fail 0`. | | OPFS/session persistence | Stable for current scope | Browser smoke passes, SDK re-exports OPFS/session helpers including `readMachineSessionReadiness()` and `createMachineSessionPersistenceSummary()`, the UI exposes `getMachineSessionPersistenceSummary()`, and `docs/opfs-session-persistence.md` defines the project-level release gate. | diff --git a/text32.txt b/text32.txt index 951e157..69da7c9 100644 --- a/text32.txt +++ b/text32.txt @@ -181,8 +181,8 @@ trt-xyzac-switchkins 当前 evidence expansion report: ```text -candidateCount=5 -readyCandidateCount=5 +candidateCount=11 +readyCandidateCount=11 inventoryBaselineUnchanged=true promotionAllowed=false ``` @@ -288,7 +288,7 @@ standalone CNC semantics guard complete ```text 1. real simulation diagnostics panel 显示 evidence expansion ready count; -2. real simulation diagnostics panel 显示完整 5 个 ready candidates; +2. real simulation diagnostics panel 显示完整 ready candidates; 3. release artifact URL workflow summary 暴露完整 candidate / G-code list; 4. INI workflow overview URL summary 暴露完整 candidate / G-code list; 5. 保留原有 preview 的前三项,兼容既有 UI 和测试。 @@ -298,9 +298,9 @@ standalone CNC semantics guard complete ```text real-browser-simulation-evidence-expansion-summary -data-evidence-expansion-summary-value="candidate-count" => 5/5 ready +data-evidence-expansion-summary-value="candidate-count" => 11/11 ready data-evidence-expansion-summary-value="candidate-list" => - woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins + woodpecker-on-abort, puma-cube, melfa-example, trt-boat-xyzac, trt-xyzac-switchkins, trt-boat-xyzbc, trt-impeller-7bl-xyzac, trt-xyzac-switchkins-test-1, trt-xyzac-switchkins-test-2, trt-xyzac-switchkins-test-3, trt-xyzbc-switchkins evidence-expansion-full-candidate-list evidence-expansion-full-gcode-list ``` @@ -340,18 +340,412 @@ browser_release_artifact_url_workflow_smoke=ok 九、下一步工作计划 -继续扩展五轴 TRT family 的 browser diagnostics evidence,不改变 -`82/82/77/0` baseline。建议下一批新增: +本轮已把计划中的六个五轴 TRT row 加入 browser diagnostics evidence +expansion,当前完整 ready candidates 为: ```text -axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc -axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc -axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc -axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc -axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc -axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc +woodpecker-on-abort +puma-cube +melfa-example +trt-boat-xyzac +trt-xyzac-switchkins +trt-boat-xyzbc +trt-impeller-7bl-xyzac +trt-xyzac-switchkins-test-1 +trt-xyzac-switchkins-test-2 +trt-xyzac-switchkins-test-3 +trt-xyzbc-switchkins ``` -每批仍只做 browser diagnostics / release evidence expansion,不能改 -`promotionAllowed=false`,不能把 SKIP 或 REP 伪装为 inventory baseline -promotion。 +下一步建议不要继续堆同一 TRT family,改为做“evidence expansion +source drilldown / family grouping”,让 UI 按 family 或 source kind 查看 +11 个 candidates: + +```text +1. 在 real simulation diagnostics panel 增加 evidence-expansion family rows; +2. 在 release URL / INI workflow summary 增加 source-count 或 family-count + drilldown; +3. 保持 preview 三项兼容; +4. inventory baseline 仍保持 82/82/77/0; +5. promotionAllowed 仍保持 false。 +``` + +十、本轮接续推进:evidence expansion family/source drilldown + +执行时间:2026-06-20 CST + +已完成第九节建议的 family/source drilldown,不改变 +`82/82/77/0` inventory baseline,也不允许 evidence expansion 触发 +inventory promotion。 + +新增/确认的 diagnostics/API/UI 字段: + +```text +virtualHalSimConfigEvidenceExpansion.familyRows +evidence-expansion-family-count +evidence-expansion-family-summary +evidence-expansion-family-source-count-list +evidence-expansion-family-woodpecker +evidence-expansion-family-vismach-remap-sims +evidence-expansion-family-five-axis-trt +data-evidence-expansion-summary-value="family-count" +data-evidence-expansion-summary-value="family-summary" +data-evidence-expansion-summary-value="family-source-count-list" +``` + +当前 family drilldown: + +```text +woodpecker: 1/1 ready; sources=3 +vismach-remap-sims: 2/2 ready; sources=6 +five-axis-trt: 8/8 ready; sources=12 +``` + +边界仍保持: + +```text +candidateCount=11 +readyCandidateCount=11 +inventoryBaselineUnchanged=true +promotionAllowed=false +inventory baseline=82/82/77/0 +``` + +本轮已运行验证: + +```text +wasm-port/tests/sdk/node/verify_sdk_surface.sh +wasm-port/tests/sdk/node/verify_project_release_gate_manifest.sh +wasm-port/tests/sdk/node/verify_project_release_artifact_url_workflow.sh +wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_real_simulation_browser.sh +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh +``` + +结果: + +```text +sdk_surface_node_smoke=ok +project_release_gate_manifest_node_smoke=ok +project_release_artifact_url_workflow_node_smoke=ok +project_batch_acceptance_workflow_node_smoke=ok +project_batch_acceptance_artifact_node_smoke=ok +ini_panel_ui_shell_node_smoke=ok +browser_real_simulation_page_smoke=ok +browser_ini_workflow_overview_smoke=ok +browser_ini_shell_integration_workflow_smoke=ok +browser_release_artifact_url_workflow_smoke=ok +``` + +十一、下一步工作计划 + +不要继续扩大同一个 TRT evidence expansion 列表,也不要改 inventory +baseline。下一批建议转向“drilldown 可用性/过滤”: + +```text +1. 在 INI workflow overview 增加 evidence-expansion family/source filter + render-state,类似现有 promotion family source filter; +2. 支持按 family 查看 candidateIds / gcodePaths / sourceFiles; +3. real simulation diagnostics panel 保持 summary 简洁,只暴露 family rows; +4. release URL workflow summary 保留 preview 三项和 full list 兼容; +5. 继续保持 promotionAllowed=false、baseline=82/82/77/0。 +``` + +十二、本轮接续推进:evidence expansion family/source filter + +执行时间:2026-06-20 CST + +已完成第十一节建议的 evidence-expansion family/source filter。该 filter +独立于 promotion family source filter,避免把 promotion candidates 与 +evidence expansion diagnostics rows 混在同一 API/DOM contract 中。 + +新增 API / DOM surface: + +```text +getWorkflowOverviewEvidenceExpansionFamilyRowsRenderState +getWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel +getWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract +getWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness +getWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan +handleWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange +bindWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls +renderWorkflowOverviewEvidenceExpansionFamilySourceFilterState +mountWorkflowOverviewEvidenceExpansionFamilySourceFilterState + +data-workflow-overview-evidence-expansion-family-source-filter +data-workflow-overview-evidence-expansion-family-source-filter-controls +data-workflow-overview-evidence-expansion-family-source-filter-rows +``` + +当前 filter 覆盖: + +```text +families=3 +sourceFiles=21 +candidates=11 +sourceKinds=ini/gcode/remap-subroutine/source +evidence-expansion-family-five-axis-trt + gcode => 8 source files / 8 candidates +``` + +边界仍保持: + +```text +promotionAllowed=false +inventoryBaselineUnchanged=true +inventory baseline=82/82/77/0 +``` + +本轮已运行验证: + +```text +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 +``` + +结果: + +```text +ini_panel_ui_shell_node_smoke=ok +sdk_surface_node_smoke=ok +project_release_gate_manifest_node_smoke=ok +project_release_artifact_url_workflow_node_smoke=ok +project_batch_acceptance_workflow_node_smoke=ok +project_batch_acceptance_artifact_node_smoke=ok +browser_ini_workflow_overview_smoke=ok +browser_ini_shell_integration_workflow_smoke=ok +``` + +十三、下一步工作计划 + +不要改 inventory baseline,也不要扩大同一 TRT family。下一批建议做 +filter 状态的可复用输出/深链: + +```text +1. 为 evidence-expansion family/source filter 增加 summary/action-plan + helper,输出 selectedFamilyId / selectedSourceKind / filtered counts; +2. 在 workflow overview URL workflow result 中保留当前 filter selection + 的 structured summary,方便外部 shell 读取; +3. 可选:支持 query/hash 参数预选 family/sourceKind; +4. 继续保持 promotionAllowed=false、baseline=82/82/77/0; +5. 验证仍以 Node UI smoke、INI browser smoke、SDK surface、docs smoke 为主。 +``` + +十四、本轮接续推进:evidence expansion filter summary/action-plan + +执行时间:2026-06-20 CST + +已完成第十三节建议中的可复用输出层,不改变 inventory baseline,也不扩大 +TRT family 候选集合。 + +新增 API / SDK / 页面 surface: + +```text +createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary +createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan +getWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary +getWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan +``` + +当前 structured summary/action-plan 覆盖: + +```text +selectedFamilyId +selectedSourceKind +filteredSourceFileCount +scopedSourceFileCount +totalSourceFileCount +filteredCandidateCount +totalCandidateCount +familyIds +sourceKinds +candidateIds +gcodePaths +sourceFiles +promotionAllowed=false +baselineChanging=false +``` + +页面侧 `workflow-overview.html` 现在会在 fixed release artifact URL workflow +执行后保留当前 evidence-expansion filter selection 的 structured summary +和 action-plan,并通过 workflow overview API 暴露给外部 shell。默认状态: + +```text +all / all => 21/21 source files selected +five-axis-trt / gcode => 8/21 source files selected, 8 candidates +``` + +边界仍保持: + +```text +promotionAllowed=false +baselineChanging=false +inventoryBaselineUnchanged=true +inventory baseline=82/82/77/0 +``` + +本轮已运行验证: + +```text +git diff --check +wasm-port/tests/sdk/node/verify_sdk_surface.sh +wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_real_simulation_browser.sh +wasm-port/tests/docs/node/verify_sim_configs_coverage_docs.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh +wasm-port/tools/verify_no_standalone_cnc_semantics.sh +``` + +结果: + +```text +sdk_surface_node_smoke=ok +project_release_gate_manifest_node_smoke=ok +project_release_artifact_url_workflow_node_smoke=ok +project_batch_acceptance_workflow_node_smoke=ok +project_batch_acceptance_artifact_node_smoke=ok +ini_panel_ui_shell_node_smoke=ok +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 +browser_release_artifact_url_workflow_smoke=ok +browser_real_simulation_page_smoke=ok +sim_configs_coverage_docs_node_smoke=ok +sim_configs_wasm_node_inventory=ok +standalone CNC semantics guard complete +``` + +inventory 验证结果仍为: + +```text +sim_configs_wasm_node_inventory_executed=82 +sim_configs_wasm_node_inventory_passed=82 +sim_configs_wasm_node_inventory_skipped=77 +sim_configs_wasm_node_inventory_unexpected_fail=0 +sim_configs_wasm_node_inventory_skip_ASSET_ONLY=65 +sim_configs_wasm_node_inventory_skip_L4_USER_M_PROCESS=1 +sim_configs_wasm_node_inventory_skip_NON_MAIN_CLASS=10 +sim_configs_wasm_node_inventory_skip_UPSTREAM_DEMO=1 +``` + +十五、下一步工作计划 + +继续不要改 inventory baseline,也不要继续扩大同一个 TRT evidence list。 +下一批建议做可选的 filter 深链预选,但要保持为 UI 状态恢复能力,不影响 +release evidence 或 promotion 结论: + +```text +1. 支持 workflow overview 的 query/hash 参数预选: + - evidenceExpansionFamily=evidence-expansion-family-five-axis-trt + - evidenceExpansionSourceKind=gcode +2. 预选只驱动 filter view-model 初始状态,不写入 inventory/report artifact; +3. browser smoke 覆盖预选后 body dataset / DOM selectedFamilyId / + selectedSourceKind / filtered count; +4. SDK summary/action-plan 保持 promotionAllowed=false、baselineChanging=false; +5. baseline 继续保持 82/82/77/0。 +``` + +十六、本轮接续推进:evidence expansion filter query/hash 预选 + +执行时间:2026-06-20 CST + +已完成第十五节建议的 workflow overview filter 深链预选。该能力只影响 +`workflow-overview.html` 中 evidence-expansion family/source filter 的初始 +UI 状态,不写入 release artifact、不写入 diagnostics artifact、不改变 +inventory/report 结论。 + +新增行为: + +```text +workflow-overview.html?evidenceExpansionFamily=evidence-expansion-family-five-axis-trt&evidenceExpansionSourceKind=gcode + +workflow-overview.html#evidenceExpansionFamily=evidence-expansion-family-five-axis-trt&evidenceExpansionSourceKind=gcode +``` + +当前预选结果: + +```text +selectedFamilyId=evidence-expansion-family-five-axis-trt +selectedSourceKind=gcode +filteredSourceFileCount=8 +filteredCandidateCount=8 +baselineChanging=false +promotionAllowed=false +``` + +实现边界: + +```text +1. 预选只通过 URL query/hash 读取; +2. 只传入 createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel; +3. 不改 SDK helper 的纯函数输入/输出; +4. 不改 diagnostics artifact 或 release readiness artifact; +5. 不改 inventory baseline。 +``` + +本轮已运行验证: + +```text +git diff --check +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 +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_real_simulation_browser.sh +wasm-port/tests/docs/node/verify_sim_configs_coverage_docs.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh +wasm-port/tools/verify_no_standalone_cnc_semantics.sh +``` + +结果: + +```text +ini_panel_ui_shell_node_smoke=ok +sdk_surface_node_smoke=ok +project_release_gate_manifest_node_smoke=ok +project_release_artifact_url_workflow_node_smoke=ok +project_batch_acceptance_workflow_node_smoke=ok +project_batch_acceptance_artifact_node_smoke=ok +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 +browser_release_artifact_url_workflow_smoke=ok +browser_real_simulation_page_smoke=ok +sim_configs_coverage_docs_node_smoke=ok +sim_configs_wasm_node_inventory=ok +standalone CNC semantics guard complete +``` + +inventory 验证结果仍为: + +```text +sim_configs_wasm_node_inventory_executed=82 +sim_configs_wasm_node_inventory_passed=82 +sim_configs_wasm_node_inventory_skipped=77 +sim_configs_wasm_node_inventory_unexpected_fail=0 +sim_configs_wasm_node_inventory_skip_ASSET_ONLY=65 +sim_configs_wasm_node_inventory_skip_L4_USER_M_PROCESS=1 +sim_configs_wasm_node_inventory_skip_NON_MAIN_CLASS=10 +sim_configs_wasm_node_inventory_skip_UPSTREAM_DEMO=1 +``` + +十七、下一步工作计划 + +不要改 inventory baseline,也不要把 evidence-expansion filter 状态写入 +artifact。下一批建议转向真实浏览器模拟页面的 operator-facing 可用性: + +```text +1. 在 real simulation page diagnostics 区增加 evidence-expansion family + drilldown 的紧凑 operator view; +2. 只展示 family/count/source-kind summary,不新增 CNC 语义; +3. 保持 release artifact URL workflow 和 INI workflow overview 现有 API 兼容; +4. browser smoke 覆盖 real simulation page 的 family drilldown 可见状态; +5. baseline 继续保持 82/82/77/0。 +``` diff --git a/wasm-port/docs/sim-config-coverage-promotion-analysis.md b/wasm-port/docs/sim-config-coverage-promotion-analysis.md index fefc7c7..df35060 100644 --- a/wasm-port/docs/sim-config-coverage-promotion-analysis.md +++ b/wasm-port/docs/sim-config-coverage-promotion-analysis.md @@ -709,6 +709,24 @@ linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ng trt-xyzac-switchkins linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc + +trt-boat-xyzbc +linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc + +trt-impeller-7bl-xyzac +linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc + +trt-xyzac-switchkins-test-1 +linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc + +trt-xyzac-switchkins-test-2 +linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc + +trt-xyzac-switchkins-test-3 +linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc + +trt-xyzbc-switchkins +linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc ``` Both rows use the LinuxCNC-owned `xyzac-trt.ini` machine context and the @@ -724,8 +742,8 @@ inventoryBaselineUnchanged=true ``` The real browser simulation diagnostics artifact now validates that the -evidence expansion report has `candidateCount=5` and `readyCandidateCount=5`, -including the two TRT rows above. The inventory baseline remains +evidence expansion report has `candidateCount=11` and `readyCandidateCount=11`, +including the TRT rows above. The inventory baseline remains `executed=82 passed=82 skipped=77 unexpected_fail=0`. ## 2026-06-20 Evidence Expansion UI Surface @@ -736,14 +754,56 @@ The evidence expansion data is now visible outside the raw diagnostics JSON: real-browser-simulation-evidence-expansion-summary evidence-expansion-full-candidate-list evidence-expansion-full-gcode-list +evidence-expansion-family-count +evidence-expansion-family-summary +evidence-expansion-family-source-count-list ``` -The real simulation diagnostics panel renders `5/5 ready`, the full five-row +The real simulation diagnostics panel renders `11/11 ready`, the full eleven-row candidate list, source-file count, promotion lock state, and unchanged inventory state. The project release URL workflow summary and INI workflow overview keep their existing three-row preview fields for compatibility, and also expose the full candidate and G-code lists so shell callers can inspect -all five ready evidence-expansion rows without opening the raw artifact. +all eleven ready evidence-expansion rows without opening the raw artifact. + +The same diagnostics and release URL summaries now group the eleven +evidence-expansion rows into three browser diagnostics families: + +```text +woodpecker: 1/1 ready; sources=3 +vismach-remap-sims: 2/2 ready; sources=6 +five-axis-trt: 8/8 ready; sources=12 +``` + +This family drilldown is source/evidence visibility only. It does not alter the +separate promotion candidate summary of 8 diagnostics-ready candidates across +3 families and 17 source files, and it does not change the inventory baseline. + +## 2026-06-20 Evidence Expansion Source Filter + +The INI workflow overview now exposes a separate evidence-expansion family +source filter, distinct from the promotion-family source filter: + +```text +getWorkflowOverviewEvidenceExpansionFamilyRowsRenderState +getWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel +renderWorkflowOverviewEvidenceExpansionFamilySourceFilterState +mountWorkflowOverviewEvidenceExpansionFamilySourceFilterState +``` + +The filter supports selecting `all`, `ini`, `gcode`, `remap-subroutine`, or +`source` rows within the evidence-expansion families, and it keeps candidate +rows separate from source rows. The current ready filter surface covers: + +```text +21 source files +11 evidence-expansion candidate rows +evidence-expansion-family-five-axis-trt / gcode => 8 source files, 8 candidates +``` + +All rows remain diagnostics evidence only: `promotionAllowed=false`, +`inventoryBaselineUnchanged=true`, and the inventory baseline remains +`82/82/77/0`. ## Boundary Statement diff --git a/wasm-port/runtime/sdk/README.md b/wasm-port/runtime/sdk/README.md index 64cea05..ba9e61f 100644 --- a/wasm-port/runtime/sdk/README.md +++ b/wasm-port/runtime/sdk/README.md @@ -61,6 +61,17 @@ import { createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel, + handleIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange, + bindIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls, + renderIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState, + mountIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness, @@ -707,6 +718,20 @@ for external browser shells: `renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()`, and `mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()` let callers render the URL workflow status into their own DOM. + `createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState()`, + `createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel()`, + `createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary()`, + and `createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan()` + expose the current evidence-expansion family/source selection for external + shells without enabling inventory promotion. + `createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract()`, + `createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness()`, + `createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan()`, + `handleIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange()`, + `bindIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls()`, + `renderIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState()`, + and `mountIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState()` + let callers render and bind that evidence-expansion filter in caller-owned DOM. `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan()` exposes the direct artifact-validation next-command plan when callers already have parsed or validated artifact JSON. diff --git a/wasm-port/runtime/sdk/src/index.js b/wasm-port/runtime/sdk/src/index.js index bf2c68b..c16178f 100644 --- a/wasm-port/runtime/sdk/src/index.js +++ b/wasm-port/runtime/sdk/src/index.js @@ -234,6 +234,17 @@ export { createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan, + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan, + handleIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange, + bindIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls, + renderIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState, + mountIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState, createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState, createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel, createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract, diff --git a/wasm-port/runtime/sdk/src/linuxcnc-hal.js b/wasm-port/runtime/sdk/src/linuxcnc-hal.js index 9baafc2..7c101b0 100644 --- a/wasm-port/runtime/sdk/src/linuxcnc-hal.js +++ b/wasm-port/runtime/sdk/src/linuxcnc-hal.js @@ -513,6 +513,132 @@ export const VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES = Object.freez blockedKind: "-", evidence: "The LinuxCNC table-rotary-tilting XYZAC switchkins demo is already a browser representative row; this evidence expansion binds it into release diagnostics only.", }), + Object.freeze({ + id: "trt-boat-xyzbc", + label: "TRT boat XYZBC", + simConfigTarget: "five-axis-trt", + sourceFiles: Object.freeze([ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ]), + iniPath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + gcodePath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc", + currentNodeInventoryStatus: "PASS", + currentMatrixBrowserStatus: "REP", + dependencyClass: "hal_process,halui_mdi_process,ui_process", + targetBrowserEvidence: "browser-diagnostics-expansion", + promotionAllowed: false, + blockedKind: "-", + evidence: "The LinuxCNC table-rotary-tilting boat XYZBC demo is already a five-axis representative row and is added as browser diagnostics evidence only.", + }), + Object.freeze({ + id: "trt-impeller-7bl-xyzac", + label: "TRT impeller 7 blade XYZAC", + simConfigTarget: "five-axis-trt", + sourceFiles: Object.freeze([ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ]), + iniPath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + gcodePath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + currentNodeInventoryStatus: "PASS", + currentMatrixBrowserStatus: "REP", + dependencyClass: "hal_process,halui_mdi_process,ui_process", + targetBrowserEvidence: "browser-diagnostics-expansion", + promotionAllowed: false, + blockedKind: "-", + evidence: "The LinuxCNC table-rotary-tilting impeller demo expands the TRT representative diagnostics set without changing inventory promotion state.", + }), + Object.freeze({ + id: "trt-xyzac-switchkins-test-1", + label: "TRT XYZAC switchkins test 1", + simConfigTarget: "five-axis-trt", + sourceFiles: Object.freeze([ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ]), + iniPath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + gcodePath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc", + currentNodeInventoryStatus: "PASS", + currentMatrixBrowserStatus: "REP", + dependencyClass: "hal_process,halui_mdi_process,ui_process", + targetBrowserEvidence: "browser-diagnostics-expansion", + promotionAllowed: false, + blockedKind: "-", + evidence: "The LinuxCNC XYZAC switchkins test 1 row is already representative coverage and is exposed as browser diagnostics evidence only.", + }), + Object.freeze({ + id: "trt-xyzac-switchkins-test-2", + label: "TRT XYZAC switchkins test 2", + simConfigTarget: "five-axis-trt", + sourceFiles: Object.freeze([ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ]), + iniPath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + gcodePath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc", + currentNodeInventoryStatus: "PASS", + currentMatrixBrowserStatus: "REP", + dependencyClass: "hal_process,halui_mdi_process,ui_process", + targetBrowserEvidence: "browser-diagnostics-expansion", + promotionAllowed: false, + blockedKind: "-", + evidence: "The LinuxCNC XYZAC switchkins test 2 row is already representative coverage and is exposed as browser diagnostics evidence only.", + }), + Object.freeze({ + id: "trt-xyzac-switchkins-test-3", + label: "TRT XYZAC switchkins test 3", + simConfigTarget: "five-axis-trt", + sourceFiles: Object.freeze([ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ]), + iniPath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + gcodePath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc", + currentNodeInventoryStatus: "PASS", + currentMatrixBrowserStatus: "REP", + dependencyClass: "hal_process,halui_mdi_process,ui_process", + targetBrowserEvidence: "browser-diagnostics-expansion", + promotionAllowed: false, + blockedKind: "-", + evidence: "The LinuxCNC XYZAC switchkins test 3 row is already representative coverage and is exposed as browser diagnostics evidence only.", + }), + Object.freeze({ + id: "trt-xyzbc-switchkins", + label: "TRT XYZBC switchkins", + simConfigTarget: "five-axis-trt", + sourceFiles: Object.freeze([ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ]), + iniPath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + gcodePath: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc", + currentNodeInventoryStatus: "PASS", + currentMatrixBrowserStatus: "REP", + dependencyClass: "hal_process,halui_mdi_process,ui_process", + targetBrowserEvidence: "browser-diagnostics-expansion", + promotionAllowed: false, + blockedKind: "-", + evidence: "The LinuxCNC XYZBC switchkins demo completes the current TRT representative diagnostics batch without changing inventory promotion state.", + }), ]); export const VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES = Object.freeze([ @@ -3371,6 +3497,30 @@ export function createVirtualHalSimConfigEvidenceExpansionReport(options = {}) { const blockedCandidateIds = rows.filter((row) => row.blockedKind !== "-").map((row) => row.id); const missingManifestFiles = [...new Set(rows.flatMap((row) => row.missingManifestFiles))]; const missingRequiredReports = [...new Set(rows.flatMap((row) => row.missingRequiredReports))]; + const familyRows = [...new Set(rows.map((row) => row.simConfigTarget ?? row.id))].map((familyId) => { + const familyCandidates = rows.filter((row) => (row.simConfigTarget ?? row.id) === familyId); + const completeCount = familyCandidates.filter((row) => row.complete).length; + const readyBrowserDiagnosticsCount = familyCandidates + .filter((row) => row.targetBrowserEvidence === "browser-diagnostics-expansion").length; + const promotionAllowedCount = familyCandidates.filter((row) => row.promotionAllowed).length; + const sourceFiles = [...new Set(familyCandidates.flatMap((row) => row.sourceFiles))]; + const gcodePaths = [...new Set(familyCandidates.map((row) => row.gcodePath).filter(Boolean))]; + const iniPaths = [...new Set(familyCandidates.map((row) => row.iniPath).filter(Boolean))]; + return { + id: familyId, + candidateIds: familyCandidates.map((row) => row.id), + candidateCount: familyCandidates.length, + completeCount, + readyBrowserDiagnosticsCount, + browserDiagnosticsExpansionReady: readyBrowserDiagnosticsCount === familyCandidates.length, + promotionAllowedCount, + complete: completeCount === familyCandidates.length, + sourceFiles, + sourceFileCount: sourceFiles.length, + gcodePaths, + iniPaths, + }; + }); const complete = rows.length > 0 && missingCandidates.length === 0 && promotionAllowedViolations.length === 0 && @@ -3397,10 +3547,12 @@ export function createVirtualHalSimConfigEvidenceExpansionReport(options = {}) { blockedCandidateIds, missingManifestFiles, missingRequiredReports, + familyRows, rows, summaryRows: [ { id: "candidates", label: "Expansion candidates", value: `${rows.length}` }, { id: "ready-candidates", label: "Ready candidates", value: `${rows.filter((row) => row.complete).length}` }, + { id: "families", label: "Expansion families", value: `${familyRows.length}` }, { id: "promotion-allowed", label: "Promotion allowed", value: "0" }, { id: "inventory-baseline", label: "Inventory baseline", value: "unchanged" }, ], diff --git a/wasm-port/runtime/sdk/src/project-release-readiness.js b/wasm-port/runtime/sdk/src/project-release-readiness.js index 2bd0133..170fd4e 100644 --- a/wasm-port/runtime/sdk/src/project-release-readiness.js +++ b/wasm-port/runtime/sdk/src/project-release-readiness.js @@ -138,6 +138,35 @@ function createPromotionFamilySummaryRows(candidateReport = {}) { }); } +function createEvidenceExpansionFamilySummaryRows(evidenceExpansionReport = {}) { + return arrayOrEmpty(objectOrEmpty(evidenceExpansionReport).familyRows).map((family) => { + const candidateCount = family.candidateCount ?? 0; + const completeCount = family.completeCount ?? 0; + const sourceFileCount = family.sourceFileCount ?? arrayOrEmpty(family.sourceFiles).length; + const ready = family.complete === true && family.browserDiagnosticsExpansionReady === true; + return { + id: family.id ?? "unknown", + label: family.id ?? "Unknown evidence expansion family", + value: `${completeCount}/${candidateCount} ready; sources=${sourceFileCount}; diagnostics=${ready ? "ready" : "blocked"}`, + candidateIds: arrayOrEmpty(family.candidateIds), + sourceFiles: arrayOrEmpty(family.sourceFiles), + gcodePaths: arrayOrEmpty(family.gcodePaths), + iniPaths: arrayOrEmpty(family.iniPaths), + candidateCount, + completeCount, + sourceFileCount, + ready, + }; + }); +} + +function createEvidenceExpansionFamilySummaryText(evidenceExpansionReport = {}) { + const rows = createEvidenceExpansionFamilySummaryRows(evidenceExpansionReport); + return rows.length > 0 + ? rows.map((row) => `${row.id}: ${row.completeCount}/${row.candidateCount} ${row.ready ? "ready" : "blocked"}`).join("; ") + : "not provided"; +} + function createPromotionCandidateArtifactSummary({ candidateReport = {}, evidenceExpansionReport = {}, @@ -161,6 +190,8 @@ function createPromotionCandidateArtifactSummary({ const artifactInventoryReadyRows = candidateArtifactRows .filter((row) => row.candidate_kind === "inventory-ready"); const artifactEvidenceReadyCount = artifactEvidenceReadyRows.length; + const evidenceExpansionFamilyRows = createEvidenceExpansionFamilySummaryRows(evidenceExpansionReport); + const evidenceExpansionFamilySummary = createEvidenceExpansionFamilySummaryText(evidenceExpansionReport); const inventoryReadyCount = artifactInventoryReadyRows.length > 0 ? artifactInventoryReadyRows.length : 2; @@ -269,6 +300,9 @@ function createPromotionCandidateArtifactSummary({ promotionAllowedCount: 0, baselineChanging: false, nextEvidence: "browser-diagnostics-binding", + familyCount: evidenceExpansionFamilyRows.length, + familySummary: evidenceExpansionFamilySummary, + familyRows: evidenceExpansionFamilyRows, }, }; } @@ -482,6 +516,66 @@ const REQUIRED_EVIDENCE_EXPANSION_CANDIDATES = [ "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", ], }, + { + id: "trt-boat-xyzbc", + sourceFiles: [ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ], + }, + { + id: "trt-impeller-7bl-xyzac", + sourceFiles: [ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ], + }, + { + id: "trt-xyzac-switchkins-test-1", + sourceFiles: [ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ], + }, + { + id: "trt-xyzac-switchkins-test-2", + sourceFiles: [ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ], + }, + { + id: "trt-xyzac-switchkins-test-3", + sourceFiles: [ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ], + }, + { + id: "trt-xyzbc-switchkins", + sourceFiles: [ + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", + "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", + ], + }, ]; const REQUIRED_MACRO_LOAD_FIXTURES = [ @@ -3223,6 +3317,10 @@ export function createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel const evidenceExpansionRows = arrayOrEmpty( workflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion?.rows, ); + const evidenceExpansionFamilyRows = arrayOrEmpty( + promotionCandidateArtifactSummary.evidenceExpansion?.familyRows + ?? workflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion?.familyRows, + ); const preferredEvidenceExpansion = evidenceExpansionRows[0] ?? {}; const evidenceExpansionPreviewRows = evidenceExpansionRows.slice(0, 3); const evidenceExpansionFullRows = evidenceExpansionRows; @@ -3401,6 +3499,34 @@ export function createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel ? evidenceExpansionFullRows.map((row) => row.gcodePath).join(", ") : "not provided", }, + { + id: "evidence-expansion-family-count", + label: "Evidence expansion family count", + value: evidenceExpansionFamilyRows.length > 0 + ? `${evidenceExpansionFamilyRows.length} families` + : "not provided", + }, + { + id: "evidence-expansion-family-summary", + label: "Evidence expansion family summary", + value: promotionCandidateArtifactSummary.evidenceExpansion?.familySummary + ?? createEvidenceExpansionFamilySummaryText(workflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion), + }, + { + id: "evidence-expansion-family-source-count-list", + label: "Evidence expansion family source counts", + value: evidenceExpansionFamilyRows.length > 0 + ? evidenceExpansionFamilyRows.map((row) => `${row.id}:${row.sourceFileCount ?? arrayOrEmpty(row.sourceFiles).length}`).join(", ") + : "not provided", + }, + ...evidenceExpansionFamilyRows.map((row) => ({ + id: `evidence-expansion-family-${row.id}`, + label: `Evidence expansion family ${row.label ?? row.id}`, + value: row.value ?? `${row.completeCount ?? 0}/${row.candidateCount ?? 0} ready; sources=${row.sourceFileCount ?? arrayOrEmpty(row.sourceFiles).length}`, + candidateIds: arrayOrEmpty(row.candidateIds), + sourceFiles: arrayOrEmpty(row.sourceFiles), + gcodePaths: arrayOrEmpty(row.gcodePaths), + })), { id: "evidence-expansion-artifact", label: "Evidence expansion artifact", diff --git a/wasm-port/runtime/ui/ini-panel/ui-shell.js b/wasm-port/runtime/ui/ini-panel/ui-shell.js index bfc6f3e..c615ff4 100644 --- a/wasm-port/runtime/ui/ini-panel/ui-shell.js +++ b/wasm-port/runtime/ui/ini-panel/ui-shell.js @@ -219,6 +219,17 @@ export function createIniPanelLaunchApiManifest(entries = getVisibleIniPanelEntr "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan", "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState", "getWorkflowOverviewPromotionFamilyRowsRenderState", + "getWorkflowOverviewEvidenceExpansionFamilyRowsRenderState", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan", + "handleWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange", + "bindWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls", + "renderWorkflowOverviewEvidenceExpansionFamilySourceFilterState", + "mountWorkflowOverviewEvidenceExpansionFamilySourceFilterState", "getWorkflowOverviewPromotionFamilySourceFilterViewModel", "getWorkflowOverviewPromotionFamilySourceFilterDomContract", "getWorkflowOverviewPromotionFamilySourceFilterDomReadiness", @@ -1942,6 +1953,17 @@ export function createIniPanelShellWorkflowOverviewContract() { "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan", "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState", "getWorkflowOverviewPromotionFamilyRowsRenderState", + "getWorkflowOverviewEvidenceExpansionFamilyRowsRenderState", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan", + "getWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan", + "handleWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange", + "bindWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls", + "renderWorkflowOverviewEvidenceExpansionFamilySourceFilterState", + "mountWorkflowOverviewEvidenceExpansionFamilySourceFilterState", "getWorkflowOverviewPromotionFamilySourceFilterViewModel", "getWorkflowOverviewPromotionFamilySourceFilterDomContract", "getWorkflowOverviewPromotionFamilySourceFilterDomReadiness", @@ -2600,6 +2622,12 @@ export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWo ?? workflow?.urlWorkflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion?.rows ?? [] ); + const evidenceExpansionFamilyRows = ( + promotionCandidateArtifactSummary.evidenceExpansion?.familyRows + ?? workflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion?.familyRows + ?? workflow?.urlWorkflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion?.familyRows + ?? [] + ); const preferredEvidenceExpansion = Array.isArray(evidenceExpansionRows) ? (evidenceExpansionRows[0] ?? {}) : {}; @@ -2817,6 +2845,40 @@ export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWo ? evidenceExpansionFullRows.map((row) => row.gcodePath).join(", ") : "not provided", }, + { + id: "evidence-expansion-family-count", + label: "Evidence expansion family count", + value: Array.isArray(evidenceExpansionFamilyRows) && evidenceExpansionFamilyRows.length > 0 + ? `${evidenceExpansionFamilyRows.length} families` + : "not provided", + }, + { + id: "evidence-expansion-family-summary", + label: "Evidence expansion family summary", + value: evidenceExpansion.familySummary ?? (Array.isArray(evidenceExpansionFamilyRows) && evidenceExpansionFamilyRows.length > 0 + ? evidenceExpansionFamilyRows.map((row) => { + const ready = row.ready === true || (row.complete === true && row.browserDiagnosticsExpansionReady === true); + return `${row.id}: ${row.completeCount ?? 0}/${row.candidateCount ?? 0} ${ready ? "ready" : "blocked"}`; + }).join("; ") + : "not provided"), + }, + { + id: "evidence-expansion-family-source-count-list", + label: "Evidence expansion family source counts", + value: Array.isArray(evidenceExpansionFamilyRows) && evidenceExpansionFamilyRows.length > 0 + ? evidenceExpansionFamilyRows.map((row) => + `${row.id}:${row.sourceFileCount ?? (Array.isArray(row.sourceFiles) ? row.sourceFiles.length : 0)}` + ).join(", ") + : "not provided", + }, + ...(Array.isArray(evidenceExpansionFamilyRows) ? evidenceExpansionFamilyRows.map((row) => ({ + id: `evidence-expansion-family-${row.id}`, + label: `Evidence expansion family ${row.label ?? row.id}`, + value: row.value ?? `${row.completeCount ?? 0}/${row.candidateCount ?? 0} ready; sources=${row.sourceFileCount ?? (Array.isArray(row.sourceFiles) ? row.sourceFiles.length : 0)}`, + candidateIds: Array.isArray(row.candidateIds) ? row.candidateIds : [], + sourceFiles: Array.isArray(row.sourceFiles) ? row.sourceFiles : [], + gcodePaths: Array.isArray(row.gcodePaths) ? row.gcodePaths : [], + })) : []), { id: "hard-block-runtime-lock", label: "Hard-block runtime lock", @@ -3360,6 +3422,77 @@ export function createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderStat }; } +export function createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState( + summaryViewModel = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(), +) { + const summaryRows = Array.isArray(summaryViewModel?.rows) ? summaryViewModel.rows : []; + const rows = summaryRows + .filter(({ id }) => String(id).startsWith("evidence-expansion-family-")) + .filter(({ sourceFiles, gcodePaths }) => Array.isArray(sourceFiles) && Array.isArray(gcodePaths)) + .map(({ id, label, value, sourceFiles, gcodePaths, candidateIds }) => { + const familySourceFiles = Array.isArray(sourceFiles) ? sourceFiles : []; + const familyGcodePaths = Array.isArray(gcodePaths) ? gcodePaths : []; + const familyCandidateIds = Array.isArray(candidateIds) ? candidateIds : []; + const sourceKindCounts = countPromotionFamilySourceKinds(familySourceFiles); + const sourceKindSummary = formatPromotionFamilySourceKindCounts(sourceKindCounts); + return { + id, + label, + value: value == null ? "" : String(value), + sourceFiles: familySourceFiles, + gcodePaths: familyGcodePaths, + candidateIds: familyCandidateIds, + sourceKindCounts, + sourceKindSummary, + }; + }); + const sourceRows = rows.flatMap((row) => + row.sourceFiles.map((sourceFile, index) => ({ + id: `${row.id}-source-${index + 1}`, + familyId: row.id, + label: `Source ${index + 1}`, + value: sourceFile, + sourceKind: classifyPromotionFamilySource(sourceFile), + manifestBacked: true, + status: "evidence-expansion-source", + })) + ); + const candidateRows = rows.flatMap((row) => + row.gcodePaths.map((gcodePath, index) => ({ + id: `${row.id}-candidate-${index + 1}`, + familyId: row.id, + label: row.candidateIds[index] ?? `Candidate ${index + 1}`, + value: gcodePath, + candidateStatus: "evidence-expansion-ready", + promotionAllowed: false, + baselineChanging: false, + sourceKind: "gcode", + manifestBacked: true, + })) + ); + const ready = rows.length > 0 && rows.every(({ value }) => String(value).includes("diagnostics=ready")); + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-rows-render-state", + renderStateVersion: 1, + phase: ready ? "ready" : "blocked", + ready, + title: "Evidence expansion family diagnostics", + statusText: ready ? "Ready" : "Blocked", + detailText: ready ? `${rows.length} evidence expansion families ready` : "evidence expansion family rows missing", + statusLine: `${ready ? "Ready" : "Blocked"}: ${ready ? `${rows.length} evidence expansion families ready` : "evidence expansion family rows missing"}`, + rows, + sourceRows, + candidateRows, + sourceFileCount: sourceRows.length, + candidateCount: candidateRows.length, + dataset: { + handoffPhase: ready ? "ready" : "blocked", + handoffReady: ready ? "true" : "false", + handoffScope: "workflow-overview-evidence-expansion-family-rows", + }, + }; +} + export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel( renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(), { sourceKind = "all", familyId = "all" } = {}, @@ -3454,6 +3587,88 @@ export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterVi }; } +export function createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel( + renderState = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState(), + { sourceKind = "all", familyId = "all" } = {}, +) { + const viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel( + renderState, + { sourceKind, familyId }, + ); + return { + ...viewModel, + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-view-model", + detailText: viewModel.ready + ? `${viewModel.filteredSourceFileCount}/${viewModel.totalSourceFileCount} source files selected` + : "evidence expansion source rows missing", + statusLine: `${viewModel.ready ? "Ready" : "Blocked"}: ${viewModel.ready ? `${viewModel.filteredSourceFileCount}/${viewModel.totalSourceFileCount} source files selected` : "evidence expansion source rows missing"}`, + }; +} + +export function createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary( + viewModel = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel(), +) { + const familyRows = Array.isArray(viewModel?.familyRows) ? viewModel.familyRows : []; + const sourceRows = Array.isArray(viewModel?.sourceRows) ? viewModel.sourceRows : []; + const candidateRows = Array.isArray(viewModel?.candidateRows) ? viewModel.candidateRows : []; + const selectedFamilyId = viewModel?.selectedFamilyId ?? "all"; + const selectedSourceKind = viewModel?.selectedSourceKind ?? "all"; + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-summary", + summaryVersion: 1, + phase: viewModel?.ready === true ? "ready" : "blocked", + ready: viewModel?.ready === true, + selectedFamilyId, + selectedSourceKind, + filteredSourceFileCount: viewModel?.filteredSourceFileCount ?? sourceRows.length, + scopedSourceFileCount: viewModel?.scopedSourceFileCount ?? sourceRows.length, + totalSourceFileCount: viewModel?.totalSourceFileCount ?? sourceRows.length, + filteredCandidateCount: viewModel?.filteredCandidateCount ?? candidateRows.length, + totalCandidateCount: viewModel?.totalCandidateCount ?? candidateRows.length, + familyCount: familyRows.length, + sourceKinds: [...new Set(sourceRows.map((row) => row.sourceKind).filter(Boolean))], + familyIds: familyRows.map((row) => row.id), + candidateIds: candidateRows.map((row) => row.label ?? row.id), + gcodePaths: candidateRows.map((row) => row.value).filter(Boolean), + sourceFiles: sourceRows.map((row) => row.value).filter(Boolean), + statusLine: viewModel?.ready === true + ? `Ready: ${selectedFamilyId} / ${selectedSourceKind} selects ${viewModel?.filteredSourceFileCount ?? sourceRows.length}/${viewModel?.totalSourceFileCount ?? sourceRows.length} source files` + : "Blocked: evidence expansion source filter summary missing", + }; +} + +export function createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan( + summary = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary(), +) { + const ready = summary?.ready === true; + const selectedFamilyId = summary?.selectedFamilyId ?? "all"; + const selectedSourceKind = summary?.selectedSourceKind ?? "all"; + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-action-plan", + actionPlanVersion: 1, + phase: ready ? "ready" : "blocked", + ready, + selectedFamilyId, + selectedSourceKind, + filteredSourceFileCount: summary?.filteredSourceFileCount ?? 0, + filteredCandidateCount: summary?.filteredCandidateCount ?? 0, + promotionAllowed: false, + baselineChanging: false, + nextCommand: ready ? null : "mountWorkflowOverviewEvidenceExpansionFamilySourceFilterState", + nextSteps: ready + ? [] + : [ + "Load a release readiness artifact URL workflow summary.", + "Create evidence expansion family rows render state.", + "Mount the evidence expansion family/source filter DOM.", + ], + statusLine: ready + ? `Ready: evidence expansion filter ${selectedFamilyId} / ${selectedSourceKind} is externally readable` + : "Blocked: evidence expansion filter summary is not ready", + summary, + }; +} + export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({ rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter", selectors = {}, @@ -3496,6 +3711,21 @@ export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDo }; } +export function createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract({ + rowDatasetPrefix = "workflowOverviewEvidenceExpansionFamilySourceFilter", + selectors = {}, +} = {}) { + return createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({ + rowDatasetPrefix, + selectors: { + mount: selectors.mount ?? "[data-workflow-overview-evidence-expansion-family-source-filter]", + status: selectors.status ?? "[data-workflow-overview-evidence-expansion-family-source-filter-status]", + controls: selectors.controls ?? "[data-workflow-overview-evidence-expansion-family-source-filter-controls]", + rows: selectors.rows ?? "[data-workflow-overview-evidence-expansion-family-source-filter-rows]", + }, + }); +} + export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness({ rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter", contract = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({ rowDatasetPrefix }), @@ -3528,6 +3758,30 @@ export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDo }; } +export function createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness({ + rowDatasetPrefix = "workflowOverviewEvidenceExpansionFamilySourceFilter", + contract = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract({ rowDatasetPrefix }), + documentRef = globalThis.document, + mountNode = documentRef?.querySelector?.(contract.selectors.mount), + statusNode = documentRef?.querySelector?.(contract.selectors.status), + controlsNode = documentRef?.querySelector?.(contract.selectors.controls), + rowsNode = documentRef?.querySelector?.(contract.selectors.rows), +} = {}) { + const readiness = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness({ + rowDatasetPrefix, + contract, + documentRef, + mountNode, + statusNode, + controlsNode, + rowsNode, + }); + return { + ...readiness, + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-dom-readiness", + }; +} + function readPromotionFamilySourceFilterControlValue( controlsNode, rowDatasetPrefix, @@ -3572,6 +3826,39 @@ export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSe }; } +export function createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan( + renderState = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState(), + { + familyId = "all", + sourceKind = "all", + previousViewModel = null, + } = {}, +) { + const nextViewModel = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel( + renderState, + { familyId, sourceKind }, + ); + const changed = previousViewModel === null || + previousViewModel.selectedFamilyId !== nextViewModel.selectedFamilyId || + previousViewModel.selectedSourceKind !== nextViewModel.selectedSourceKind; + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-selection-action-plan", + actionPlanVersion: 1, + phase: nextViewModel.ready ? "ready" : "blocked", + ready: nextViewModel.ready, + changed, + selectedFamilyId: nextViewModel.selectedFamilyId, + selectedSourceKind: nextViewModel.selectedSourceKind, + filteredSourceFileCount: nextViewModel.filteredSourceFileCount, + scopedSourceFileCount: nextViewModel.scopedSourceFileCount, + totalSourceFileCount: nextViewModel.totalSourceFileCount, + statusLine: changed + ? `Ready: evidence expansion source filter changed to ${nextViewModel.selectedFamilyId} / ${nextViewModel.selectedSourceKind}` + : "Ready: evidence expansion source filter unchanged", + nextViewModel, + }; +} + export function handleIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionChange({ renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(), viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(renderState), @@ -3628,6 +3915,62 @@ export function handleIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSe }; } +export function handleIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange({ + renderState = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState(), + viewModel = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel(renderState), + rowDatasetPrefix = "workflowOverviewEvidenceExpansionFamilySourceFilter", + contract = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract({ rowDatasetPrefix }), + documentRef = globalThis.document, + mountNode = documentRef?.querySelector?.(contract.selectors.mount), + statusNode = documentRef?.querySelector?.(contract.selectors.status), + controlsNode = documentRef?.querySelector?.(contract.selectors.controls), + rowsNode = documentRef?.querySelector?.(contract.selectors.rows), + render = false, +} = {}) { + const selectedFamilyId = readPromotionFamilySourceFilterControlValue( + controlsNode, + contract.rowDatasetPrefix, + "family", + viewModel?.selectedFamilyId ?? "all", + ); + const selectedSourceKind = readPromotionFamilySourceFilterControlValue( + controlsNode, + contract.rowDatasetPrefix, + "source-kind", + viewModel?.selectedSourceKind ?? "all", + ); + const actionPlan = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan( + renderState, + { + familyId: selectedFamilyId, + sourceKind: selectedSourceKind, + previousViewModel: viewModel, + }, + ); + const renderResult = render + ? renderIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState(actionPlan.nextViewModel, { + contract, + documentRef, + mountNode, + statusNode, + controlsNode, + rowsNode, + }) + : null; + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-selection-change", + workflowVersion: 1, + phase: actionPlan.phase, + ready: actionPlan.ready, + statusLine: actionPlan.statusLine, + selectedFamilyId: actionPlan.selectedFamilyId, + selectedSourceKind: actionPlan.selectedSourceKind, + actionPlan, + viewModel: actionPlan.nextViewModel, + renderResult, + }; +} + export function bindIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionControls({ renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(), viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(renderState), @@ -3720,6 +4063,98 @@ export function bindIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSele return binding; } +export function bindIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls({ + renderState = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState(), + viewModel = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel(renderState), + rowDatasetPrefix = "workflowOverviewEvidenceExpansionFamilySourceFilter", + contract = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract({ rowDatasetPrefix }), + documentRef = globalThis.document, + mountNode = documentRef?.querySelector?.(contract.selectors.mount), + statusNode = documentRef?.querySelector?.(contract.selectors.status), + controlsNode = documentRef?.querySelector?.(contract.selectors.controls), + rowsNode = documentRef?.querySelector?.(contract.selectors.rows), + render = true, + onChange = null, +} = {}) { + const domReadiness = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness({ + contract, + documentRef, + mountNode, + statusNode, + controlsNode, + rowsNode, + }); + const selectNodes = Array.from(controlsNode?.children ?? []) + .filter((node) => typeof node?.dataset?.[`${contract.rowDatasetPrefix}Select`] === "string"); + if (!domReadiness.ready || selectNodes.length === 0) { + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-selection-controls-binding", + bindingVersion: 1, + phase: "blocked", + ready: false, + statusLine: `Blocked: ${domReadiness.ready ? "selector controls missing" : domReadiness.missing.join(", ")}`, + boundControlCount: 0, + controlIds: [], + domReadiness, + lastChange: null, + triggerChange: () => null, + unbind: () => ({ unbound: 0 }), + }; + } + + const binding = { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-selection-controls-binding", + bindingVersion: 1, + phase: "ready", + ready: true, + statusLine: `Ready: ${selectNodes.length} selector controls bound`, + boundControlCount: selectNodes.length, + controlIds: selectNodes.map((node) => node.dataset[`${contract.rowDatasetPrefix}Select`]), + domReadiness, + lastChange: null, + triggerChange: null, + unbind: null, + }; + const handleChange = () => { + const changeResult = handleIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange({ + renderState, + viewModel, + contract, + documentRef, + mountNode, + statusNode, + controlsNode, + rowsNode, + render, + }); + binding.lastChange = changeResult; + if (typeof onChange === "function") { + onChange(changeResult); + } + return changeResult; + }; + const unbinders = selectNodes.map((node) => { + if (typeof node.addEventListener === "function") { + node.addEventListener("change", handleChange); + return () => node.removeEventListener?.("change", handleChange); + } + node.onchange = handleChange; + return () => { + if (node.onchange === handleChange) { + node.onchange = null; + } + }; + }); + binding.triggerChange = handleChange; + binding.unbind = () => { + for (const unbind of unbinders) { + unbind(); + } + return { unbound: unbinders.length }; + }; + return binding; +} + export function renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState( viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(), { @@ -3892,6 +4327,32 @@ export function renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSt }; } +export function renderIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState( + viewModel = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel(), + { + rowDatasetPrefix = "workflowOverviewEvidenceExpansionFamilySourceFilter", + contract = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract({ rowDatasetPrefix }), + documentRef = globalThis.document, + mountNode = documentRef?.querySelector?.(contract.selectors.mount), + statusNode = documentRef?.querySelector?.(contract.selectors.status), + controlsNode = documentRef?.querySelector?.(contract.selectors.controls), + rowsNode = documentRef?.querySelector?.(contract.selectors.rows), + } = {}, +) { + const renderResult = renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState(viewModel, { + rowDatasetPrefix, + contract, + documentRef, + mountNode, + statusNode, + controlsNode, + rowsNode, + }); + mountNode.dataset.handoffScope = "workflow-overview-evidence-expansion-family-source-filter"; + renderResult.dataset.handoffScope = mountNode.dataset.handoffScope; + return renderResult; +} + export function mountIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState({ viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(), rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter", @@ -3962,6 +4423,76 @@ export function mountIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSta } } +export function mountIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState({ + viewModel = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel(), + rowDatasetPrefix = "workflowOverviewEvidenceExpansionFamilySourceFilter", + contract = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract({ rowDatasetPrefix }), + documentRef = globalThis.document, + mountNode = documentRef?.querySelector?.(contract.selectors.mount), + statusNode = documentRef?.querySelector?.(contract.selectors.status), + controlsNode = documentRef?.querySelector?.(contract.selectors.controls), + rowsNode = documentRef?.querySelector?.(contract.selectors.rows), +} = {}) { + const domReadiness = createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness({ + contract, + documentRef, + mountNode, + statusNode, + controlsNode, + rowsNode, + }); + if (!domReadiness.ready) { + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-dom-mount", + workflowVersion: 1, + phase: "blocked", + ready: false, + statusLine: `Blocked: ${domReadiness.missing.join(", ")}`, + contract, + domReadiness, + viewModel, + renderResult: null, + error: null, + }; + } + + try { + const renderResult = renderIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState(viewModel, { + contract, + documentRef, + mountNode, + statusNode, + controlsNode, + rowsNode, + }); + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-dom-mount", + workflowVersion: 1, + phase: viewModel?.phase === "ready" ? "ready" : "blocked", + ready: viewModel?.ready === true, + statusLine: renderResult.statusLine, + contract, + domReadiness, + viewModel, + renderResult, + error: null, + }; + } catch (error) { + return { + apiName: "ini-panel-shell-workflow-overview-evidence-expansion-family-source-filter-dom-mount", + workflowVersion: 1, + phase: "blocked", + ready: false, + statusLine: `Blocked: ${error?.message ?? "evidence expansion source filter DOM mount error"}`, + contract, + domReadiness, + viewModel, + renderResult: null, + error: error?.message ?? String(error), + }; + } +} + export function createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract({ rowDatasetPrefix = "workflowOverviewPromotionFamily", selectors = {}, @@ -6852,6 +7383,28 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan, createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState: createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState, + createWorkflowOverviewEvidenceExpansionFamilyRowsRenderState: + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilyRowsRenderState, + createWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel: + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterViewModel, + createWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract: + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomContract, + createWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness: + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterDomReadiness, + createWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary: + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSummary, + createWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan: + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterActionPlan, + createWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan: + createIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionActionPlan, + handleWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange: + handleIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionChange, + bindWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls: + bindIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterSelectionControls, + renderWorkflowOverviewEvidenceExpansionFamilySourceFilterState: + renderIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState, + mountWorkflowOverviewEvidenceExpansionFamilySourceFilterState: + mountIniPanelShellWorkflowOverviewEvidenceExpansionFamilySourceFilterState, createWorkflowOverviewPromotionFamilyRowsRenderState: createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState, createWorkflowOverviewPromotionFamilySourceFilterViewModel: diff --git a/wasm-port/runtime/ui/ini-panel/workflow-overview.html b/wasm-port/runtime/ui/ini-panel/workflow-overview.html index 4d2b1cf..8a9f32f 100644 --- a/wasm-port/runtime/ui/ini-panel/workflow-overview.html +++ b/wasm-port/runtime/ui/ini-panel/workflow-overview.html @@ -162,6 +162,11 @@
Waiting for evidence expansion family source evidence.
+ +