虚拟HAL完全满足Web数控仿真

结论:ini-panel workflow overview 已提供固定 URL 表单和按钮,用户可直接输入 release artifact URL 与 browser diagnostics URL 并运行 release URL workflow;该流程验证的 virtual HAL evidence 仍完全来自 LinuxCNC source-derived reports,virtual HAL 继续满足 Web 数控系统仿真范围,不声明 Linux kernel hard-realtime ABI、外部硬件驱动 ABI 或 native HAL module ABI。
This commit is contained in:
2026-06-17 23:12:45 +08:00
parent 208992c42e
commit abf858641f
3 changed files with 200 additions and 0 deletions

View File

@@ -1190,3 +1190,79 @@ git diff --check ok
source files 与 vendored LinuxCNC manifest 做显式一致性验证。 source files 与 vendored LinuxCNC manifest 做显式一致性验证。
3. 将 virtual HAL session diagnostics artifact 纳入 release artifact URL workflow 的示例 3. 将 virtual HAL session diagnostics artifact 纳入 release artifact URL workflow 的示例
fixtures使 URL workflow 同时覆盖 live diagnostics 与 saved-session diagnostics。 fixtures使 URL workflow 同时覆盖 live diagnostics 与 saved-session diagnostics。
### 十三、2026-06-17 INI Workflow Overview URL Form
继续按本文件铁律推进:虚拟 HAL 的功能完全来源于 LinuxCNC 源程序,并且虚拟 HAL
完全满足 Web 方式数控系统仿真系统。本批完成上一节下一步第 1 项,把 ini-panel
workflow overview 的 diagnostics URL workflow 接入固定页面表单和按钮,让用户可在页面上
输入 release artifact URL 与 browser diagnostics URL 后直接运行验证。
新增实质能力:
- `workflow-overview.html` 新增固定 URL workflow 表单:
- Release artifact URL 输入;
- Browser diagnostics URL 输入;
- `Run URL Workflow` 按钮;
- release artifact URL workflow 状态区;
- release artifact URL workflow rows 区;
- 页面脚本新增:
- `runWorkflowOverviewReleaseReadinessArtifactUrlForm(options)`
- 从页面输入框读取 artifact URL 与 diagnostics URL
- 复用 `loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl()`
- 复用 release URL workflow summary/render/mount helpers
- 写入 `document.body.dataset.releaseArtifactUrlWorkflowPhase`
- 写入 `document.body.dataset.releaseArtifactUrlWorkflowReady`
- Browser API 新增:
- `runWorkflowOverviewReleaseReadinessArtifactUrlForm()`
- 表单输入使用 `type="text"` 与 `inputmode="url"`,同时支持相对 fixture 路径和真实
HTTP/HTTPS URL。
新增/扩展验证:
- `ini_panel_workflow_overview_smoke.html` 覆盖:
- workflow overview API 暴露 `runWorkflowOverviewReleaseReadinessArtifactUrlForm()`
- 页面固定输入框可写入 release artifact URL 与 diagnostics URL
- 表单 runner 可复用 diagnostics artifact fetch stub
- 表单 runner 返回 `workflow.ready === true`
- 表单 runner 返回 `mountResult.ready === true`
- 页面 body dataset 标记 URL workflow ready
- 页面固定 workflow rows 中 `browser-diagnostics` 行显示 `ready`
- `verify_ini_panel_browser.sh` 聚合确认 workflow overview 页面、launch、control、
shell integration 仍全部通过;
- `verify_ui_node_smokes.sh` 聚合确认 ui-shell/API manifest/docs 不回归。
关键验证:
```text
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
ini_panel_ui_shell_node_smoke=ok
ini_panel_shell_integration_manifest_node_smoke=ok
ini_panel_launch_api_manifest_node_smoke=ok
ini_panel_entry_docs_node_smoke=ok
ui_node_smokes=ok
git diff --check ok
```
语义边界:
- 本批没有新增 G-code/interpreter/planner/kinematics/remap 语义;
- workflow overview 表单只加载并验证 release artifact 与 browser diagnostics artifact
- browser diagnostics artifact 中的 virtual HAL evidence 仍来自 source-derived virtual HAL
reports
- virtual HAL 仍不声称提供 Linux kernel hard-realtime ABI、外部硬件驱动 ABI 或 native
HAL module ABI
- G-code/interpreter/planner/canonical motion 语义仍来自 LinuxCNC-backed WASM。
下一步工作内容:
1. 为 motion matrix 增加 manifest-backed source check把 matrix 关联的 sim config
source files 与 vendored LinuxCNC manifest 做显式一致性验证。
2. 将 virtual HAL session diagnostics artifact 纳入 release artifact URL workflow 的示例
fixtures使 URL workflow 同时覆盖 live diagnostics 与 saved-session diagnostics。
3. 将 workflow overview 固定 URL 表单的 action-plan 与 gate execution summary rows
同屏渲染,便于用户看到 URL workflow 的下一步命令和 gate evidence。

View File

@@ -68,6 +68,39 @@
color: var(--text); color: var(--text);
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.url-workflow-form {
display: grid;
grid-template-columns: 1fr;
gap: 10px;
border-top: 1px solid var(--border);
padding-top: 12px;
}
.url-workflow-form label {
display: grid;
gap: 4px;
color: var(--muted);
font: 12px/1.4 "Segoe UI", "Noto Sans", sans-serif;
}
.url-workflow-form input {
width: 100%;
min-height: 32px;
border: 1px solid var(--border);
border-radius: 4px;
padding: 6px 8px;
color: var(--text);
font: 13px/1.4 "Segoe UI", "Noto Sans", sans-serif;
}
.url-workflow-form button {
justify-self: start;
min-height: 32px;
border: 1px solid #0f5f9d;
border-radius: 4px;
background: var(--accent);
color: #fff;
padding: 6px 12px;
font: 13px/1.4 "Segoe UI", "Noto Sans", sans-serif;
cursor: pointer;
}
</style> </style>
</head> </head>
<body> <body>
@@ -79,6 +112,21 @@
<p data-handoff-workflow-status>Checking shell handoff workflow summary.</p> <p data-handoff-workflow-status>Checking shell handoff workflow summary.</p>
<dl data-handoff-workflow-rows></dl> <dl data-handoff-workflow-rows></dl>
</section> </section>
<form class="url-workflow-form" data-release-artifact-url-workflow-form>
<label>
Release artifact URL
<input type="text" inputmode="url" data-release-artifact-url-input placeholder="../../tests/fixtures/project-release-readiness-ready.json">
</label>
<label>
Browser diagnostics URL
<input type="text" inputmode="url" data-browser-diagnostics-url-input placeholder="../../tests/fixtures/real-browser-simulation-diagnostics-ready.json">
</label>
<button type="submit" data-run-release-artifact-url-workflow>Run URL Workflow</button>
</form>
<section class="overview-status" aria-label="Release artifact URL workflow" data-workflow-overview-release-readiness-artifact-url-workflow>
<p data-workflow-overview-release-readiness-artifact-url-workflow-status>Waiting for release artifact URL workflow.</p>
<dl data-workflow-overview-release-readiness-artifact-url-workflow-rows></dl>
</section>
</section> </section>
</main> </main>
<script type="module"> <script type="module">
@@ -149,6 +197,46 @@
const shellViewModel = createIniPanelShellViewModel(); const shellViewModel = createIniPanelShellViewModel();
const workflowRenderState = shellViewModel.shellSessionHandoffWorkflowRenderState; const workflowRenderState = shellViewModel.shellSessionHandoffWorkflowRenderState;
renderIniPanelShellSessionHandoffWorkflowState(workflowRenderState, { documentRef: document }); renderIniPanelShellSessionHandoffWorkflowState(workflowRenderState, { documentRef: document });
const releaseArtifactUrlInput = document.querySelector("[data-release-artifact-url-input]");
const browserDiagnosticsUrlInput = document.querySelector("[data-browser-diagnostics-url-input]");
const releaseArtifactUrlWorkflowForm = document.querySelector("[data-release-artifact-url-workflow-form]");
async function runWorkflowOverviewReleaseReadinessArtifactUrlForm(options = {}) {
const artifactUrl = String(options.artifactUrl ?? releaseArtifactUrlInput?.value ?? "").trim();
const diagnosticsUrl = String(options.diagnosticsUrl ?? browserDiagnosticsUrlInput?.value ?? "").trim();
const workflow = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({
artifactUrl,
diagnosticsUrl,
fetchRef: options.fetchRef,
mount: options.mount ?? true,
});
const summary = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(workflow);
const renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(summary);
const mountResult = mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState({
renderState,
documentRef: document,
});
document.body.dataset.releaseArtifactUrlWorkflowPhase = workflow.phase;
document.body.dataset.releaseArtifactUrlWorkflowReady = workflow.ready ? "true" : "false";
return {
workflow,
summary,
renderState,
mountResult,
};
}
releaseArtifactUrlWorkflowForm?.addEventListener("submit", (event) => {
event.preventDefault();
runWorkflowOverviewReleaseReadinessArtifactUrlForm().catch((error) => {
const status = document.querySelector("[data-workflow-overview-release-readiness-artifact-url-workflow-status]");
if (status) {
status.textContent = `Blocked: ${error?.message ?? "release artifact URL workflow failed"}`;
}
document.body.dataset.releaseArtifactUrlWorkflowPhase = "blocked";
document.body.dataset.releaseArtifactUrlWorkflowReady = "false";
});
});
window.linuxCncIniPanelWorkflowOverviewApi = { window.linuxCncIniPanelWorkflowOverviewApi = {
getWorkflowOverviewRenderState: () => shellViewModel.shellSessionHandoffWorkflowRenderState, getWorkflowOverviewRenderState: () => shellViewModel.shellSessionHandoffWorkflowRenderState,
@@ -207,6 +295,7 @@
loadWorkflowOverviewReleaseReadinessArtifactUrl: (options) => ( loadWorkflowOverviewReleaseReadinessArtifactUrl: (options) => (
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl(options) loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl(options)
), ),
runWorkflowOverviewReleaseReadinessArtifactUrlForm,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: (workflow) => ( getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: (workflow) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(workflow) createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(workflow)
), ),

View File

@@ -60,6 +60,7 @@
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness ||
!workflowApi?.renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState || !workflowApi?.renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState ||
!workflowApi?.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState || !workflowApi?.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState ||
!workflowApi?.runWorkflowOverviewReleaseReadinessArtifactUrlForm ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState ||
@@ -372,6 +373,20 @@
}, },
mount: true, mount: true,
}); });
workflowDoc.querySelector("[data-release-artifact-url-input]").value = "../../tests/fixtures/project-release-readiness-ready.json";
workflowDoc.querySelector("[data-browser-diagnostics-url-input]").value = "../../tests/fixtures/real-browser-simulation-diagnostics-ready.json";
const releaseArtifactUrlFormResult = await workflowApi.runWorkflowOverviewReleaseReadinessArtifactUrlForm({
fetchRef: async (url) => {
if (String(url).endsWith("real-browser-simulation-diagnostics-ready.json")) {
return {
ok: true,
status: 200,
text: async () => diagnosticsArtifactJson,
};
}
return fetch(url);
},
});
const releaseArtifactUrlWorkflowSummary = workflowApi const releaseArtifactUrlWorkflowSummary = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(releaseArtifactUrlWorkflow); .getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(releaseArtifactUrlWorkflow);
const releaseArtifactUrlWorkflowActionPlan = workflowApi const releaseArtifactUrlWorkflowActionPlan = workflowApi
@@ -519,6 +534,26 @@
"Ready: Artifact URL workflow complete", "Ready: Artifact URL workflow complete",
"workflow overview release artifact URL workflow rendered status", "workflow overview release artifact URL workflow rendered status",
); );
assertEqual(
releaseArtifactUrlFormResult.workflow.ready,
true,
"workflow overview fixed URL workflow form readiness",
);
assertEqual(
releaseArtifactUrlFormResult.mountResult.ready,
true,
"workflow overview fixed URL workflow form mount readiness",
);
assertEqual(
workflowDoc.body.dataset.releaseArtifactUrlWorkflowReady,
"true",
"workflow overview fixed URL workflow form body ready",
);
assertEqual(
workflowDoc.querySelector('[data-workflow-overview-release-readiness-artifact-url-workflow-value="browser-diagnostics"]').textContent,
"ready",
"workflow overview fixed URL workflow form browser diagnostics row",
);
assertEqual( assertEqual(
releaseArtifactJsonWorkflow.statusLine, releaseArtifactJsonWorkflow.statusLine,
"Ready: Artifact JSON workflow complete", "Ready: Artifact JSON workflow complete",