上传真实浏览器仿真推进

结论:新增 LinuxCNC WASM 驱动的真实浏览器仿真页面,接入 browser smoke、release gate、SDK 与项目交付文档,并完成当前推进批次的验收记录。
This commit is contained in:
2026-06-16 20:59:21 +08:00
parent 19eabdf06e
commit 24e1fc18b1
39 changed files with 7563 additions and 59 deletions

View File

@@ -9,10 +9,11 @@ turn-by-turn continuation notes and next-batch execution records.
## Current Status ## Current Status
- Active continuation file: `text15.txt` - Active continuation file: `text15.txt`
- Latest completed batch: project release artifact URL workflow action-plan SDK API - Latest completed batch: real browser simulation page MVP
- Latest relevant commit: use `git log -1 --oneline` after each committed batch - Latest relevant commit: use `git log -1 --oneline` after each committed batch
- Working tree at tracker creation: clean - Working tree at tracker creation: clean
- Required policy: LinuxCNC remains the only CNC semantic source - Required policy: LinuxCNC remains the only CNC semantic source
- First priority: real UI/browser CNC simulation page; see `wasm-port/docs/real-browser-simulation-priority.md`
- Current scope status: complete after final clean-tree release validation - Current scope status: complete after final clean-tree release validation
## Completion Definition ## Completion Definition
@@ -20,6 +21,7 @@ turn-by-turn continuation notes and next-batch execution records.
The project is complete for the current scope when all of the following are true: The project is complete for the current scope when all of the following are true:
- Browser UI workflows are usable and validated: - Browser UI workflows are usable and validated:
- real browser CNC simulation page
- INI panel - INI panel
- control page - control page
- workflow overview - workflow overview
@@ -37,18 +39,20 @@ The project is complete for the current scope when all of the following are true
| Area | Status | Notes | | Area | Status | Notes |
| --- | --- | --- | | --- | --- | --- |
| LinuxCNC semantic boundary | Stable | JS/browser remains glue, staging, OPFS, WASM/browser boundary, docs, and tests only. | | LinuxCNC semantic boundary | Stable | JS/browser remains glue, staging, OPFS, WASM/browser boundary, docs, and tests only. |
| Real browser simulation priority | Active first priority | Future batches should prioritize the real UI/browser CNC simulation page, with visible machine/session loading, G-code program state, LinuxCNC-backed interpreter execution, machine readiness/status panels, toolpath/preview rendering from LinuxCNC-produced output or validated runtime events, and browser smoke coverage. First entry point: `wasm-port/runtime/ui/simulation/index.html`; gate: `wasm-port/tests/browser/verify_real_simulation_browser.sh`. See `wasm-port/docs/real-browser-simulation-priority.md`. |
| Real browser simulation page | MVP active | `runtime/ui/simulation/index.html` loads in Chromium, runs a representative G-code program through LinuxCNC interpreter WASM, renders program lines, final axis readout, canonical event table, raw canonical output, and SVG toolpath preview. |
| Vendor/source guard | Stable | `verify_vendor_sync.sh` and standalone semantic guard are required every batch. | | 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`. | | Interpreter WASM smoke | Stable | `interp_wasm_node_smoke=ok`. |
| 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. | | 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 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`. | | 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. | | OPFS/session persistence | Stable for current scope | Browser smoke passes, SDK re-exports OPFS/session helpers including `readMachineSessionReadiness()` and `createMachineSessionPersistenceSummary()`, the UI exposes `getMachineSessionPersistenceSummary()`, and `docs/opfs-session-persistence.md` defines the project-level release gate. |
| SDK/API surface | Stable for current scope | SDK re-exports core, OPFS/session readiness/load helpers, sim-config staging, project release gate manifest/result matrix/action-plan/readiness summary view-model, project release readiness report/artifact JSON workflow/artifact URL workflow summary/action-plan/artifact validation summary/action-plan plus URL loading workflow, INI panel entry/launcher/control-page/shell/workflow overview helpers, the session readiness workflow report, and the shell API surface inventory with dedicated Node smokes. | | SDK/API surface | Stable for current scope | SDK re-exports core, OPFS/session readiness/load helpers, sim-config staging, project release gate manifest/result matrix/action-plan/readiness summary view-model, project batch acceptance capability matrix/workflow/summary/action-plan/checklist/report validation summary/action-plan, JSON workflow, URL workflow helpers, and artifact writer/validator gate, project release readiness report/artifact JSON workflow/artifact URL workflow summary/action-plan/artifact validation summary/action-plan plus URL loading workflow, INI panel entry/launcher/control-page/shell/workflow overview helpers including release artifact JSON and URL workflow summary/action-plan/render-state DOM mount helpers, validation action-plan render/mount helpers, URL workflow action-plan, and gate execution summary render/mount helpers, the session readiness workflow report, and the shell API surface inventory with dedicated Node smokes. |
| Browser/UI workflow | Stable for current scope | Workflow overview embedding mount DOM closure is complete, and INI panel session workflows plus read-only control/shell handoff expose, render, fetch, validate, summarize, and report OPFS/session readiness, OPFS/session persistence summary, release readiness artifact validation/rendering/URL workflow summaries, and API surface inventory before loading or reading WASM session state. | | 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, mount, fetch, validate, summarize, action-plan, and report OPFS/session readiness, OPFS/session persistence summary, release readiness artifact JSON/URL workflows, validation/rendering/URL workflow summaries/action-plans/gate execution summaries, and API surface inventory before loading or reading WASM session state. |
| Workflow overview embedding | Stable for current scope | Report/display/render, DOM contract/readiness/renderer, mount result/display/render, mount DOM contract/readiness/renderer/wrapper exist. | | 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. | | 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, tracker acceptance paths, and the machine-readable release readiness report/artifact. | | 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, tracker acceptance paths, and the machine-readable release readiness report/artifact. |
| Project release gate wrapper | Stable | `tests/host/verify_project_release_gate.sh` runs the documented minimum release validation commands including the release artifact URL browser workflow gate and SDK URL workflow gate, writes `build/project-release-readiness.json`, verifies embedded gate manifest/result matrix/action-plan evidence through the SDK artifact validation workflow, and ends with `project_release_gate=ok`. | | Project release gate wrapper | Stable | `tests/host/verify_project_release_gate.sh` runs the documented minimum release validation commands including the release artifact URL browser workflow gate, SDK URL workflow gate, and project batch acceptance workflow/artifact gate, writes `build/project-release-readiness.json` and `build/project-batch-acceptance.json`, verifies embedded gate manifest/result matrix/action-plan evidence plus batch acceptance report evidence through SDK validation workflows, and ends with `project_release_gate=ok`. |
## Blocked Runtime Families ## Blocked Runtime Families
@@ -72,6 +76,29 @@ ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1 bash wasm-port/tests/native/probe_python_rem
Execute these in order unless a later user request explicitly changes priority. Execute these in order unless a later user request explicitly changes priority.
### 0. Real Browser CNC Simulation Page
Current first priority:
- Build a real UI/browser CNC simulation page as quickly as possible.
- First MVP exists at `wasm-port/runtime/ui/simulation/index.html`.
- The page must be visible and operator-oriented, not another release dashboard.
- It should use OPFS/session persistence, staged G-code, and existing
LinuxCNC-backed WASM SDK execution.
- It should expose machine/session readiness, active program state, run status,
and a toolpath/preview surface based on LinuxCNC-produced interpreter output,
canonical events, or validated runtime summaries.
- Add browser smoke coverage proving the page loads, renders nonempty runtime
state, and runs a representative LinuxCNC-backed flow.
- Do not implement G-code, tool, parameter, kinematics, remap, planner, or
canonical motion semantics in JavaScript.
Constraint document:
```bash
wasm-port/tests/docs/node/verify_real_browser_simulation_priority_docs.sh
```
### 1. Browser/UI Workflow Closure ### 1. Browser/UI Workflow Closure
Current next task: Current next task:
@@ -210,6 +237,9 @@ 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_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 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_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh
wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh
wasm-port/tests/docs/node/verify_real_browser_simulation_priority_docs.sh
SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_real_simulation_browser.sh
wasm-port/tests/ui/node/verify_ui_node_smokes.sh wasm-port/tests/ui/node/verify_ui_node_smokes.sh
wasm-port/tests/host/verify_host_smokes.sh wasm-port/tests/host/verify_host_smokes.sh
``` ```

1158
text15.txt

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,17 @@ This directory is the standalone workspace for the WASM-based simulation port.
Start from `docs/project-release-handoff.md` for the current project-level Start from `docs/project-release-handoff.md` for the current project-level
handoff. It links the browser/UI workflow surface, SDK surface, handoff. It links the browser/UI workflow surface, SDK surface,
OPFS/session persistence scope, sim-config coverage baseline, blocked OPFS/session persistence scope, sim-config coverage baseline, blocked
host/runtime families, source reuse rules, drift rules, and acceptance tracker. host/runtime families, source reuse rules, drift rules, the real browser
simulation priority constraint, and acceptance tracker.
The first priority for subsequent work is documented in
`docs/real-browser-simulation-priority.md`: move quickly toward a real browser
CNC simulation page with visible machine/session loading, G-code program state,
LinuxCNC-backed interpreter execution, and browser smoke coverage. This does
not relax the LinuxCNC semantic boundary; browser code still must not implement
G-code, tool, parameter, kinematics, remap, or planner semantics.
The first real simulation entry point is `runtime/ui/simulation/index.html`,
validated by `tests/browser/verify_real_simulation_browser.sh`.
The project release gate for the current scope is: The project release gate for the current scope is:
@@ -35,6 +45,7 @@ project_release_handoff_docs_node_smoke=ok
opfs_session_docs_node_smoke=ok opfs_session_docs_node_smoke=ok
sim_configs_coverage_docs_node_smoke=ok sim_configs_coverage_docs_node_smoke=ok
host_runtime_boundary_docs_node_smoke=ok host_runtime_boundary_docs_node_smoke=ok
real_browser_simulation_priority_docs_node_smoke=ok
sdk_surface_node_smoke=ok sdk_surface_node_smoke=ok
host_wasm_opfs_browser_smokes=ok host_wasm_opfs_browser_smokes=ok
project_release_gate=ok project_release_gate=ok
@@ -174,6 +185,8 @@ Directory intent:
Project-level OPFS/session persistence and release-gate handoff is documented in Project-level OPFS/session persistence and release-gate handoff is documented in
`docs/opfs-session-persistence.md`. `docs/opfs-session-persistence.md`.
The real browser CNC simulation page priority is documented in
`docs/real-browser-simulation-priority.md`.
Sim-config inventory coverage and release-gate handoff is documented in Sim-config inventory coverage and release-gate handoff is documented in
`docs/sim-configs-coverage-handoff.md`. `docs/sim-configs-coverage-handoff.md`.
Host/runtime boundary release-gate handoff is documented in Host/runtime boundary release-gate handoff is documented in

View File

@@ -163,6 +163,31 @@ when an outer shell needs to validate a project release readiness artifact JSON
through the same read-only workflow overview surface. It parses the artifact, through the same read-only workflow overview surface. It parses the artifact,
returns stable validation rows, and does not execute release gates or CNC returns stable validation rows, and does not execute release gates or CNC
behavior. behavior.
Use `runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow()` or
`linuxCncIniPanelWorkflowOverviewApi.runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow()`
when the shell already has artifact JSON and needs parse, validation, summary,
action-plan, and gate execution summary output in one workflow result.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel()` or
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel()`
when the shell needs the artifact's release gate execution summary rows.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness()`,
`renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()`, or
`mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()` when the
shell needs to render those per-gate rows into caller-owned DOM.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel()` or
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel()`
when the shell needs stable status text and rows for that JSON workflow.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan()` or
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan()`
when the shell needs the JSON workflow next-command plan without inspecting
internal workflow fields.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness()`,
`renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()`, or
`mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()` when the
shell needs to render that JSON workflow state into caller-owned DOM.
Use `loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl()` or Use `loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl()` or
`linuxCncIniPanelWorkflowOverviewApi.loadWorkflowOverviewReleaseReadinessArtifactUrl()` `linuxCncIniPanelWorkflowOverviewApi.loadWorkflowOverviewReleaseReadinessArtifactUrl()`
when the shell should fetch the artifact JSON URL, validate it, and optionally when the shell should fetch the artifact JSON URL, validate it, and optionally
@@ -173,10 +198,30 @@ Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSumma
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel()` `linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel()`
when the shell needs one stable status line and dashboard rows for the whole when the shell needs one stable status line and dashboard rows for the whole
artifact URL fetch/validate/render/mount workflow. artifact URL fetch/validate/render/mount workflow.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness()`,
`renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()`, or
`mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()` when the
shell needs to render that URL workflow state into caller-owned DOM.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan()` or
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan()`
when the shell needs the ordered next-action/next-command plan for that URL
workflow without executing release gates.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel()` or Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel()` or
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel()` `linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel()`
when the shell needs stable artifact validation status text and dashboard rows when the shell needs stable artifact validation status text and dashboard rows
without interpreting validation flags itself. without interpreting validation flags itself.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan()` or
`linuxCncIniPanelWorkflowOverviewApi.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan()`
when direct artifact JSON validation needs its own ordered next-command plan
without executing release gates.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness()`,
`renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()`, or
`mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()` when the
shell needs to render that validation action plan into caller-owned DOM.
Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel()`, Use `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState()`, `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract()`, `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract()`,

View File

@@ -13,6 +13,8 @@ Use these documents as the current handoff set:
- `docs/panel-entry.md` for browser/UI entry points and shell handoff helpers. - `docs/panel-entry.md` for browser/UI entry points and shell handoff helpers.
- `runtime/sdk/README.md` for stable SDK imports from `runtime/sdk/src/index.js`. - `runtime/sdk/README.md` for stable SDK imports from `runtime/sdk/src/index.js`.
- `docs/opfs-session-persistence.md` for OPFS/session persistence scope. - `docs/opfs-session-persistence.md` for OPFS/session persistence scope.
- `docs/real-browser-simulation-priority.md` for the standing first priority:
build the real browser CNC simulation page before lower-value metadata work.
- `docs/sim-configs-coverage-handoff.md` for sim-config inventory status. - `docs/sim-configs-coverage-handoff.md` for sim-config inventory status.
- `docs/host-runtime-boundary-handoff.md` for blocked runtime families. - `docs/host-runtime-boundary-handoff.md` for blocked runtime families.
- `docs/source-reuse-map.md` and `docs/drift-report.md` for LinuxCNC source - `docs/source-reuse-map.md` and `docs/drift-report.md` for LinuxCNC source
@@ -24,6 +26,26 @@ continuation records are in `../text15.txt`.
## Supported current workflows ## Supported current workflows
## First Priority Constraint
Subsequent work must prioritize a real browser CNC simulation page. The page
should converge on visible machine/session loading, G-code program state,
LinuxCNC-backed interpreter execution, machine readiness/status panels, and a
toolpath/preview area backed by LinuxCNC-produced output or validated runtime
events. The authoritative constraint is
`docs/real-browser-simulation-priority.md`.
Its executable docs gate is
`verify_real_browser_simulation_priority_docs.sh`, which is included in the
host smoke and project release gate and ends with
`real_browser_simulation_priority_docs_node_smoke=ok`.
The first implementation entry point is `runtime/ui/simulation/index.html`,
validated by `verify_real_simulation_browser.sh`, which ends with
`browser_real_simulation_page_smoke=ok`.
This priority does not permit JavaScript-owned CNC semantics. G-code, tool,
parameter, kinematics, remap, planner, and canonical motion behavior must remain
owned by vendored LinuxCNC source and existing LinuxCNC-backed WASM boundaries.
- INI panel launch, edit/run page, read-only control page, workflow overview, - INI panel launch, edit/run page, read-only control page, workflow overview,
and external shell handoff are exposed from `runtime/ui/ini-panel/`. and external shell handoff are exposed from `runtime/ui/ini-panel/`.
- External shells should use the read-only helpers documented in - External shells should use the read-only helpers documented in
@@ -76,15 +98,86 @@ continuation records are in `../text15.txt`.
that SDK URL workflow into stable dashboard rows and status text. that SDK URL workflow into stable dashboard rows and status text.
`createProjectReleaseReadinessArtifactUrlWorkflowActionPlan()` turns blocked `createProjectReleaseReadinessArtifactUrlWorkflowActionPlan()` turns blocked
URL workflows into ordered input, fetch, and command actions for CI tooling. URL workflows into ordered input, fetch, and command actions for CI tooling.
`createProjectBatchAcceptanceCapabilityMatrix()` classifies per-batch evidence
into accepted API/workflow/gate/browser capabilities and rejected entries.
`createProjectBatchAcceptanceWorkflow()` records the per-batch acceptance rule
that each batch must ship at least one callable API, verifiable workflow,
executable gate, or browser capability. Its summary view-model and action-plan
helpers provide dashboard rows and the next batch-acceptance gate command.
`createProjectBatchAcceptanceChecklist()` combines those results into
pass/blocked checklist rows for external release dashboards.
`createProjectBatchAcceptanceReport()` packages the matrix, workflow,
summary, action plan, and checklist into one stable CI/dashboard object.
`createProjectBatchAcceptanceReportValidation()` and
`createProjectBatchAcceptanceReportJsonWorkflow()` validate that object from
parsed data or JSON text without throwing.
`createProjectBatchAcceptanceReportValidationSummaryViewModel()` and
`createProjectBatchAcceptanceReportValidationActionPlan()` expose dashboard
rows and the next artifact gate command for blocked report validation.
`loadProjectBatchAcceptanceReportUrlWorkflow()` fetches hosted batch
acceptance report JSON through a caller-provided `fetch` implementation, then
runs the same validation workflow without throwing.
`createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel()` and
`createProjectBatchAcceptanceReportUrlWorkflowActionPlan()` expose dashboard
rows and ordered input/fetch/gate actions for that URL workflow.
The executable batch acceptance gate writes
`build/project-batch-acceptance.json` with
`write_project_batch_acceptance_artifact.mjs` and validates it through
`verify_project_batch_acceptance_artifact.sh`, ending with
`project_batch_acceptance_artifact_node_smoke=ok`.
Workflow overview shells can use
`getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel()`
and
`getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel()`
to display the embedded release gate execution summary without parsing
artifact internals. They can render or mount those per-gate rows through
`getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState()`,
`getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract()`,
`getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness()`,
`renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()`, and
`mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()`, and
`getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan()` to show
the URL workflow next action or command without executing gates. Direct JSON
validation callers can use
`getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan()` for the
artifact-validation next-command plan. They can render or mount that action
plan through
`getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState()`,
`getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract()`,
`getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness()`,
`renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()`, and
`mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()`.
Browser shells can also pass the JSON to Browser shells can also pass the JSON to
`linuxCncIniPanelWorkflowOverviewApi.validateWorkflowOverviewReleaseReadinessArtifactJson()` `linuxCncIniPanelWorkflowOverviewApi.validateWorkflowOverviewReleaseReadinessArtifactJson()`
through the workflow overview iframe and receive stable validation rows. They through the workflow overview iframe and receive stable validation rows. They
can call `runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow()` when they
need parse, validation, summary, action-plan, and gate execution summary
output in one workflow result, and
`getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel()`
when they need stable dashboard rows for that JSON workflow. The JSON
workflow action plan is available through
`getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan()`. They
can render or mount the JSON workflow state into caller-owned DOM through
`getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract()`,
`getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness()`,
`renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()`, and
`mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()`. They
can also call can also call
`linuxCncIniPanelWorkflowOverviewApi.loadWorkflowOverviewReleaseReadinessArtifactUrl()` `linuxCncIniPanelWorkflowOverviewApi.loadWorkflowOverviewReleaseReadinessArtifactUrl()`
to fetch the artifact URL, validate it, and optionally mount the resulting to fetch the artifact URL, validate it, and optionally mount the resulting
read-only render state. That URL workflow includes a validation summary read-only render state. That URL workflow includes a validation summary
view-model and can be summarized with view-model and can be summarized with
`getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel()`. `getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel()`.
The same workflow can expose the ordered next-action plan through
`getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan()`. Shells
can render or mount the URL workflow state through
`getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState()`,
`getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract()`,
`getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness()`,
`renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()`, and
`mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()`.
Direct artifact JSON validation can expose its own next-command plan through
`getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan()`.
When the outer shell needs DOM output, the workflow When the outer shell needs DOM output, the workflow
overview iframe also exposes overview iframe also exposes
display, render-state, DOM readiness, renderer, and mount helpers for the display, render-state, DOM readiness, renderer, and mount helpers for the
@@ -126,6 +219,7 @@ SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.
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_ini_panel_browser.sh
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_opfs_session_workflow_browser.sh SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_opfs_session_workflow_browser.sh
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh
wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh
wasm-port/tests/ui/node/verify_ui_node_smokes.sh wasm-port/tests/ui/node/verify_ui_node_smokes.sh
wasm-port/tests/sdk/node/verify_project_release_artifact_url_workflow.sh wasm-port/tests/sdk/node/verify_project_release_artifact_url_workflow.sh
wasm-port/tests/host/verify_host_smokes.sh wasm-port/tests/host/verify_host_smokes.sh
@@ -166,6 +260,7 @@ opfs_session_docs_node_smoke=ok
sim_configs_coverage_docs_node_smoke=ok sim_configs_coverage_docs_node_smoke=ok
host_runtime_boundary_docs_node_smoke=ok host_runtime_boundary_docs_node_smoke=ok
sdk_surface_node_smoke=ok sdk_surface_node_smoke=ok
project_batch_acceptance_workflow_node_smoke=ok
project_release_artifact_url_workflow_node_smoke=ok project_release_artifact_url_workflow_node_smoke=ok
``` ```

View File

@@ -0,0 +1,82 @@
# Real Browser Simulation Priority
This document is a standing project constraint for all work after 2026-06-16.
## Primary Objective
The first priority is to deliver a real browser CNC simulation page, not more
project metadata or dashboard-only helpers. Future batches should prefer
visible, interactive browser capability that moves the product toward an
operator-usable CNC simulation surface.
The target page must become a real CNC simulation page with:
- a machine/session loader backed by the existing OPFS/session workflow;
- a G-code program view backed by persisted or staged program text;
- LinuxCNC-backed interpreter execution through the existing WASM SDK;
- machine state panels for run status, active program, machine files, and
missing readiness;
- a toolpath/preview area driven by LinuxCNC-produced interpreter/canonical
output or existing validated runtime events, not JavaScript-owned CNC
semantics;
- browser smoke coverage that proves the page loads, renders nonempty runtime
state, and can run a representative LinuxCNC-backed program flow.
The first implementation entry point is:
```text
runtime/ui/simulation/index.html
```
Its browser gate is:
```bash
wasm-port/tests/browser/verify_real_simulation_browser.sh
```
## Batch Priority
Unless a user explicitly changes priority, choose work in this order:
1. Real UI/browser simulation page capability.
2. Browser workflow smoke for that simulation capability.
3. UI APIs needed by the simulation page.
4. OPFS/session integration needed by the simulation page.
5. SDK/API helpers only when they directly unblock the simulation page.
6. Documentation or release metadata only when it creates an executable gate or
protects the simulation-page direction.
Every implementation batch still must produce at least one callable API,
verifiable workflow, executable gate, or real UI/browser capability.
## Boundary Rules
The browser simulation page must not implement CNC semantics in JavaScript.
G-code interpretation, canonical motion behavior, tool semantics, parameter
semantics, kinematics, remap behavior, and planner behavior must remain owned by
vendored LinuxCNC source and existing LinuxCNC-backed WASM C ABI boundaries.
JavaScript/browser code may own:
- layout and interaction state;
- OPFS/session persistence;
- file staging into the Emscripten filesystem;
- calls into the SDK/WASM boundary;
- rendering LinuxCNC-produced output, canonical events, and validated runtime
summaries;
- non-CNC UI state such as selected file, active tab, viewport mode, and
validation messages.
## Required Evidence
The priority is enforced by:
```bash
wasm-port/tests/docs/node/verify_real_browser_simulation_priority_docs.sh
wasm-port/tests/host/verify_host_smokes.sh
wasm-port/tests/host/verify_project_release_gate.sh
```
The docs gate must verify that this priority document, the release handoff, the
README, and `PROJECT_COMPLETION_TRACKER.md` all point future work toward a real
browser CNC simulation page while preserving the LinuxCNC semantic boundary.

View File

@@ -44,8 +44,27 @@ import {
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState,
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
createLinuxCncIniSdk, createLinuxCncIniSdk,
createLinuxCncInterpSdk, createLinuxCncInterpSdk,
@@ -87,14 +106,35 @@ import {
machineFilePaths, machineFilePaths,
machineIniPath, machineIniPath,
mountIniPanelShellWorkflowOverviewEmbeddingMountState, mountIniPanelShellWorkflowOverviewEmbeddingMountState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactState, mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactState,
normalizeOpfsPath, normalizeOpfsPath,
parameterFilePath, parameterFilePath,
parseProjectReleaseReadinessArtifactJson, parseProjectReleaseReadinessArtifactJson,
planIniFileContextStaging, planIniFileContextStaging,
planSimConfigStaging, planSimConfigStaging,
createProjectBatchAcceptanceActionPlan,
createProjectBatchAcceptanceCapabilityMatrix,
createProjectBatchAcceptanceChecklist,
createProjectBatchAcceptanceReport,
createProjectBatchAcceptanceReportJsonWorkflow,
createProjectBatchAcceptanceReportUrlWorkflowActionPlan,
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel,
createProjectBatchAcceptanceReportValidationActionPlan,
createProjectBatchAcceptanceReportValidationSummaryViewModel,
createProjectBatchAcceptanceReportValidation,
createProjectBatchAcceptanceSummaryViewModel,
createProjectBatchAcceptanceWorkflow,
loadProjectBatchAcceptanceReportUrlWorkflow,
readMachineSessionReadiness, readMachineSessionReadiness,
renderIniPanelShellWorkflowOverviewEmbeddingMountState, renderIniPanelShellWorkflowOverviewEmbeddingMountState,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactState, renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactState,
restoreMachineParametersFromOpfs, restoreMachineParametersFromOpfs,
saveMachineSessionSnapshot, saveMachineSessionSnapshot,
@@ -227,6 +267,35 @@ such as `project_release_gate=ok` or explicit gate results.
`createProjectReleaseReadinessSummaryViewModel()` turns the report into stable `createProjectReleaseReadinessSummaryViewModel()` turns the report into stable
status text, a status line, and display rows for dashboards without executing status text, a status line, and display rows for dashboards without executing
any gate. any gate.
`createProjectBatchAcceptanceCapabilityMatrix()` normalizes per-batch evidence
and classifies accepted `api`, `workflow`, `gate`, and `browser` capabilities
separately from rejected docs-only or unknown entries.
`createProjectBatchAcceptanceWorkflow()` packages that capability matrix with
release-gate evidence for the project rule that each batch must produce at
least one callable API, verifiable workflow, executable gate, or browser
capability. The companion
`createProjectBatchAcceptanceSummaryViewModel()` and
`createProjectBatchAcceptanceActionPlan()` helpers make that evidence
dashboard-friendly and provide the next gate command when the batch acceptance
smoke has not been observed. `createProjectBatchAcceptanceChecklist()` combines
the capability matrix, gate evidence, and action plan into pass/blocked rows
for release dashboards. `createProjectBatchAcceptanceReport()` packages the
matrix, workflow, summary, action plan, and checklist into one stable object
for external CI or release dashboards.
`createProjectBatchAcceptanceReportValidation()` validates that report shape
without copying test assertions.
`createProjectBatchAcceptanceReportValidationSummaryViewModel()` and
`createProjectBatchAcceptanceReportValidationActionPlan()` expose dashboard rows
and the next artifact gate command for blocked report validation.
`createProjectBatchAcceptanceReportJsonWorkflow()` is the non-throwing JSON
workflow for external CI systems that exchange batch acceptance reports as
strings.
`loadProjectBatchAcceptanceReportUrlWorkflow()` is the fetch-driven URL
workflow for hosted batch acceptance reports. It returns fetch status, the JSON
workflow, report validation, and missing evidence without throwing.
`createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel()` and
`createProjectBatchAcceptanceReportUrlWorkflowActionPlan()` turn the same URL
workflow into dashboard rows and ordered input/fetch/gate actions.
This helper does not execute shell commands and does not inspect or implement This helper does not execute shell commands and does not inspect or implement
CNC behavior. It only packages project-level release evidence and blocked CNC behavior. It only packages project-level release evidence and blocked
@@ -273,6 +342,13 @@ dedicated executable SDK gate for that URL workflow. It verifies caller-provided
fetch handling, ready summaries, action plans, missing input, HTTP failure, fetch handling, ready summaries, action plans, missing input, HTTP failure,
thrown fetch errors, and ends with thrown fetch errors, and ends with
`project_release_artifact_url_workflow_node_smoke=ok`. `project_release_artifact_url_workflow_node_smoke=ok`.
`tests/sdk/node/verify_project_batch_acceptance_workflow.sh` is the executable
SDK gate for the per-batch acceptance workflow. It runs the workflow smoke,
writes `build/project-batch-acceptance.json` through
`write_project_batch_acceptance_artifact.mjs`, validates that artifact through
`verify_project_batch_acceptance_artifact.sh`, and emits
`project_batch_acceptance_workflow_node_smoke=ok` before ending with
`project_batch_acceptance_artifact_node_smoke=ok`.
## OPFS/session persistence exports ## OPFS/session persistence exports
@@ -339,12 +415,57 @@ for external browser shells:
- `validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson()` for the - `validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson()` for the
read-only workflow overview artifact validation wrapper exposed by read-only workflow overview artifact validation wrapper exposed by
`workflow-overview.html`. Use `workflow-overview.html`. Use
`runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow()` when
a shell already has artifact JSON and needs parse, validation, summary,
action-plan, and gate execution summary output in one non-throwing workflow.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel()`
turns that JSON workflow into stable dashboard status text and rows.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan()`
exposes the JSON workflow next-command plan without requiring callers to read
internal workflow fields.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness()`,
`renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()`,
and `mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()`
let a shell render or mount that JSON workflow render-state into caller-owned
DOM without executing release gate commands.
Use
`loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl()` when a `loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl()` when a
browser or shell should fetch the artifact JSON URL, validate it, and browser or shell should fetch the artifact JSON URL, validate it, and
optionally mount the resulting render-state into caller-owned DOM. The URL optionally mount the resulting render-state into caller-owned DOM. The URL
workflow result includes `validationSummaryViewModel` for dashboards. workflow result includes `validationSummaryViewModel` and
`gateExecutionSummaryViewModel` for dashboards.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel()` `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel()`
turns the full URL workflow result into stable status text and rows. turns the full URL workflow result into stable status text and rows.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan()`
exposes the same URL workflow next-action/next-command plan through the
browser workflow overview surface.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness()`,
`renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()`,
and `mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()`
let callers render the URL workflow status into their own DOM.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan()`
exposes the direct artifact-validation next-command plan when callers already
have parsed or validated artifact JSON.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness()`,
`renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()`,
and `mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()`
let callers render that validation action plan into caller-owned DOM.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel()`
and
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel()`
expose the embedded release gate execution summary for external shells without
requiring callers to parse artifact internals.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness()`,
`renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()`,
and `mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()`
let callers render the per-gate execution summary rows into caller-owned DOM.
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel()`, `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState()`, `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState()`,
`createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel()`, `createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel()`,

View File

@@ -1,6 +1,18 @@
export { createLinuxCncIniSdk } from "./linuxcnc-ini.js"; export { createLinuxCncIniSdk } from "./linuxcnc-ini.js";
export { createLinuxCncInterpSdk } from "./linuxcnc-interp.js"; export { createLinuxCncInterpSdk } from "./linuxcnc-interp.js";
export { export {
createProjectBatchAcceptanceActionPlan,
createProjectBatchAcceptanceCapabilityMatrix,
createProjectBatchAcceptanceChecklist,
createProjectBatchAcceptanceReport,
createProjectBatchAcceptanceReportJsonWorkflow,
createProjectBatchAcceptanceReportUrlWorkflowActionPlan,
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel,
createProjectBatchAcceptanceReportValidationActionPlan,
createProjectBatchAcceptanceReportValidationSummaryViewModel,
createProjectBatchAcceptanceReportValidation,
createProjectBatchAcceptanceSummaryViewModel,
createProjectBatchAcceptanceWorkflow,
createProjectReleaseGateActionPlan, createProjectReleaseGateActionPlan,
createProjectReleaseGateExecutionManifest, createProjectReleaseGateExecutionManifest,
createProjectReleaseGateExecutionSummaryViewModel, createProjectReleaseGateExecutionSummaryViewModel,
@@ -14,6 +26,7 @@ export {
createProjectReleaseReadinessArtifactValidationSummaryViewModel, createProjectReleaseReadinessArtifactValidationSummaryViewModel,
createProjectReleaseReadinessReport, createProjectReleaseReadinessReport,
createProjectReleaseReadinessSummaryViewModel, createProjectReleaseReadinessSummaryViewModel,
loadProjectBatchAcceptanceReportUrlWorkflow,
loadProjectReleaseReadinessArtifactUrlWorkflow, loadProjectReleaseReadinessArtifactUrlWorkflow,
parseProjectReleaseReadinessArtifactJson, parseProjectReleaseReadinessArtifactJson,
} from "./project-release-readiness.js"; } from "./project-release-readiness.js";
@@ -109,8 +122,27 @@ export {
createIniPanelShellWorkflowOverviewEmbeddingMountRenderState, createIniPanelShellWorkflowOverviewEmbeddingMountRenderState,
createIniPanelShellWorkflowOverviewEmbeddingRenderState, createIniPanelShellWorkflowOverviewEmbeddingRenderState,
createIniPanelShellWorkflowOverviewEmbeddingReport, createIniPanelShellWorkflowOverviewEmbeddingReport,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness,
@@ -125,6 +157,14 @@ export {
isSupportedIniPanelShellSessionHandoffPackage, isSupportedIniPanelShellSessionHandoffPackage,
isSupportedIniPanelShellSessionHandoffSummary, isSupportedIniPanelShellSessionHandoffSummary,
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellSessionHandoff, mountIniPanelShellSessionHandoff,
mountIniPanelShellWorkflowOverviewEmbedding, mountIniPanelShellWorkflowOverviewEmbedding,
mountIniPanelShellWorkflowOverviewEmbeddingMountState, mountIniPanelShellWorkflowOverviewEmbeddingMountState,

View File

@@ -46,6 +46,12 @@ const REQUIRED_RELEASE_GATES = [
command: "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh", command: "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh",
expectedOutput: "browser_release_artifact_url_workflow_smoke=ok", expectedOutput: "browser_release_artifact_url_workflow_smoke=ok",
}, },
{
id: "project-batch-acceptance",
label: "Project batch acceptance workflow smoke",
command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
expectedOutput: "project_batch_acceptance_workflow_node_smoke=ok",
},
{ {
id: "ui-node-smokes", id: "ui-node-smokes",
label: "UI Node smokes", label: "UI Node smokes",
@@ -336,6 +342,864 @@ export function createProjectReleaseGateActionPlan({
}; };
} }
const BATCH_ACCEPTANCE_CAPABILITY_TYPES = [
"api",
"workflow",
"gate",
"browser",
];
function normalizeBatchCapabilities(capabilities) {
return arrayOrEmpty(capabilities)
.map((capability) => objectOrEmpty(capability))
.filter(({ id, type }) => typeof id === "string" && typeof type === "string")
.map((capability) => ({
id: capability.id,
type: capability.type,
label: capability.label ?? capability.id,
evidence: capability.evidence ?? null,
command: capability.command ?? null,
}));
}
export function createProjectBatchAcceptanceCapabilityMatrix({
capabilities = [],
} = {}) {
const normalizedCapabilities = normalizeBatchCapabilities(capabilities);
const acceptedCapabilities = normalizedCapabilities.filter(({ type }) =>
BATCH_ACCEPTANCE_CAPABILITY_TYPES.includes(type)
);
const rejectedCapabilities = normalizedCapabilities.filter(({ type }) =>
!BATCH_ACCEPTANCE_CAPABILITY_TYPES.includes(type)
);
const capabilityTypes = [...new Set(acceptedCapabilities.map(({ type }) => type))];
const countsByType = BATCH_ACCEPTANCE_CAPABILITY_TYPES.reduce((counts, type) => ({
...counts,
[type]: acceptedCapabilities.filter((capability) => capability.type === type).length,
}), {});
const missing = acceptedCapabilities.length > 0 ? [] : ["batch-capability"];
return {
apiName: "project-batch-acceptance-capability-matrix",
matrixVersion: 1,
phase: missing.length === 0 ? "ready" : "blocked",
ready: missing.length === 0,
acceptedCapabilityTypes: BATCH_ACCEPTANCE_CAPABILITY_TYPES,
capabilityTypes,
capabilityCount: acceptedCapabilities.length,
acceptedCount: acceptedCapabilities.length,
rejectedCount: rejectedCapabilities.length,
countsByType,
capabilities: acceptedCapabilities,
rejectedCapabilities,
missing,
rows: [
{
id: "accepted-capabilities",
label: "Accepted capabilities",
value: `${acceptedCapabilities.length}`,
},
{
id: "accepted-types",
label: "Accepted capability types",
value: capabilityTypes.join(", ") || "none",
},
{
id: "rejected-capabilities",
label: "Rejected capabilities",
value: `${rejectedCapabilities.length}`,
},
{
id: "missing",
label: "Missing capability evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
export function createProjectBatchAcceptanceWorkflow({
batchId = "current-batch",
capabilities = [],
gateResults = {},
observedOutputs = [],
} = {}) {
const capabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({ capabilities });
const gateManifest = createProjectReleaseGateManifest();
const gateResultMatrix = createProjectReleaseGateResultMatrix({
gateResults,
observedOutputs,
manifest: gateManifest,
});
const batchGatePassed = gateResultMatrix.rows
.find(({ id }) => id === "project-batch-acceptance")?.passed === true;
const ready = capabilityMatrix.ready && batchGatePassed;
const missing = [
...capabilityMatrix.missing,
...(batchGatePassed ? [] : ["project-batch-acceptance"]),
];
return {
apiName: "project-batch-acceptance-workflow",
workflowVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
batchId,
acceptedCapabilityTypes: capabilityMatrix.acceptedCapabilityTypes,
capabilityTypes: capabilityMatrix.capabilityTypes,
capabilityCount: capabilityMatrix.capabilityCount,
capabilityMatrix,
capabilities: capabilityMatrix.capabilities,
rejectedCapabilities: capabilityMatrix.rejectedCapabilities,
gateResultMatrix,
missing,
rows: [
{
id: "batch",
label: "Batch",
value: batchId,
},
{
id: "capabilities",
label: "Accepted capabilities",
value: capabilityMatrix.capabilityTypes.join(", ") || "none",
},
{
id: "project-batch-acceptance",
label: "Batch acceptance gate",
value: batchGatePassed ? "passed" : "unknown",
},
{
id: "missing",
label: "Missing acceptance evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
export function createProjectBatchAcceptanceSummaryViewModel(
workflow = createProjectBatchAcceptanceWorkflow(),
) {
const missing = arrayOrEmpty(workflow?.missing);
const ready = workflow?.ready === true;
const statusText = ready ? "Ready" : "Blocked";
const detailText = ready
? "Batch acceptance evidence complete"
: (missing.length > 0 ? missing.join(", ") : "batch acceptance evidence missing");
return {
apiName: "project-batch-acceptance-summary-view-model",
viewModelVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Project batch acceptance",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows: [
{
id: "batch",
label: "Batch",
value: workflow?.batchId ?? "current-batch",
},
{
id: "capability-count",
label: "Accepted capability count",
value: `${workflow?.capabilityCount ?? 0}`,
},
{
id: "capability-types",
label: "Accepted capability types",
value: arrayOrEmpty(workflow?.capabilityTypes).join(", ") || "none",
},
{
id: "missing",
label: "Missing acceptance evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
export function createProjectBatchAcceptanceActionPlan(
workflow = createProjectBatchAcceptanceWorkflow(),
) {
const missing = arrayOrEmpty(workflow?.missing);
const ready = workflow?.ready === true;
const commands = ready ? [] : [
...(missing.includes("project-batch-acceptance")
? [{
step: 1,
id: "project-batch-acceptance",
label: "Run project batch acceptance workflow smoke",
command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
expectedOutput: "project_batch_acceptance_workflow_node_smoke=ok",
}]
: []),
];
const shellScript = commands.length > 0
? [
"#!/usr/bin/env bash",
"set -euo pipefail",
"",
...commands.map(({ command }) => command),
"",
].join("\n")
: (ready
? "# Project batch acceptance workflow is already ready.\n"
: "# Project batch acceptance workflow requires at least one API, workflow, gate, or browser capability.\n");
return {
apiName: "project-batch-acceptance-action-plan",
planVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
commandCount: commands.length,
nextActionId: commands[0]?.id ?? (missing[0] ?? null),
nextCommand: commands[0]?.command ?? null,
commands,
shellScript,
rows: [
{
id: "batch-acceptance",
label: "Batch acceptance",
value: ready ? "ready" : "blocked",
},
{
id: "missing",
label: "Missing acceptance evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
{
id: "next-command",
label: "Next command",
value: commands[0]?.command ?? "none",
},
],
};
}
export function createProjectBatchAcceptanceChecklist({
workflow = createProjectBatchAcceptanceWorkflow(),
actionPlan = createProjectBatchAcceptanceActionPlan(workflow),
} = {}) {
const capabilityMatrix = objectOrEmpty(workflow?.capabilityMatrix);
const ready = workflow?.ready === true;
const items = [
{
id: "accepted-capability",
label: "At least one API, workflow, gate, or browser capability",
status: capabilityMatrix.ready === true ? "pass" : "blocked",
passed: capabilityMatrix.ready === true,
detail: arrayOrEmpty(workflow?.capabilityTypes).join(", ") || "none",
},
{
id: "batch-acceptance-gate",
label: "Batch acceptance gate evidence",
status: !arrayOrEmpty(workflow?.missing).includes("project-batch-acceptance") ? "pass" : "blocked",
passed: !arrayOrEmpty(workflow?.missing).includes("project-batch-acceptance"),
detail: workflow?.gateResultMatrix?.rows
?.find?.(({ id }) => id === "project-batch-acceptance")?.status ?? "unknown",
},
{
id: "next-action",
label: "Next acceptance action",
status: actionPlan?.nextActionId ? "blocked" : "pass",
passed: !actionPlan?.nextActionId,
detail: actionPlan?.nextCommand ?? "none",
},
];
return {
apiName: "project-batch-acceptance-checklist",
checklistVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
batchId: workflow?.batchId ?? "current-batch",
passedCount: items.filter(({ passed }) => passed).length,
blockedCount: items.filter(({ passed }) => !passed).length,
items,
rows: items.map(({ id, label, status, detail }) => ({
id,
label,
value: `${status}: ${detail}`,
})),
};
}
export function createProjectBatchAcceptanceReport({
batchId = "current-batch",
capabilities = [],
gateResults = {},
observedOutputs = [],
} = {}) {
const capabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({ capabilities });
const workflow = createProjectBatchAcceptanceWorkflow({
batchId,
capabilities,
gateResults,
observedOutputs,
});
const summaryViewModel = createProjectBatchAcceptanceSummaryViewModel(workflow);
const actionPlan = createProjectBatchAcceptanceActionPlan(workflow);
const checklist = createProjectBatchAcceptanceChecklist({ workflow, actionPlan });
return {
apiName: "project-batch-acceptance-report",
reportVersion: 1,
phase: workflow.phase,
ready: workflow.ready,
batchId: workflow.batchId,
missing: [...workflow.missing],
capabilityMatrix,
workflow,
summaryViewModel,
actionPlan,
checklist,
rows: [
{
id: "summary",
label: "Batch acceptance summary",
value: summaryViewModel.statusLine,
},
{
id: "capabilities",
label: "Accepted capabilities",
value: capabilityMatrix.capabilityTypes.join(", ") || "none",
},
{
id: "checklist",
label: "Checklist",
value: `${checklist.passedCount}/${checklist.items.length} passed`,
},
{
id: "next-command",
label: "Next command",
value: actionPlan.nextCommand ?? "none",
},
],
};
}
export function createProjectBatchAcceptanceReportValidation(report = {}) {
const reportObject = objectOrEmpty(report);
const capabilityMatrix = objectOrEmpty(reportObject.capabilityMatrix);
const workflow = objectOrEmpty(reportObject.workflow);
const summaryViewModel = objectOrEmpty(reportObject.summaryViewModel);
const actionPlan = objectOrEmpty(reportObject.actionPlan);
const checklist = objectOrEmpty(reportObject.checklist);
const rows = arrayOrEmpty(reportObject.rows);
const missing = [
...(reportObject.apiName === "project-batch-acceptance-report" ? [] : ["apiName"]),
...(reportObject.reportVersion === 1 ? [] : ["reportVersion"]),
...(reportObject.phase === "ready" ? [] : ["phase"]),
...(reportObject.ready === true ? [] : ["ready"]),
...(Array.isArray(reportObject.missing) && reportObject.missing.length === 0 ? [] : ["missing"]),
...(capabilityMatrix.apiName === "project-batch-acceptance-capability-matrix"
&& capabilityMatrix.ready === true
? []
: ["capabilityMatrix"]),
...(workflow.apiName === "project-batch-acceptance-workflow" && workflow.ready === true
? []
: ["workflow"]),
...(summaryViewModel.apiName === "project-batch-acceptance-summary-view-model"
&& summaryViewModel.ready === true
? []
: ["summaryViewModel"]),
...(actionPlan.apiName === "project-batch-acceptance-action-plan" && actionPlan.ready === true
? []
: ["actionPlan"]),
...(checklist.apiName === "project-batch-acceptance-checklist" && checklist.ready === true
? []
: ["checklist"]),
...(rows.find(({ id, value }) => id === "checklist" && value === "3/3 passed")
? []
: ["rows.checklist"]),
];
return {
apiName: "project-batch-acceptance-report-validation",
validationVersion: 1,
phase: missing.length === 0 ? "ready" : "blocked",
ready: missing.length === 0,
missing,
batchId: reportObject.batchId ?? null,
reportApiName: reportObject.apiName ?? null,
reportVersion: reportObject.reportVersion ?? null,
rows: [
{
id: "report",
label: "Batch acceptance report",
value: reportObject.apiName ?? "missing",
},
{
id: "capability-matrix",
label: "Capability matrix",
value: capabilityMatrix.ready === true ? "ready" : "missing",
},
{
id: "workflow",
label: "Batch workflow",
value: workflow.ready === true ? "ready" : "missing",
},
{
id: "checklist",
label: "Checklist",
value: checklist.ready === true ? "ready" : "missing",
},
{
id: "missing",
label: "Missing report evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
export function createProjectBatchAcceptanceReportValidationSummaryViewModel(
validation = createProjectBatchAcceptanceReportValidation(),
) {
const missing = arrayOrEmpty(validation?.missing);
const ready = validation?.ready === true;
const statusText = ready ? "Ready" : "Blocked";
const detailText = ready
? "Batch acceptance report evidence complete"
: (missing.length > 0 ? missing.join(", ") : "batch acceptance report evidence missing");
return {
apiName: "project-batch-acceptance-report-validation-summary-view-model",
viewModelVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Project batch acceptance report validation",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows: [
{
id: "report",
label: "Batch acceptance report",
value: validation?.reportApiName ?? "missing",
},
{
id: "batch",
label: "Batch",
value: validation?.batchId ?? "missing",
},
{
id: "validation",
label: "Report validation",
value: ready ? "ready" : "blocked",
},
{
id: "missing",
label: "Missing report evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
export function createProjectBatchAcceptanceReportValidationActionPlan(
validation = createProjectBatchAcceptanceReportValidation(),
) {
const missing = arrayOrEmpty(validation?.missing);
const ready = validation?.ready === true;
const commands = ready ? [] : [
{
step: 1,
id: "project-batch-acceptance",
label: "Run project batch acceptance workflow and artifact gate",
command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
expectedOutput: "project_batch_acceptance_artifact_node_smoke=ok",
},
];
const shellScript = commands.length > 0
? [
"#!/usr/bin/env bash",
"set -euo pipefail",
"",
...commands.map(({ command }) => command),
"",
].join("\n")
: "# Project batch acceptance report validation is already ready.\n";
return {
apiName: "project-batch-acceptance-report-validation-action-plan",
planVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
missingCount: missing.length,
commandCount: commands.length,
nextActionId: commands[0]?.id ?? null,
nextCommand: commands[0]?.command ?? null,
commands,
shellScript,
rows: [
{
id: "report-validation",
label: "Report validation",
value: ready ? "ready" : "blocked",
},
{
id: "missing",
label: "Missing report evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
{
id: "next-command",
label: "Next command",
value: commands[0]?.command ?? "none",
},
],
};
}
export function createProjectBatchAcceptanceReportJsonWorkflow({ reportJson = "" } = {}) {
try {
const report = JSON.parse(String(reportJson));
const validation = createProjectBatchAcceptanceReportValidation(report);
return {
apiName: "project-batch-acceptance-report-json-workflow",
workflowVersion: 1,
phase: validation.ready ? "ready" : "blocked",
ready: validation.ready,
parsed: true,
parseError: null,
report,
validation,
missing: validation.missing,
rows: [
{
id: "parse",
label: "Batch report JSON parse",
value: "ready",
},
{
id: "validation",
label: "Batch report validation",
value: validation.ready ? "ready" : "blocked",
},
{
id: "missing",
label: "Missing report evidence",
value: validation.missing.length > 0 ? validation.missing.join(", ") : "none",
},
],
};
} catch (error) {
const validation = createProjectBatchAcceptanceReportValidation({});
return {
apiName: "project-batch-acceptance-report-json-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
parsed: false,
parseError: error?.message ?? "batch acceptance report JSON parse error",
report: null,
validation,
missing: ["report-json", ...validation.missing],
rows: [
{
id: "parse",
label: "Batch report JSON parse",
value: "blocked",
},
{
id: "validation",
label: "Batch report validation",
value: "blocked",
},
{
id: "missing",
label: "Missing report evidence",
value: ["report-json", ...validation.missing].join(", "),
},
],
};
}
}
export async function loadProjectBatchAcceptanceReportUrlWorkflow({
reportUrl = "",
fetchRef = globalThis.fetch,
} = {}) {
if (!reportUrl || typeof fetchRef !== "function") {
const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson: "" });
const missing = [
...(reportUrl ? [] : ["report-url"]),
...(typeof fetchRef === "function" ? [] : ["fetch"]),
...jsonWorkflow.missing,
];
return {
apiName: "project-batch-acceptance-report-url-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
reportUrl,
fetched: false,
httpStatus: null,
fetchError: null,
jsonWorkflow,
validation: jsonWorkflow.validation,
missing,
rows: [
{
id: "fetch",
label: "Batch report URL fetch",
value: "blocked",
},
{
id: "json-workflow",
label: "Batch report JSON workflow",
value: "blocked",
},
{
id: "missing",
label: "Missing report evidence",
value: missing.join(", "),
},
],
};
}
try {
const response = await fetchRef(reportUrl);
const httpStatus = response?.status ?? null;
if (!response?.ok) {
const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson: "" });
const fetchError = `batch report URL fetch failed${httpStatus ? `: ${httpStatus}` : ""}`;
return {
apiName: "project-batch-acceptance-report-url-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
reportUrl,
fetched: false,
httpStatus,
fetchError,
jsonWorkflow,
validation: jsonWorkflow.validation,
missing: ["report-fetch", ...jsonWorkflow.missing],
rows: [
{
id: "fetch",
label: "Batch report URL fetch",
value: "blocked",
},
{
id: "json-workflow",
label: "Batch report JSON workflow",
value: "blocked",
},
{
id: "missing",
label: "Missing report evidence",
value: ["report-fetch", ...jsonWorkflow.missing].join(", "),
},
],
};
}
const reportJson = await response.text();
const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson });
return {
apiName: "project-batch-acceptance-report-url-workflow",
workflowVersion: 1,
phase: jsonWorkflow.ready === true ? "ready" : "blocked",
ready: jsonWorkflow.ready === true,
reportUrl,
fetched: true,
httpStatus,
fetchError: null,
jsonWorkflow,
validation: jsonWorkflow.validation,
missing: jsonWorkflow.missing,
rows: [
{
id: "fetch",
label: "Batch report URL fetch",
value: "ready",
},
{
id: "json-workflow",
label: "Batch report JSON workflow",
value: jsonWorkflow.ready === true ? "ready" : "blocked",
},
{
id: "missing",
label: "Missing report evidence",
value: jsonWorkflow.missing.length > 0 ? jsonWorkflow.missing.join(", ") : "none",
},
],
};
} catch (error) {
const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson: "" });
return {
apiName: "project-batch-acceptance-report-url-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
reportUrl,
fetched: false,
httpStatus: null,
fetchError: error?.message ?? "batch report URL fetch error",
jsonWorkflow,
validation: jsonWorkflow.validation,
missing: ["report-fetch", ...jsonWorkflow.missing],
rows: [
{
id: "fetch",
label: "Batch report URL fetch",
value: "blocked",
},
{
id: "json-workflow",
label: "Batch report JSON workflow",
value: "blocked",
},
{
id: "missing",
label: "Missing report evidence",
value: ["report-fetch", ...jsonWorkflow.missing].join(", "),
},
],
};
}
}
export function createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel(
workflow = {},
) {
const missing = arrayOrEmpty(workflow?.missing);
const ready = workflow?.ready === true;
const statusText = ready ? "Ready" : "Blocked";
const detailText = ready
? "Batch report URL workflow complete"
: (missing.length > 0 ? missing.join(", ") : workflow?.fetchError ?? "batch report URL workflow blocked");
return {
apiName: "project-batch-acceptance-report-url-workflow-summary-view-model",
viewModelVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Project batch acceptance report URL workflow",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows: [
{
id: "report-url",
label: "Report URL",
value: workflow?.reportUrl || "missing",
},
{
id: "fetch",
label: "Fetch",
value: workflow?.fetched === true ? `ready${workflow?.httpStatus ? ` (${workflow.httpStatus})` : ""}` : "blocked",
},
{
id: "json-workflow",
label: "JSON workflow",
value: workflow?.jsonWorkflow?.ready === true ? "ready" : "blocked",
},
{
id: "report-validation",
label: "Report validation",
value: workflow?.validation?.ready === true ? "ready" : "blocked",
},
{
id: "missing",
label: "Missing workflow evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
export function createProjectBatchAcceptanceReportUrlWorkflowActionPlan(
workflow = {},
) {
const missing = arrayOrEmpty(workflow?.missing);
const ready = workflow?.ready === true;
const inputActions = [
...(missing.includes("report-url")
? [{
id: "provide-report-url",
label: "Provide project batch acceptance report URL",
kind: "input",
command: null,
expectedOutput: null,
}]
: []),
...(missing.includes("fetch")
? [{
id: "provide-fetch",
label: "Provide fetch implementation",
kind: "input",
command: null,
expectedOutput: null,
}]
: []),
...(missing.includes("report-fetch")
? [{
id: "verify-report-url-fetch",
label: "Verify project batch acceptance report URL fetch",
kind: "fetch",
command: null,
expectedOutput: null,
}]
: []),
];
const commandActions = ready ? [] : [
{
id: "project-batch-acceptance",
label: "Run project batch acceptance workflow smoke",
kind: "command",
command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
expectedOutput: "project_batch_acceptance_workflow_node_smoke=ok",
},
];
const actions = ready ? [] : [...inputActions, ...commandActions].map((action, index) => ({
step: index + 1,
...action,
}));
const commands = actions.filter(({ command }) => typeof command === "string" && command.length > 0);
const shellScript = commands.length > 0
? [
"#!/usr/bin/env bash",
"set -euo pipefail",
"",
...commands.map(({ command }) => command),
"",
].join("\n")
: (ready
? "# Project batch acceptance report URL workflow is already ready.\n"
: "# Project batch acceptance report URL workflow requires non-shell input.\n");
return {
apiName: "project-batch-acceptance-report-url-workflow-action-plan",
planVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
actionCount: actions.length,
commandCount: commands.length,
nextActionId: actions[0]?.id ?? null,
nextCommand: commands[0]?.command ?? null,
actions,
commands,
shellScript,
rows: actions.map(({ id, label, kind, command, expectedOutput }) => ({
id,
label,
kind,
value: command ?? kind,
expectedOutput,
})),
};
}
export function createProjectReleaseReadinessReport({ export function createProjectReleaseReadinessReport({
gateResults = {}, gateResults = {},
observedOutputs = [], observedOutputs = [],

View File

@@ -91,6 +91,7 @@
<a data-entry-id="edit-run" href="./index.html">Open edit and run panel</a> <a data-entry-id="edit-run" href="./index.html">Open edit and run panel</a>
<a data-entry-id="control-view" href="./control-page.html">Open read-only control view</a> <a data-entry-id="control-view" href="./control-page.html">Open read-only control view</a>
<a data-entry-id="workflow-overview" href="./workflow-overview.html">Open shell handoff overview</a> <a data-entry-id="workflow-overview" href="./workflow-overview.html">Open shell handoff overview</a>
<a data-entry-id="real-simulation" href="../simulation/index.html">Open real browser simulation</a>
</div> </div>
<section class="handoff-status" aria-label="Shell handoff compatibility" data-handoff-shell> <section class="handoff-status" aria-label="Shell handoff compatibility" data-handoff-shell>
<p data-handoff-status>Checking shell handoff compatibility.</p> <p data-handoff-status>Checking shell handoff compatibility.</p>
@@ -297,15 +298,124 @@
mountWorkflowOverviewEmbedding: (options) => ( mountWorkflowOverviewEmbedding: (options) => (
shellViewModel.mountWorkflowOverviewEmbedding(options) shellViewModel.mountWorkflowOverviewEmbedding(options)
), ),
runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow: (options) => (
shellViewModel.runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow(options)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel: (workflow) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(workflow)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan: (workflow) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan(workflow)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState: (summaryViewModel) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(summaryViewModel)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract: (options) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract(options)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness: (options) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness(
options ?? { documentRef: document },
)
),
renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState: (renderState, options) => (
shellViewModel.renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
renderState,
options ?? { documentRef: document },
)
),
mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState: (options) => (
shellViewModel.mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
options ?? { documentRef: document },
)
),
loadWorkflowOverviewReleaseReadinessArtifactUrl: (options) => ( loadWorkflowOverviewReleaseReadinessArtifactUrl: (options) => (
shellViewModel.loadWorkflowOverviewReleaseReadinessArtifactUrl(options) shellViewModel.loadWorkflowOverviewReleaseReadinessArtifactUrl(options)
), ),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: (workflow) => ( getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: (workflow) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(workflow) shellViewModel.createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(workflow)
), ),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan: (workflow) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(workflow)
),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState: (summaryViewModel) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(summaryViewModel)
),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract: (options) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract(options)
),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness: (options) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness(
options ?? { documentRef: document },
)
),
renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState: (renderState, options) => (
shellViewModel.renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
renderState,
options ?? { documentRef: document },
)
),
mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState: (options) => (
shellViewModel.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
options ?? { documentRef: document },
)
),
getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel: (validation) => ( getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel: (validation) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(validation) shellViewModel.createWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(validation)
), ),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan: (validation) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(validation)
),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState: (actionPlan) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(actionPlan)
),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract: (options) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract(options)
),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness: (options) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness(
options ?? { documentRef: document },
)
),
renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState: (renderState, options) => (
shellViewModel.renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
renderState,
options ?? { documentRef: document },
)
),
mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState: (options) => (
shellViewModel.mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
options ?? { documentRef: document },
)
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel: (validation) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(validation)
),
getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel: (workflow) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel(workflow)
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState: (summaryViewModel) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(summaryViewModel)
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract: (options) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract(options)
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness: (options) => (
shellViewModel.createWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness(
options ?? { documentRef: document },
)
),
renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState: (renderState, options) => (
shellViewModel.renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
renderState,
options ?? { documentRef: document },
)
),
mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState: (options) => (
shellViewModel.mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
options ?? { documentRef: document },
)
),
getWorkflowOverviewEmbeddingReport: (embeddingResult, contract) => ( getWorkflowOverviewEmbeddingReport: (embeddingResult, contract) => (
shellViewModel.createWorkflowOverviewEmbeddingReport(embeddingResult, contract) shellViewModel.createWorkflowOverviewEmbeddingReport(embeddingResult, contract)
), ),

File diff suppressed because it is too large Load Diff

View File

@@ -106,9 +106,36 @@
renderIniPanelShellWorkflowOverviewEmbeddingMountState, renderIniPanelShellWorkflowOverviewEmbeddingMountState,
mountIniPanelShellWorkflowOverviewEmbeddingMountState, mountIniPanelShellWorkflowOverviewEmbeddingMountState,
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson, validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson,
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract,
@@ -146,15 +173,124 @@
validateWorkflowOverviewReleaseReadinessArtifactJson: (artifactJson) => ( validateWorkflowOverviewReleaseReadinessArtifactJson: (artifactJson) => (
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(artifactJson) validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(artifactJson)
), ),
runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow: (options) => (
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow(options)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel: (workflow) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(workflow)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan: (workflow) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan(workflow)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState: (summaryViewModel) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(summaryViewModel)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract: (options) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract(options)
),
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness: (options) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness(
options ?? { documentRef: document },
)
),
renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState: (renderState, options) => (
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
renderState,
options ?? { documentRef: document },
)
),
mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState: (options) => (
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
options ?? { documentRef: document },
)
),
loadWorkflowOverviewReleaseReadinessArtifactUrl: (options) => ( loadWorkflowOverviewReleaseReadinessArtifactUrl: (options) => (
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl(options) loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl(options)
), ),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: (workflow) => ( getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: (workflow) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(workflow) createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(workflow)
), ),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan: (workflow) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(workflow)
),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState: (summaryViewModel) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(summaryViewModel)
),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract: (options) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract(options)
),
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness: (options) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness(
options ?? { documentRef: document },
)
),
renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState: (renderState, options) => (
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
renderState,
options ?? { documentRef: document },
)
),
mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState: (options) => (
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
options ?? { documentRef: document },
)
),
getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel: (validation) => ( getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel: (validation) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(validation) createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(validation)
), ),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan: (validation) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(validation)
),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState: (actionPlan) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(actionPlan)
),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract: (options) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract(options)
),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness: (options) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness(
options ?? { documentRef: document },
)
),
renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState: (renderState, options) => (
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
renderState,
options ?? { documentRef: document },
)
),
mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState: (options) => (
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
options ?? { documentRef: document },
)
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel: (validation) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(validation)
),
getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel: (workflow) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel(workflow)
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState: (summaryViewModel) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(summaryViewModel)
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract: (options) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract(options)
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness: (options) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness(
options ?? { documentRef: document },
)
),
renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState: (renderState, options) => (
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
renderState,
options ?? { documentRef: document },
)
),
mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState: (options) => (
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
options ?? { documentRef: document },
)
),
getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel: (validation) => ( getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel: (validation) => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(validation) createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(validation)
), ),

View File

@@ -0,0 +1,338 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>LinuxCNC Browser Simulation</title>
<style>
:root {
color-scheme: light;
--page: #eef2f5;
--surface: #ffffff;
--line: #c8d3dc;
--text: #1a252f;
--muted: #596875;
--blue: #1263a3;
--green: #188160;
--steel: #6f7f8d;
--warn: #a9561b;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
font-family: "Segoe UI", "Noto Sans", sans-serif;
color: var(--text);
background: var(--page);
}
main {
display: grid;
grid-template-rows: auto minmax(0, 1fr);
min-height: 100vh;
}
header {
border-bottom: 1px solid var(--line);
background: var(--surface);
padding: 14px 20px;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 16px;
align-items: center;
}
h1 {
margin: 0;
font-size: 18px;
font-weight: 650;
}
.status-strip {
display: flex;
gap: 8px;
align-items: center;
flex-wrap: wrap;
justify-content: end;
}
.badge {
border: 1px solid var(--line);
border-radius: 6px;
padding: 5px 8px;
background: #f8fafb;
color: var(--muted);
font: 12px/1.2 "Segoe UI", sans-serif;
}
.badge strong {
color: var(--green);
font-weight: 700;
}
.workspace {
display: grid;
grid-template-columns: minmax(280px, 0.75fr) minmax(420px, 1.35fr) minmax(300px, 0.9fr);
min-height: 0;
}
section {
min-width: 0;
min-height: 0;
border-right: 1px solid var(--line);
background: var(--surface);
display: grid;
grid-template-rows: auto minmax(0, 1fr);
}
section:last-child { border-right: 0; }
.section-head {
border-bottom: 1px solid var(--line);
padding: 12px 14px;
display: grid;
gap: 4px;
}
h2 {
margin: 0;
font-size: 14px;
font-weight: 650;
}
.hint {
margin: 0;
color: var(--muted);
font-size: 12px;
line-height: 1.4;
}
.program-lines {
overflow: auto;
padding: 10px 0;
background: #fbfcfd;
font: 13px/1.45 "SFMono-Regular", "Consolas", monospace;
}
.program-lines div {
display: grid;
grid-template-columns: 48px minmax(0, 1fr);
gap: 10px;
padding: 4px 12px;
border-left: 3px solid transparent;
}
.program-lines div[data-active="true"] {
background: #e9f4ef;
border-left-color: var(--green);
}
.program-lines span {
color: var(--steel);
text-align: right;
user-select: none;
}
.program-lines code {
color: var(--text);
white-space: pre-wrap;
overflow-wrap: anywhere;
}
.preview {
background: #f8fafb;
display: grid;
grid-template-rows: minmax(0, 1fr) auto;
}
.toolpath-wrap {
min-height: 0;
padding: 18px;
display: grid;
}
svg {
width: 100%;
height: 100%;
min-height: 320px;
border: 1px solid var(--line);
background: #ffffff;
}
.grid-line {
stroke: #edf1f4;
stroke-width: 0.01;
}
.toolpath {
fill: none;
stroke: var(--blue);
stroke-width: 0.035;
stroke-linecap: round;
stroke-linejoin: round;
}
.toolhead {
fill: var(--warn);
stroke: #ffffff;
stroke-width: 0.025;
}
.readout {
border-top: 1px solid var(--line);
padding: 12px 14px;
display: grid;
gap: 10px;
background: var(--surface);
}
.axis-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
}
.axis-grid div {
border: 1px solid var(--line);
border-radius: 6px;
padding: 8px;
display: grid;
gap: 4px;
background: #fbfcfd;
}
.axis-grid span:first-child {
color: var(--muted);
font-size: 11px;
font-weight: 700;
}
.axis-grid span:last-child {
font: 14px/1.2 "SFMono-Regular", "Consolas", monospace;
}
dl {
margin: 0;
display: grid;
grid-template-columns: 128px minmax(0, 1fr);
gap: 7px 12px;
font-size: 12px;
}
dt { color: var(--muted); }
dd {
margin: 0;
overflow-wrap: anywhere;
font-family: "SFMono-Regular", "Consolas", monospace;
}
.motion-table-wrap {
overflow: auto;
min-height: 0;
}
table {
width: 100%;
border-collapse: collapse;
font: 12px/1.4 "Segoe UI", sans-serif;
}
th, td {
border-bottom: 1px solid #edf1f4;
padding: 7px 8px;
text-align: left;
vertical-align: top;
}
th {
position: sticky;
top: 0;
background: #f8fafb;
z-index: 1;
color: var(--muted);
font-size: 11px;
text-transform: uppercase;
}
td:nth-child(3), td:nth-child(4) {
font-family: "SFMono-Regular", "Consolas", monospace;
}
pre {
margin: 0;
overflow: auto;
padding: 12px;
background: #111820;
color: #dbe7ef;
font: 11px/1.45 "SFMono-Regular", "Consolas", monospace;
max-height: 170px;
}
@media (max-width: 1040px) {
.workspace { grid-template-columns: 1fr; }
section { border-right: 0; border-bottom: 1px solid var(--line); }
svg { min-height: 280px; }
}
@media (max-width: 560px) {
header { grid-template-columns: 1fr; }
.status-strip { justify-content: start; }
.axis-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
dl { grid-template-columns: 1fr; }
}
</style>
</head>
<body data-simulation-ready="false">
<main>
<header>
<h1>LinuxCNC Browser Simulation</h1>
<div class="status-strip">
<span class="badge">Simulation <strong data-simulation-status>loading</strong></span>
<span class="badge" data-runtime-status>LinuxCNC interpreter WASM</span>
</div>
</header>
<div class="workspace">
<section aria-label="G-code program">
<div class="section-head">
<h2>Program</h2>
<p class="hint">Executed through the LinuxCNC-backed WASM interpreter.</p>
</div>
<div class="program-lines" data-program-lines></div>
</section>
<section aria-label="Toolpath preview">
<div class="section-head">
<h2>Toolpath Preview</h2>
<p class="hint">Rendered from LinuxCNC canonical motion events.</p>
</div>
<div class="preview">
<div class="toolpath-wrap">
<svg data-toolpath-svg role="img" aria-label="LinuxCNC canonical toolpath preview" viewBox="-1 -1 2 2">
<line class="grid-line" x1="-10" y1="0" x2="10" y2="0"></line>
<line class="grid-line" x1="0" y1="-10" x2="0" y2="10"></line>
<polyline class="toolpath" data-toolpath-polyline points=""></polyline>
<circle class="toolhead" data-toolpath-head cx="0" cy="0" r="0.055"></circle>
</svg>
</div>
<div class="readout">
<div class="axis-grid">
<div><span>X</span><span data-axis="x">0.000</span></div>
<div><span>Y</span><span data-axis="y">0.000</span></div>
<div><span>Z</span><span data-axis="z">0.000</span></div>
<div><span>A</span><span data-axis="a">0.000</span></div>
<div><span>B</span><span data-axis="b">0.000</span></div>
<div><span>C</span><span data-axis="c">0.000</span></div>
</div>
<dl data-simulation-summary-rows></dl>
</div>
</div>
</section>
<section aria-label="Machine state">
<div class="section-head">
<h2>Machine State</h2>
<p class="hint">Active line, statement, motion rows, and canonical output.</p>
</div>
<div class="motion-table-wrap">
<table>
<thead>
<tr>
<th>Motion</th>
<th>Line</th>
<th>Position</th>
<th>Statement</th>
</tr>
</thead>
<tbody data-motion-rows></tbody>
</table>
<div class="readout">
<dl>
<dt>Active line</dt>
<dd data-active-line>-</dd>
<dt>Statement</dt>
<dd data-active-statement>-</dd>
</dl>
</div>
<pre data-canonical-output></pre>
</div>
</section>
</div>
</main>
<script type="module">
import { runRealBrowserSimulation } from "./simulation-app.js";
try {
const state = await runRealBrowserSimulation({ documentRef: document });
window.linuxCncRealSimulationState = state;
window.linuxCncRealSimulationApi = {
getState: () => window.linuxCncRealSimulationState,
};
} catch (error) {
document.body.dataset.simulationReady = "false";
document.querySelector("[data-simulation-status]").textContent = "failed";
document.querySelector("[data-canonical-output]").textContent = error?.stack ?? error?.message ?? String(error);
throw error;
}
</script>
</body>
</html>

View File

@@ -0,0 +1,239 @@
import { createLinuxCncInterpSdk } from "../../sdk/src/index.js";
export const DEFAULT_SIMULATION_PROGRAM = [
"G0 X0 Y0 Z0",
"G1 X1 Y0 Z0 F100",
"G1 X1 Y1 Z0",
"G1 X0 Y1 Z0",
"G1 X0 Y0 Z0",
"M2",
"",
].join("\n");
const AXES = ["x", "y", "z", "a", "b", "c", "u", "v", "w"];
function readCanonicalNumber(line, name) {
const match = line.match(new RegExp(`(?:^| )${name}=([-+0-9.eE]+)`));
return match ? Number(match[1]) : null;
}
function programLineMap(programText) {
const lines = new Map();
programText.split(/\r?\n/).forEach((line, index) => {
lines.set(index + 1, line.trim() || "(blank)");
});
return lines;
}
export function parseLinuxCncCanonicalMotion(resultText, programText = "") {
const axes = Object.fromEntries(AXES.map((axis) => [axis, 0]));
const sourceLines = programLineMap(programText);
const motion = [];
for (const line of String(resultText).split("\n")) {
const event = line.match(/^canon_event=(STRAIGHT_TRAVERSE|STRAIGHT_FEED|ARC_FEED)\b/);
if (!event) {
continue;
}
for (const axis of AXES) {
const value = readCanonicalNumber(line, axis);
if (value !== null && Number.isFinite(value)) {
axes[axis] = value;
}
}
const sourceLine = readCanonicalNumber(line, "line");
motion.push({
type: event[1],
line: Number.isFinite(sourceLine) ? sourceLine : null,
statement: Number.isFinite(sourceLine) ? (sourceLines.get(sourceLine) ?? "-") : "-",
axes: { ...axes },
raw: line,
});
}
return motion;
}
export function createSimulationSummary({ programText, resultText, motion }) {
const canonicalLines = String(resultText).split("\n").filter((line) => line.startsWith("canon_event="));
const finalAxes = motion.at(-1)?.axes ?? Object.fromEntries(AXES.map((axis) => [axis, 0]));
return {
apiName: "real-browser-simulation-summary",
summaryVersion: 1,
ready: motion.length > 0,
phase: motion.length > 0 ? "ready" : "blocked",
programLineCount: programText.split(/\r?\n/).filter(Boolean).length,
canonicalEventCount: canonicalLines.length,
motionEventCount: motion.length,
finalAxes,
rows: [
{ id: "runtime", label: "Runtime", value: "LinuxCNC interpreter WASM" },
{ id: "program-lines", label: "Program lines", value: `${programText.split(/\r?\n/).filter(Boolean).length}` },
{ id: "canonical-events", label: "Canonical events", value: `${canonicalLines.length}` },
{ id: "motion-events", label: "Motion events", value: `${motion.length}` },
{ id: "final-position", label: "Final XYZ", value: formatPosition(finalAxes) },
],
};
}
export function createToolpathViewBox(motion, padding = 0.25) {
const points = motion.map(({ axes }) => ({ x: axes.x ?? 0, y: axes.y ?? 0 }));
if (points.length === 0) {
return { minX: -1, minY: -1, width: 2, height: 2 };
}
const xs = points.map(({ x }) => x);
const ys = points.map(({ y }) => y);
const minX = Math.min(...xs) - padding;
const maxX = Math.max(...xs) + padding;
const minY = Math.min(...ys) - padding;
const maxY = Math.max(...ys) + padding;
return {
minX,
minY,
width: Math.max(0.1, maxX - minX),
height: Math.max(0.1, maxY - minY),
};
}
export function createToolpathPolylinePoints(motion) {
return motion.map(({ axes }) => `${axes.x ?? 0},${-(axes.y ?? 0)}`).join(" ");
}
export function formatPosition(axes = {}) {
return `X ${formatAxis(axes.x)} Y ${formatAxis(axes.y)} Z ${formatAxis(axes.z)}`;
}
function formatAxis(value) {
return Number.isFinite(value) ? Number(value).toFixed(3) : "0.000";
}
function setText(documentRef, selector, value) {
const node = documentRef.querySelector(selector);
if (node) {
node.textContent = value;
}
}
function renderRows(documentRef, rows) {
const container = documentRef.querySelector("[data-simulation-summary-rows]");
if (!container) {
return;
}
container.textContent = "";
for (const row of rows) {
const term = documentRef.createElement("dt");
term.textContent = row.label;
term.dataset.simulationRow = row.id;
const detail = documentRef.createElement("dd");
detail.textContent = row.value;
detail.dataset.simulationValue = row.id;
container.append(term, detail);
}
}
function renderProgramLines(documentRef, programText, activeLine) {
const container = documentRef.querySelector("[data-program-lines]");
if (!container) {
return;
}
container.textContent = "";
programText.split(/\r?\n/).forEach((line, index) => {
if (!line && index === programText.split(/\r?\n/).length - 1) {
return;
}
const row = documentRef.createElement("div");
row.dataset.programLine = `${index + 1}`;
row.dataset.active = activeLine === index + 1 ? "true" : "false";
const number = documentRef.createElement("span");
number.textContent = `${index + 1}`;
const text = documentRef.createElement("code");
text.textContent = line || " ";
row.append(number, text);
container.append(row);
});
}
function renderAxisReadout(documentRef, axes) {
for (const axis of ["x", "y", "z", "a", "b", "c"]) {
setText(documentRef, `[data-axis="${axis}"]`, formatAxis(axes?.[axis]));
}
}
function renderToolpath(documentRef, motion) {
const svg = documentRef.querySelector("[data-toolpath-svg]");
const polyline = documentRef.querySelector("[data-toolpath-polyline]");
const head = documentRef.querySelector("[data-toolpath-head]");
if (!svg || !polyline || !head) {
return;
}
const viewBox = createToolpathViewBox(motion);
svg.setAttribute(
"viewBox",
`${viewBox.minX} ${-(viewBox.minY + viewBox.height)} ${viewBox.width} ${viewBox.height}`,
);
polyline.setAttribute("points", createToolpathPolylinePoints(motion));
const last = motion.at(-1)?.axes ?? { x: 0, y: 0 };
head.setAttribute("cx", `${last.x ?? 0}`);
head.setAttribute("cy", `${-(last.y ?? 0)}`);
}
function renderMotionTable(documentRef, motion) {
const body = documentRef.querySelector("[data-motion-rows]");
if (!body) {
return;
}
body.textContent = "";
for (const [index, item] of motion.entries()) {
const row = documentRef.createElement("tr");
row.dataset.motionRow = `${index}`;
for (const value of [
item.type,
item.line ?? "-",
formatPosition(item.axes),
item.statement,
]) {
const cell = documentRef.createElement("td");
cell.textContent = `${value}`;
row.append(cell);
}
body.append(row);
}
}
export function renderSimulationState(documentRef, state) {
documentRef.body.dataset.simulationReady = state.summary.ready ? "true" : "false";
setText(documentRef, "[data-simulation-status]", state.summary.ready ? "ready" : "blocked");
setText(documentRef, "[data-runtime-status]", state.summary.rows[0].value);
setText(documentRef, "[data-active-line]", `${state.motion.at(-1)?.line ?? "-"}`);
setText(documentRef, "[data-active-statement]", state.motion.at(-1)?.statement ?? "-");
setText(documentRef, "[data-canonical-output]", state.resultText);
renderRows(documentRef, state.summary.rows);
renderProgramLines(documentRef, state.programText, state.motion.at(-1)?.line ?? null);
renderAxisReadout(documentRef, state.summary.finalAxes);
renderToolpath(documentRef, state.motion);
renderMotionTable(documentRef, state.motion);
}
export async function runRealBrowserSimulation({
documentRef = document,
programText = DEFAULT_SIMULATION_PROGRAM,
interpFactory = createLinuxCncInterpSdk,
} = {}) {
const interp = await interpFactory();
const resultText = interp.runProgram(programText);
const motion = parseLinuxCncCanonicalMotion(resultText, programText);
const summary = createSimulationSummary({ programText, resultText, motion });
const state = {
apiName: "real-browser-simulation-state",
stateVersion: 1,
programText,
resultText,
motion,
summary,
};
renderSimulationState(documentRef, state);
return state;
}

View File

@@ -22,6 +22,22 @@
<p data-external-release-artifact-status>waiting</p> <p data-external-release-artifact-status>waiting</p>
<dl data-external-release-artifact-rows></dl> <dl data-external-release-artifact-rows></dl>
</section> </section>
<section data-external-release-artifact-json-workflow>
<p data-external-release-artifact-json-workflow-status>waiting</p>
<dl data-external-release-artifact-json-workflow-rows></dl>
</section>
<section data-external-release-artifact-url-workflow>
<p data-external-release-artifact-url-workflow-status>waiting</p>
<dl data-external-release-artifact-url-workflow-rows></dl>
</section>
<section data-external-release-artifact-gate-execution-summary>
<p data-external-release-artifact-gate-execution-summary-status>waiting</p>
<dl data-external-release-artifact-gate-execution-summary-rows></dl>
</section>
<section data-external-release-artifact-validation-action-plan>
<p data-external-release-artifact-validation-action-plan-status>waiting</p>
<dl data-external-release-artifact-validation-action-plan-rows></dl>
</section>
<script type="module"> <script type="module">
function assertEqual(actual, expected, label) { function assertEqual(actual, expected, label) {
if (actual !== expected) { if (actual !== expected) {
@@ -115,9 +131,36 @@ TOOL_TABLE = browser-shell-tool.tbl
!launchApi?.getWorkflowOverviewContract || !launchApi?.getWorkflowOverviewContract ||
!launchApi?.getWorkflowOverviewReadiness || !launchApi?.getWorkflowOverviewReadiness ||
!launchApi?.mountWorkflowOverviewEmbedding || !launchApi?.mountWorkflowOverviewEmbedding ||
!launchApi?.runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness ||
!launchApi?.renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState ||
!launchApi?.mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState ||
!launchApi?.loadWorkflowOverviewReleaseReadinessArtifactUrl || !launchApi?.loadWorkflowOverviewReleaseReadinessArtifactUrl ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel || !launchApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness ||
!launchApi?.renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState ||
!launchApi?.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel || !launchApi?.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness ||
!launchApi?.renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState ||
!launchApi?.mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract ||
!launchApi?.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness ||
!launchApi?.renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState ||
!launchApi?.mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState ||
!launchApi?.getWorkflowOverviewEmbeddingReport || !launchApi?.getWorkflowOverviewEmbeddingReport ||
!launchApi?.getWorkflowOverviewEmbeddingDisplayViewModel || !launchApi?.getWorkflowOverviewEmbeddingDisplayViewModel ||
!launchApi?.getWorkflowOverviewEmbeddingRenderState || !launchApi?.getWorkflowOverviewEmbeddingRenderState ||
@@ -320,6 +363,77 @@ TOOL_TABLE = browser-shell-tool.tbl
.then((response) => response.text()); .then((response) => response.text());
const workflowOverviewReleaseArtifactValidation = workflowOverviewApi const workflowOverviewReleaseArtifactValidation = workflowOverviewApi
.validateWorkflowOverviewReleaseReadinessArtifactJson(workflowOverviewReleaseArtifactJson); .validateWorkflowOverviewReleaseReadinessArtifactJson(workflowOverviewReleaseArtifactJson);
const workflowOverviewReleaseArtifactJsonWorkflow = workflowOverviewApi
.runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson: workflowOverviewReleaseArtifactJson,
});
const launchReleaseArtifactJsonWorkflow = launchApi
.runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson: workflowOverviewReleaseArtifactJson,
});
const workflowOverviewReleaseArtifactJsonWorkflowSummary = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(
workflowOverviewReleaseArtifactJsonWorkflow,
);
const launchReleaseArtifactJsonWorkflowSummary = launchApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(
launchReleaseArtifactJsonWorkflow,
);
const workflowOverviewReleaseArtifactJsonWorkflowActionPlan = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan(
workflowOverviewReleaseArtifactJsonWorkflow,
);
const launchReleaseArtifactJsonWorkflowActionPlan = launchApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan(
launchReleaseArtifactJsonWorkflow,
);
const workflowOverviewReleaseArtifactJsonWorkflowRenderState = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(
workflowOverviewReleaseArtifactJsonWorkflowSummary,
);
const launchReleaseArtifactJsonWorkflowRenderState = launchApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(
launchReleaseArtifactJsonWorkflowSummary,
);
const workflowOverviewReleaseArtifactJsonWorkflowDomContract = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract({
rowDatasetPrefix: "externalReleaseArtifactJsonWorkflow",
selectors: {
mount: "[data-external-release-artifact-json-workflow]",
status: "[data-external-release-artifact-json-workflow-status]",
rows: "[data-external-release-artifact-json-workflow-rows]",
},
});
const workflowOverviewReleaseArtifactJsonWorkflowDomReadiness = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness({
contract: workflowOverviewReleaseArtifactJsonWorkflowDomContract,
documentRef: document,
});
const workflowOverviewReleaseArtifactJsonWorkflowRenderResult = workflowOverviewApi
.renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
workflowOverviewReleaseArtifactJsonWorkflowRenderState,
{
contract: workflowOverviewReleaseArtifactJsonWorkflowDomContract,
documentRef: document,
},
);
const workflowOverviewReleaseArtifactJsonWorkflowMountResult = workflowOverviewApi
.mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState({
renderState: workflowOverviewReleaseArtifactJsonWorkflowRenderState,
contract: workflowOverviewReleaseArtifactJsonWorkflowDomContract,
documentRef: document,
});
const launchReleaseArtifactJsonWorkflowDomReadiness = launchApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness({
contract: workflowOverviewReleaseArtifactJsonWorkflowDomContract,
documentRef: document,
});
const launchReleaseArtifactJsonWorkflowMountResult = launchApi
.mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState({
renderState: launchReleaseArtifactJsonWorkflowRenderState,
contract: workflowOverviewReleaseArtifactJsonWorkflowDomContract,
documentRef: document,
});
const workflowOverviewReleaseArtifactSummary = workflowOverviewApi const workflowOverviewReleaseArtifactSummary = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel( .getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(
workflowOverviewReleaseArtifactValidation, workflowOverviewReleaseArtifactValidation,
@@ -328,6 +442,106 @@ TOOL_TABLE = browser-shell-tool.tbl
.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel( .getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(
workflowOverviewReleaseArtifactValidation, workflowOverviewReleaseArtifactValidation,
); );
const workflowOverviewReleaseArtifactValidationActionPlan = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(
workflowOverviewReleaseArtifactValidation,
);
const launchReleaseArtifactValidationActionPlan = launchApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(
workflowOverviewReleaseArtifactValidation,
);
const workflowOverviewReleaseArtifactValidationActionPlanRenderState = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(
workflowOverviewReleaseArtifactValidationActionPlan,
);
const launchReleaseArtifactValidationActionPlanRenderState = launchApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(
launchReleaseArtifactValidationActionPlan,
);
const workflowOverviewReleaseArtifactValidationActionPlanDomContract = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract({
rowDatasetPrefix: "externalReleaseArtifactValidationActionPlan",
selectors: {
mount: "[data-external-release-artifact-validation-action-plan]",
status: "[data-external-release-artifact-validation-action-plan-status]",
rows: "[data-external-release-artifact-validation-action-plan-rows]",
},
});
const workflowOverviewReleaseArtifactValidationActionPlanDomReadiness = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness({
contract: workflowOverviewReleaseArtifactValidationActionPlanDomContract,
documentRef: document,
});
const workflowOverviewReleaseArtifactValidationActionPlanRenderResult = workflowOverviewApi
.renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
workflowOverviewReleaseArtifactValidationActionPlanRenderState,
{
contract: workflowOverviewReleaseArtifactValidationActionPlanDomContract,
documentRef: document,
},
);
const workflowOverviewReleaseArtifactValidationActionPlanMountResult = workflowOverviewApi
.mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState({
renderState: workflowOverviewReleaseArtifactValidationActionPlanRenderState,
contract: workflowOverviewReleaseArtifactValidationActionPlanDomContract,
documentRef: document,
});
const launchReleaseArtifactValidationActionPlanMountResult = launchApi
.mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState({
renderState: launchReleaseArtifactValidationActionPlanRenderState,
contract: workflowOverviewReleaseArtifactValidationActionPlanDomContract,
documentRef: document,
});
const workflowOverviewReleaseArtifactGateExecutionSummary = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(
workflowOverviewReleaseArtifactValidation,
);
const launchReleaseArtifactGateExecutionSummary = launchApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(
workflowOverviewReleaseArtifactValidation,
);
const workflowOverviewReleaseArtifactGateExecutionSummaryRenderState = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(
workflowOverviewReleaseArtifactGateExecutionSummary,
);
const launchReleaseArtifactGateExecutionSummaryRenderState = launchApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(
launchReleaseArtifactGateExecutionSummary,
);
const workflowOverviewReleaseArtifactGateExecutionSummaryDomContract = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract({
rowDatasetPrefix: "externalReleaseArtifactGateExecutionSummary",
selectors: {
mount: "[data-external-release-artifact-gate-execution-summary]",
status: "[data-external-release-artifact-gate-execution-summary-status]",
rows: "[data-external-release-artifact-gate-execution-summary-rows]",
},
});
const workflowOverviewReleaseArtifactGateExecutionSummaryDomReadiness = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness({
contract: workflowOverviewReleaseArtifactGateExecutionSummaryDomContract,
documentRef: document,
});
const workflowOverviewReleaseArtifactGateExecutionSummaryRenderResult = workflowOverviewApi
.renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
workflowOverviewReleaseArtifactGateExecutionSummaryRenderState,
{
contract: workflowOverviewReleaseArtifactGateExecutionSummaryDomContract,
documentRef: document,
},
);
const workflowOverviewReleaseArtifactGateExecutionSummaryMountResult = workflowOverviewApi
.mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState({
renderState: workflowOverviewReleaseArtifactGateExecutionSummaryRenderState,
contract: workflowOverviewReleaseArtifactGateExecutionSummaryDomContract,
documentRef: document,
});
const launchReleaseArtifactGateExecutionSummaryMountResult = launchApi
.mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState({
renderState: launchReleaseArtifactGateExecutionSummaryRenderState,
contract: workflowOverviewReleaseArtifactGateExecutionSummaryDomContract,
documentRef: document,
});
const workflowOverviewReleaseArtifactDisplay = workflowOverviewApi const workflowOverviewReleaseArtifactDisplay = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(workflowOverviewReleaseArtifactValidation); .getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(workflowOverviewReleaseArtifactValidation);
const workflowOverviewReleaseArtifactRenderState = workflowOverviewApi const workflowOverviewReleaseArtifactRenderState = workflowOverviewApi
@@ -381,6 +595,64 @@ TOOL_TABLE = browser-shell-tool.tbl
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel( .getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(
launchReleaseArtifactUrlWorkflow, launchReleaseArtifactUrlWorkflow,
); );
const workflowOverviewReleaseArtifactUrlWorkflowActionPlan = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(
workflowOverviewReleaseArtifactUrlWorkflow,
);
const launchReleaseArtifactUrlWorkflowActionPlan = launchApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(
launchReleaseArtifactUrlWorkflow,
);
const workflowOverviewReleaseArtifactUrlWorkflowRenderState = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(
workflowOverviewReleaseArtifactUrlWorkflowSummary,
);
const launchReleaseArtifactUrlWorkflowRenderState = launchApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(
launchReleaseArtifactUrlWorkflowSummary,
);
const workflowOverviewReleaseArtifactUrlWorkflowDomContract = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract({
rowDatasetPrefix: "externalReleaseArtifactUrlWorkflow",
selectors: {
mount: "[data-external-release-artifact-url-workflow]",
status: "[data-external-release-artifact-url-workflow-status]",
rows: "[data-external-release-artifact-url-workflow-rows]",
},
});
const workflowOverviewReleaseArtifactUrlWorkflowDomReadiness = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness({
contract: workflowOverviewReleaseArtifactUrlWorkflowDomContract,
documentRef: document,
});
const workflowOverviewReleaseArtifactUrlWorkflowRenderResult = workflowOverviewApi
.renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
workflowOverviewReleaseArtifactUrlWorkflowRenderState,
{
contract: workflowOverviewReleaseArtifactUrlWorkflowDomContract,
documentRef: document,
},
);
const workflowOverviewReleaseArtifactUrlWorkflowMountResult = workflowOverviewApi
.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState({
renderState: workflowOverviewReleaseArtifactUrlWorkflowRenderState,
contract: workflowOverviewReleaseArtifactUrlWorkflowDomContract,
documentRef: document,
});
const launchReleaseArtifactUrlWorkflowMountResult = launchApi
.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState({
renderState: launchReleaseArtifactUrlWorkflowRenderState,
contract: workflowOverviewReleaseArtifactUrlWorkflowDomContract,
documentRef: document,
});
const workflowOverviewReleaseArtifactUrlGateExecutionSummary = workflowOverviewApi
.getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel(
workflowOverviewReleaseArtifactUrlWorkflow,
);
const launchReleaseArtifactUrlGateExecutionSummary = launchApi
.getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel(
launchReleaseArtifactUrlWorkflow,
);
const workflowOverviewEmbedding = launchApi.mountWorkflowOverviewEmbedding({ const workflowOverviewEmbedding = launchApi.mountWorkflowOverviewEmbedding({
overviewApi: workflowOverviewApi, overviewApi: workflowOverviewApi,
}); });
@@ -452,6 +724,86 @@ TOOL_TABLE = browser-shell-tool.tbl
true, true,
"shell workflow overview release artifact validation readiness", "shell workflow overview release artifact validation readiness",
); );
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflow.statusLine,
"Ready: Artifact JSON workflow complete",
"shell workflow overview release artifact JSON workflow",
);
assertEqual(
launchReleaseArtifactJsonWorkflow.statusLine,
workflowOverviewReleaseArtifactJsonWorkflow.statusLine,
"launch release artifact JSON workflow",
);
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflowSummary.statusLine,
"Ready: Artifact JSON workflow complete",
"shell workflow overview release artifact JSON workflow summary",
);
assertEqual(
launchReleaseArtifactJsonWorkflowSummary.statusLine,
workflowOverviewReleaseArtifactJsonWorkflowSummary.statusLine,
"launch release artifact JSON workflow summary",
);
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflowActionPlan.shellScript,
"# Project release readiness artifact validation is already ready.\n",
"shell workflow overview release artifact JSON workflow action plan",
);
assertEqual(
launchReleaseArtifactJsonWorkflowActionPlan.shellScript,
workflowOverviewReleaseArtifactJsonWorkflowActionPlan.shellScript,
"launch release artifact JSON workflow action plan",
);
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflowRenderState.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-json-workflow",
"shell workflow overview release artifact JSON workflow render state",
);
assertEqual(
launchReleaseArtifactJsonWorkflowRenderState.statusLine,
workflowOverviewReleaseArtifactJsonWorkflowRenderState.statusLine,
"launch release artifact JSON workflow render state",
);
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflowDomReadiness.ready,
true,
"shell workflow overview release artifact JSON workflow DOM readiness",
);
assertEqual(
launchReleaseArtifactJsonWorkflowDomReadiness.ready,
true,
"launch release artifact JSON workflow DOM readiness",
);
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflowRenderResult.rowCount,
5,
"shell workflow overview release artifact JSON workflow render rows",
);
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflowRenderResult.rowIds.includes("gate-execution-summary"),
true,
"shell workflow overview release artifact JSON workflow gate row",
);
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflowMountResult.ready,
true,
"shell workflow overview release artifact JSON workflow mount readiness",
);
assertEqual(
launchReleaseArtifactJsonWorkflowMountResult.ready,
true,
"launch release artifact JSON workflow mount readiness",
);
assertEqual(
document.querySelector("[data-external-release-artifact-json-workflow-status]").textContent,
"Ready: Artifact JSON workflow complete",
"shell workflow overview release artifact JSON workflow rendered status",
);
assertEqual(
workflowOverviewReleaseArtifactJsonWorkflow.actionPlan.nextCommand,
null,
"shell workflow overview release artifact JSON workflow action plan",
);
assertEqual( assertEqual(
workflowOverviewReleaseArtifactSummary.statusLine, workflowOverviewReleaseArtifactSummary.statusLine,
"Ready: Artifact evidence complete", "Ready: Artifact evidence complete",
@@ -462,6 +814,96 @@ TOOL_TABLE = browser-shell-tool.tbl
workflowOverviewReleaseArtifactSummary.statusLine, workflowOverviewReleaseArtifactSummary.statusLine,
"launch release artifact validation summary", "launch release artifact validation summary",
); );
assertEqual(
workflowOverviewReleaseArtifactValidationActionPlan.shellScript,
"# Project release readiness artifact validation is already ready.\n",
"shell workflow overview release artifact validation action plan",
);
assertEqual(
launchReleaseArtifactValidationActionPlan.shellScript,
workflowOverviewReleaseArtifactValidationActionPlan.shellScript,
"launch release artifact validation action plan",
);
assertEqual(
workflowOverviewReleaseArtifactValidationActionPlanRenderState.statusLine,
"Ready: Artifact validation action plan complete",
"shell workflow overview release artifact validation action-plan render state",
);
assertEqual(
launchReleaseArtifactValidationActionPlanRenderState.statusLine,
workflowOverviewReleaseArtifactValidationActionPlanRenderState.statusLine,
"launch release artifact validation action-plan render state",
);
assertEqual(
workflowOverviewReleaseArtifactValidationActionPlanDomReadiness.ready,
true,
"shell workflow overview release artifact validation action-plan DOM readiness",
);
assertEqual(
workflowOverviewReleaseArtifactValidationActionPlanRenderResult.rowIds.includes("next-command"),
true,
"shell workflow overview release artifact validation action-plan next-command row",
);
assertEqual(
workflowOverviewReleaseArtifactValidationActionPlanMountResult.ready,
true,
"shell workflow overview release artifact validation action-plan mount readiness",
);
assertEqual(
launchReleaseArtifactValidationActionPlanMountResult.ready,
true,
"launch release artifact validation action-plan mount readiness",
);
assertEqual(
document.querySelector("[data-external-release-artifact-validation-action-plan-status]").textContent,
"Ready: Artifact validation action plan complete",
"shell workflow overview release artifact validation action-plan rendered status",
);
assertEqual(
workflowOverviewReleaseArtifactGateExecutionSummary.statusLine,
"Ready: All release gate evidence present",
"shell workflow overview release artifact gate execution summary",
);
assertEqual(
launchReleaseArtifactGateExecutionSummary.statusLine,
workflowOverviewReleaseArtifactGateExecutionSummary.statusLine,
"launch release artifact gate execution summary",
);
assertEqual(
workflowOverviewReleaseArtifactGateExecutionSummaryRenderState.rows.length,
17,
"shell workflow overview release artifact gate execution summary render rows",
);
assertEqual(
launchReleaseArtifactGateExecutionSummaryRenderState.statusLine,
workflowOverviewReleaseArtifactGateExecutionSummaryRenderState.statusLine,
"launch release artifact gate execution summary render-state",
);
assertEqual(
workflowOverviewReleaseArtifactGateExecutionSummaryDomReadiness.ready,
true,
"shell workflow overview release artifact gate execution summary DOM readiness",
);
assertEqual(
workflowOverviewReleaseArtifactGateExecutionSummaryRenderResult.rowIds.includes("gate-ui-node-smokes"),
true,
"shell workflow overview release artifact gate execution summary SDK row",
);
assertEqual(
workflowOverviewReleaseArtifactGateExecutionSummaryMountResult.ready,
true,
"shell workflow overview release artifact gate execution summary mount readiness",
);
assertEqual(
launchReleaseArtifactGateExecutionSummaryMountResult.ready,
true,
"launch release artifact gate execution summary mount readiness",
);
assertEqual(
document.querySelector("[data-external-release-artifact-gate-execution-summary-status]").textContent,
"Ready: All release gate evidence present",
"shell workflow overview release artifact gate execution summary rendered status",
);
assertEqual( assertEqual(
workflowOverviewReleaseArtifactDomReadiness.ready, workflowOverviewReleaseArtifactDomReadiness.ready,
true, true,
@@ -522,6 +964,66 @@ TOOL_TABLE = browser-shell-tool.tbl
workflowOverviewReleaseArtifactUrlWorkflowSummary.statusLine, workflowOverviewReleaseArtifactUrlWorkflowSummary.statusLine,
"launch release artifact URL workflow summary view model", "launch release artifact URL workflow summary view model",
); );
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowRenderState.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-url-workflow",
"shell workflow overview release artifact URL workflow render-state scope",
);
assertEqual(
launchReleaseArtifactUrlWorkflowRenderState.statusLine,
workflowOverviewReleaseArtifactUrlWorkflowRenderState.statusLine,
"launch release artifact URL workflow render-state",
);
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowDomReadiness.ready,
true,
"shell workflow overview release artifact URL workflow DOM readiness",
);
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowRenderResult.rowCount,
8,
"shell workflow overview release artifact URL workflow render rows",
);
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowRenderResult.rowIds.includes("mount-result"),
true,
"shell workflow overview release artifact URL workflow mount row",
);
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowMountResult.ready,
true,
"shell workflow overview release artifact URL workflow DOM mount readiness",
);
assertEqual(
launchReleaseArtifactUrlWorkflowMountResult.ready,
true,
"launch release artifact URL workflow DOM mount readiness",
);
assertEqual(
document.querySelector("[data-external-release-artifact-url-workflow-status]").textContent,
"Ready: Artifact URL workflow complete",
"shell workflow overview release artifact URL workflow rendered status",
);
assertEqual(
workflowOverviewReleaseArtifactUrlWorkflowActionPlan.shellScript,
"# Project release readiness artifact URL workflow is already ready.\n",
"shell workflow overview release artifact URL workflow action plan",
);
assertEqual(
launchReleaseArtifactUrlWorkflowActionPlan.shellScript,
workflowOverviewReleaseArtifactUrlWorkflowActionPlan.shellScript,
"launch release artifact URL workflow action plan",
);
assertEqual(
workflowOverviewReleaseArtifactUrlGateExecutionSummary.statusLine,
"Ready: All release gate evidence present",
"shell workflow overview release artifact URL gate execution summary",
);
assertEqual(
launchReleaseArtifactUrlGateExecutionSummary.statusLine,
workflowOverviewReleaseArtifactUrlGateExecutionSummary.statusLine,
"launch release artifact URL gate execution summary",
);
assertEqual( assertEqual(
document.querySelector("[data-external-release-artifact-status]").textContent, document.querySelector("[data-external-release-artifact-status]").textContent,
"Ready: No blocking reasons", "Ready: No blocking reasons",

View File

@@ -35,9 +35,36 @@
!workflowApi?.getWorkflowOverviewApiSurfaceInventory || !workflowApi?.getWorkflowOverviewApiSurfaceInventory ||
!workflowApi?.getWorkflowOverviewPersistenceSummary || !workflowApi?.getWorkflowOverviewPersistenceSummary ||
!workflowApi?.validateWorkflowOverviewReleaseReadinessArtifactJson || !workflowApi?.validateWorkflowOverviewReleaseReadinessArtifactJson ||
!workflowApi?.runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness ||
!workflowApi?.renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState ||
!workflowApi?.mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState ||
!workflowApi?.loadWorkflowOverviewReleaseReadinessArtifactUrl || !workflowApi?.loadWorkflowOverviewReleaseReadinessArtifactUrl ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness ||
!workflowApi?.renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState ||
!workflowApi?.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness ||
!workflowApi?.renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState ||
!workflowApi?.mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness ||
!workflowApi?.renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState ||
!workflowApi?.mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactRenderState || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactRenderState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactDomContract || !workflowApi?.getWorkflowOverviewReleaseReadinessArtifactDomContract ||
@@ -77,8 +104,23 @@
const releaseArtifactValidation = workflowApi.validateWorkflowOverviewReleaseReadinessArtifactJson( const releaseArtifactValidation = workflowApi.validateWorkflowOverviewReleaseReadinessArtifactJson(
releaseArtifactJson, releaseArtifactJson,
); );
const releaseArtifactJsonWorkflow = workflowApi.runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson: releaseArtifactJson,
});
const releaseArtifactJsonWorkflowSummary = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(releaseArtifactJsonWorkflow);
const releaseArtifactJsonWorkflowActionPlan = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan(releaseArtifactJsonWorkflow);
const releaseArtifactJsonWorkflowRenderState = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(releaseArtifactJsonWorkflowSummary);
const releaseArtifactValidationSummary = workflowApi const releaseArtifactValidationSummary = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(releaseArtifactValidation); .getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(releaseArtifactValidation);
const releaseArtifactValidationActionPlan = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(releaseArtifactValidation);
const releaseArtifactValidationActionPlanRenderState = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(
releaseArtifactValidationActionPlan,
);
const releaseArtifactDisplay = workflowApi.getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel( const releaseArtifactDisplay = workflowApi.getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(
releaseArtifactValidation, releaseArtifactValidation,
); );
@@ -87,6 +129,8 @@
); );
const releaseArtifactDomContract = workflowApi.getWorkflowOverviewReleaseReadinessArtifactDomContract(); const releaseArtifactDomContract = workflowApi.getWorkflowOverviewReleaseReadinessArtifactDomContract();
const releaseArtifactDomReadinessMissing = workflowApi.getWorkflowOverviewReleaseReadinessArtifactDomReadiness(); const releaseArtifactDomReadinessMissing = workflowApi.getWorkflowOverviewReleaseReadinessArtifactDomReadiness();
const releaseArtifactJsonWorkflowDomReadinessMissing = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness();
const domContract = workflowApi.getWorkflowOverviewDomContract(); const domContract = workflowApi.getWorkflowOverviewDomContract();
const domReadiness = workflowApi.getWorkflowOverviewDomReadiness(); const domReadiness = workflowApi.getWorkflowOverviewDomReadiness();
const renderResult = workflowApi.renderWorkflowOverview(); const renderResult = workflowApi.renderWorkflowOverview();
@@ -138,7 +182,7 @@
"workflow overview release artifact validation API name", "workflow overview release artifact validation API name",
); );
assertEqual(releaseArtifactValidation.ready, true, "workflow overview release artifact validation readiness"); assertEqual(releaseArtifactValidation.ready, true, "workflow overview release artifact validation readiness");
assertEqual(releaseArtifactValidation.gateCount, 11, "workflow overview release artifact validation gates"); assertEqual(releaseArtifactValidation.gateCount, 12, "workflow overview release artifact validation gates");
assertEqual( assertEqual(
releaseArtifactValidationSummary.statusLine, releaseArtifactValidationSummary.statusLine,
"Ready: Artifact evidence complete", "Ready: Artifact evidence complete",
@@ -254,12 +298,102 @@
const releaseArtifactMountResult = workflowApi.mountWorkflowOverviewReleaseReadinessArtifactState({ const releaseArtifactMountResult = workflowApi.mountWorkflowOverviewReleaseReadinessArtifactState({
renderState: releaseArtifactRenderState, renderState: releaseArtifactRenderState,
}); });
const releaseArtifactValidationActionPlanNode = workflowDoc.createElement("section");
releaseArtifactValidationActionPlanNode.dataset.workflowOverviewReleaseReadinessArtifactValidationActionPlan = "";
const releaseArtifactValidationActionPlanStatus = workflowDoc.createElement("p");
releaseArtifactValidationActionPlanStatus.dataset.workflowOverviewReleaseReadinessArtifactValidationActionPlanStatus = "";
const releaseArtifactValidationActionPlanRows = workflowDoc.createElement("dl");
releaseArtifactValidationActionPlanRows.dataset.workflowOverviewReleaseReadinessArtifactValidationActionPlanRows = "";
releaseArtifactValidationActionPlanNode.append(
releaseArtifactValidationActionPlanStatus,
releaseArtifactValidationActionPlanRows,
);
workflowDoc.body.append(releaseArtifactValidationActionPlanNode);
const releaseArtifactValidationActionPlanDomReadinessReady = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness();
const releaseArtifactValidationActionPlanRenderResult = workflowApi
.renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
releaseArtifactValidationActionPlanRenderState,
);
const releaseArtifactValidationActionPlanMountResult = workflowApi
.mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState({
renderState: releaseArtifactValidationActionPlanRenderState,
});
const releaseArtifactJsonWorkflowNode = workflowDoc.createElement("section");
releaseArtifactJsonWorkflowNode.dataset.workflowOverviewReleaseReadinessArtifactJsonWorkflow = "";
const releaseArtifactJsonWorkflowStatus = workflowDoc.createElement("p");
releaseArtifactJsonWorkflowStatus.dataset.workflowOverviewReleaseReadinessArtifactJsonWorkflowStatus = "";
const releaseArtifactJsonWorkflowRows = workflowDoc.createElement("dl");
releaseArtifactJsonWorkflowRows.dataset.workflowOverviewReleaseReadinessArtifactJsonWorkflowRows = "";
releaseArtifactJsonWorkflowNode.append(releaseArtifactJsonWorkflowStatus, releaseArtifactJsonWorkflowRows);
workflowDoc.body.append(releaseArtifactJsonWorkflowNode);
const releaseArtifactJsonWorkflowDomReadinessReady = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness();
const releaseArtifactJsonWorkflowRenderResult = workflowApi
.renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
releaseArtifactJsonWorkflowRenderState,
);
const releaseArtifactJsonWorkflowMountResult = workflowApi
.mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState({
renderState: releaseArtifactJsonWorkflowRenderState,
});
const releaseArtifactUrlWorkflow = await workflowApi.loadWorkflowOverviewReleaseReadinessArtifactUrl({ const releaseArtifactUrlWorkflow = await workflowApi.loadWorkflowOverviewReleaseReadinessArtifactUrl({
artifactUrl: "../../tests/fixtures/project-release-readiness-ready.json", artifactUrl: "../../tests/fixtures/project-release-readiness-ready.json",
mount: true, mount: true,
}); });
const releaseArtifactUrlWorkflowSummary = workflowApi const releaseArtifactUrlWorkflowSummary = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(releaseArtifactUrlWorkflow); .getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(releaseArtifactUrlWorkflow);
const releaseArtifactUrlWorkflowActionPlan = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(releaseArtifactUrlWorkflow);
const releaseArtifactUrlWorkflowRenderState = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(releaseArtifactUrlWorkflowSummary);
const releaseArtifactUrlWorkflowNode = workflowDoc.createElement("section");
releaseArtifactUrlWorkflowNode.dataset.workflowOverviewReleaseReadinessArtifactUrlWorkflow = "";
const releaseArtifactUrlWorkflowStatus = workflowDoc.createElement("p");
releaseArtifactUrlWorkflowStatus.dataset.workflowOverviewReleaseReadinessArtifactUrlWorkflowStatus = "";
const releaseArtifactUrlWorkflowRows = workflowDoc.createElement("dl");
releaseArtifactUrlWorkflowRows.dataset.workflowOverviewReleaseReadinessArtifactUrlWorkflowRows = "";
releaseArtifactUrlWorkflowNode.append(releaseArtifactUrlWorkflowStatus, releaseArtifactUrlWorkflowRows);
workflowDoc.body.append(releaseArtifactUrlWorkflowNode);
const releaseArtifactUrlWorkflowDomReadinessReady = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness();
const releaseArtifactUrlWorkflowRenderResult = workflowApi
.renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
releaseArtifactUrlWorkflowRenderState,
);
const releaseArtifactUrlWorkflowMountResult = workflowApi
.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState({
renderState: releaseArtifactUrlWorkflowRenderState,
});
const releaseArtifactGateExecutionSummary = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(releaseArtifactValidation);
const releaseArtifactGateExecutionSummaryRenderState = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(
releaseArtifactGateExecutionSummary,
);
const releaseArtifactGateExecutionSummaryNode = workflowDoc.createElement("section");
releaseArtifactGateExecutionSummaryNode.dataset.workflowOverviewReleaseReadinessArtifactGateExecutionSummary = "";
const releaseArtifactGateExecutionSummaryStatus = workflowDoc.createElement("p");
releaseArtifactGateExecutionSummaryStatus.dataset.workflowOverviewReleaseReadinessArtifactGateExecutionSummaryStatus = "";
const releaseArtifactGateExecutionSummaryRows = workflowDoc.createElement("dl");
releaseArtifactGateExecutionSummaryRows.dataset.workflowOverviewReleaseReadinessArtifactGateExecutionSummaryRows = "";
releaseArtifactGateExecutionSummaryNode.append(
releaseArtifactGateExecutionSummaryStatus,
releaseArtifactGateExecutionSummaryRows,
);
workflowDoc.body.append(releaseArtifactGateExecutionSummaryNode);
const releaseArtifactGateExecutionSummaryDomReadinessReady = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness();
const releaseArtifactGateExecutionSummaryRenderResult = workflowApi
.renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
releaseArtifactGateExecutionSummaryRenderState,
);
const releaseArtifactGateExecutionSummaryMountResult = workflowApi
.mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState({
renderState: releaseArtifactGateExecutionSummaryRenderState,
});
const releaseArtifactUrlGateExecutionSummary = workflowApi
.getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel(releaseArtifactUrlWorkflow);
assertEqual(releaseArtifactDomReadinessReady.ready, true, "workflow overview release artifact DOM readiness"); assertEqual(releaseArtifactDomReadinessReady.ready, true, "workflow overview release artifact DOM readiness");
assertEqual(releaseArtifactRenderResult.rendered, true, "workflow overview release artifact render result"); assertEqual(releaseArtifactRenderResult.rendered, true, "workflow overview release artifact render result");
assertEqual(releaseArtifactRenderResult.rowCount, 8, "workflow overview release artifact render row count"); assertEqual(releaseArtifactRenderResult.rowCount, 8, "workflow overview release artifact render row count");
@@ -275,6 +409,36 @@
); );
assertEqual(releaseArtifactMountResult.ready, true, "workflow overview release artifact mount readiness"); assertEqual(releaseArtifactMountResult.ready, true, "workflow overview release artifact mount readiness");
assertEqual(releaseArtifactMountResult.renderResult.rowCount, 8, "workflow overview release artifact mount rows"); assertEqual(releaseArtifactMountResult.renderResult.rowCount, 8, "workflow overview release artifact mount rows");
assertEqual(
releaseArtifactJsonWorkflowDomReadinessMissing.missing.join(","),
"mount,status,rows",
"workflow overview release artifact JSON workflow missing DOM readiness",
);
assertEqual(
releaseArtifactJsonWorkflowDomReadinessReady.ready,
true,
"workflow overview release artifact JSON workflow DOM readiness",
);
assertEqual(
releaseArtifactJsonWorkflowRenderResult.rowCount,
5,
"workflow overview release artifact JSON workflow render rows",
);
assertEqual(
releaseArtifactJsonWorkflowRenderResult.rowIds.includes("gate-execution-summary"),
true,
"workflow overview release artifact JSON workflow gate row",
);
assertEqual(
releaseArtifactJsonWorkflowMountResult.ready,
true,
"workflow overview release artifact JSON workflow mount readiness",
);
assertEqual(
releaseArtifactJsonWorkflowStatus.textContent,
"Ready: Artifact JSON workflow complete",
"workflow overview release artifact JSON workflow rendered status",
);
assertEqual(releaseArtifactUrlWorkflow.ready, true, "workflow overview release artifact URL workflow readiness"); assertEqual(releaseArtifactUrlWorkflow.ready, true, "workflow overview release artifact URL workflow readiness");
assertEqual(releaseArtifactUrlWorkflow.httpStatus, 200, "workflow overview release artifact URL workflow status"); assertEqual(releaseArtifactUrlWorkflow.httpStatus, 200, "workflow overview release artifact URL workflow status");
assertEqual( assertEqual(
@@ -287,6 +451,136 @@
"Ready: Artifact URL workflow complete", "Ready: Artifact URL workflow complete",
"workflow overview release artifact URL workflow summary view model", "workflow overview release artifact URL workflow summary view model",
); );
assertEqual(
releaseArtifactUrlWorkflowRenderState.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-url-workflow",
"workflow overview release artifact URL workflow render scope",
);
assertEqual(
releaseArtifactUrlWorkflowDomReadinessReady.ready,
true,
"workflow overview release artifact URL workflow DOM readiness",
);
assertEqual(
releaseArtifactUrlWorkflowRenderResult.rowCount,
8,
"workflow overview release artifact URL workflow render rows",
);
assertEqual(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("mount-result"),
true,
"workflow overview release artifact URL workflow mount row",
);
assertEqual(
releaseArtifactUrlWorkflowMountResult.ready,
true,
"workflow overview release artifact URL workflow DOM mount readiness",
);
assertEqual(
releaseArtifactUrlWorkflowStatus.textContent,
"Ready: Artifact URL workflow complete",
"workflow overview release artifact URL workflow rendered status",
);
assertEqual(
releaseArtifactJsonWorkflow.statusLine,
"Ready: Artifact JSON workflow complete",
"workflow overview release artifact JSON workflow",
);
assertEqual(
releaseArtifactJsonWorkflowSummary.statusLine,
"Ready: Artifact JSON workflow complete",
"workflow overview release artifact JSON workflow summary",
);
assertEqual(
releaseArtifactJsonWorkflowActionPlan.shellScript,
"# Project release readiness artifact validation is already ready.\n",
"workflow overview release artifact JSON workflow action plan",
);
assertEqual(
releaseArtifactJsonWorkflowRenderState.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-json-workflow",
"workflow overview release artifact JSON workflow render state scope",
);
assertEqual(
releaseArtifactJsonWorkflow.gateExecutionSummaryViewModel.statusLine,
"Ready: All release gate evidence present",
"workflow overview release artifact JSON workflow gate summary",
);
assertEqual(
releaseArtifactJsonWorkflow.actionPlan.nextCommand,
null,
"workflow overview release artifact JSON workflow action plan",
);
assertEqual(
releaseArtifactUrlWorkflowActionPlan.shellScript,
"# Project release readiness artifact URL workflow is already ready.\n",
"workflow overview release artifact URL workflow action plan",
);
assertEqual(
releaseArtifactValidationActionPlan.shellScript,
"# Project release readiness artifact validation is already ready.\n",
"workflow overview release artifact validation action plan",
);
assertEqual(
releaseArtifactValidationActionPlanRenderState.statusLine,
"Ready: Artifact validation action plan complete",
"workflow overview release artifact validation action-plan render state",
);
assertEqual(
releaseArtifactValidationActionPlanDomReadinessReady.ready,
true,
"workflow overview release artifact validation action-plan DOM readiness",
);
assertEqual(
releaseArtifactValidationActionPlanRenderResult.rowIds.includes("next-command"),
true,
"workflow overview release artifact validation action-plan next-command row",
);
assertEqual(
releaseArtifactValidationActionPlanMountResult.ready,
true,
"workflow overview release artifact validation action-plan mount readiness",
);
assertEqual(
releaseArtifactValidationActionPlanStatus.textContent,
"Ready: Artifact validation action plan complete",
"workflow overview release artifact validation action-plan rendered status",
);
assertEqual(
releaseArtifactGateExecutionSummary.statusLine,
"Ready: All release gate evidence present",
"workflow overview release artifact gate execution summary",
);
assertEqual(
releaseArtifactGateExecutionSummaryRenderState.rows.length,
17,
"workflow overview release artifact gate execution summary render rows",
);
assertEqual(
releaseArtifactGateExecutionSummaryDomReadinessReady.ready,
true,
"workflow overview release artifact gate execution summary DOM readiness",
);
assertEqual(
releaseArtifactGateExecutionSummaryRenderResult.rowIds.includes("gate-ui-node-smokes"),
true,
"workflow overview release artifact gate execution summary SDK row",
);
assertEqual(
releaseArtifactGateExecutionSummaryMountResult.ready,
true,
"workflow overview release artifact gate execution summary mount readiness",
);
assertEqual(
releaseArtifactGateExecutionSummaryStatus.textContent,
"Ready: All release gate evidence present",
"workflow overview release artifact gate execution summary rendered status",
);
assertEqual(
releaseArtifactUrlGateExecutionSummary.statusLine,
"Ready: All release gate evidence present",
"workflow overview release artifact URL gate execution summary",
);
assertEqual(releaseArtifactUrlWorkflow.mountResult.ready, true, "workflow overview release artifact URL workflow mount"); assertEqual(releaseArtifactUrlWorkflow.mountResult.ready, true, "workflow overview release artifact URL workflow mount");
assertEqual(releaseArtifactStatus.textContent, releaseArtifactRenderState.statusLine, "workflow overview release artifact rendered status"); assertEqual(releaseArtifactStatus.textContent, releaseArtifactRenderState.statusLine, "workflow overview release artifact rendered status");
assertEqual( assertEqual(

View File

@@ -0,0 +1,83 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>LinuxCNC Real Simulation Page Smoke</title>
</head>
<body>
<pre id="status">running</pre>
<script type="module">
const status = document.getElementById("status");
async function loadFrame(src) {
const frame = document.createElement("iframe");
frame.src = src;
frame.width = "1280";
frame.height = "800";
document.body.appendChild(frame);
await new Promise((resolve, reject) => {
frame.addEventListener("load", resolve, { once: true });
frame.addEventListener("error", reject, { once: true });
});
return frame;
}
async function waitForState(frame) {
for (let i = 0; i < 200; i += 1) {
const state = frame.contentWindow?.linuxCncRealSimulationState;
if (state?.summary?.ready) {
return state;
}
await new Promise((resolve) => setTimeout(resolve, 50));
}
throw new Error("real simulation page did not expose ready state");
}
try {
const frame = await loadFrame("../../runtime/ui/simulation/index.html");
const doc = frame.contentDocument;
const state = await waitForState(frame);
const polyline = doc.querySelector("[data-toolpath-polyline]");
const rows = [...doc.querySelectorAll("[data-motion-row]")];
const programRows = [...doc.querySelectorAll("[data-program-line]")];
const canonicalOutput = doc.querySelector("[data-canonical-output]")?.textContent ?? "";
if (doc.body.dataset.simulationReady !== "true") {
throw new Error("simulation body readiness flag not true");
}
if (state.apiName !== "real-browser-simulation-state") {
throw new Error("simulation state API name drift");
}
if (state.summary.motionEventCount < 5) {
throw new Error("simulation motion event count too low");
}
if (!canonicalOutput.includes("canon_event=STRAIGHT_FEED line=2 x=1 y=0 z=0")) {
throw new Error("simulation canonical output missing LinuxCNC feed event");
}
if (!polyline?.getAttribute("points")?.includes("1,0")) {
throw new Error("simulation toolpath polyline missing expected point");
}
if (rows.length !== state.motion.length) {
throw new Error("simulation motion table row count drift");
}
if (programRows.length < 6) {
throw new Error("simulation program rows missing");
}
if (doc.querySelector('[data-axis="x"]')?.textContent !== "0.000") {
throw new Error("simulation final X axis drift");
}
if (doc.querySelector('[data-axis="y"]')?.textContent !== "0.000") {
throw new Error("simulation final Y axis drift");
}
if (!doc.querySelector("[data-toolpath-svg]")?.getAttribute("viewBox")) {
throw new Error("simulation SVG viewBox missing");
}
status.textContent = "browser_real_simulation_page_smoke=ok";
} catch (error) {
status.textContent = `browser_real_simulation_page_smoke=fail ${error.stack || error.message}`;
throw error;
}
</script>
</body>
</html>

View File

@@ -68,7 +68,7 @@
); );
assertEqual(readyWorkflow.ready, true, "ready workflow readiness"); assertEqual(readyWorkflow.ready, true, "ready workflow readiness");
assertEqual(readyWorkflow.httpStatus, 200, "ready workflow HTTP status"); assertEqual(readyWorkflow.httpStatus, 200, "ready workflow HTTP status");
assertEqual(readyWorkflow.validation.gateCount, 11, "ready workflow gate count"); assertEqual(readyWorkflow.validation.gateCount, 12, "ready workflow gate count");
assertEqual( assertEqual(
readyWorkflow.validationSummaryViewModel.statusLine, readyWorkflow.validationSummaryViewModel.statusLine,
"Ready: Artifact evidence complete", "Ready: Artifact evidence complete",

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
CHROMIUM="${CHROMIUM:-$(command -v chromium || command -v chromium-browser || command -v google-chrome || command -v google-chrome-stable || true)}"
if [[ -z "$CHROMIUM" ]]; then
echo "missing Chromium-compatible browser; set CHROMIUM=/path/to/browser" >&2
exit 1
fi
if [[ "${SKIP_INTERP_BUILD:-0}" != "1" ]]; then
"$ROOT_DIR/tools/build_wasm_core.sh"
fi
TMP_DIR="$(mktemp -d)"
PORT_FILE="$TMP_DIR/port"
SERVER_LOG="$TMP_DIR/server.log"
CHROME_PROFILE="$TMP_DIR/chrome-profile"
mkdir -p "$CHROME_PROFILE"
cleanup() {
if [[ -n "${SERVER_PID:-}" ]]; then
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
fi
rm -rf "$TMP_DIR"
}
trap cleanup EXIT
python3 - <<'PY' "$ROOT_DIR" "$PORT_FILE" >"$SERVER_LOG" 2>&1 &
import functools
import http.server
import pathlib
import socketserver
import sys
root = pathlib.Path(sys.argv[1])
port_file = pathlib.Path(sys.argv[2])
handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory=str(root))
with socketserver.TCPServer(("127.0.0.1", 0), handler) as httpd:
port_file.write_text(str(httpd.server_address[1]), encoding="ascii")
httpd.serve_forever()
PY
SERVER_PID=$!
for _ in $(seq 1 100); do
[[ -s "$PORT_FILE" ]] && break
sleep 0.05
done
if [[ ! -s "$PORT_FILE" ]]; then
echo "real simulation browser smoke HTTP server did not start" >&2
cat "$SERVER_LOG" >&2 || true
exit 1
fi
PORT="$(cat "$PORT_FILE")"
URL="http://127.0.0.1:$PORT/tests/browser/real_simulation_page_smoke.html"
OUT="$TMP_DIR/chromium-real-simulation.out"
"$CHROMIUM" \
--headless=new \
--disable-gpu \
--no-sandbox \
--user-data-dir="$CHROME_PROFILE" \
--virtual-time-budget=10000 \
--dump-dom \
"$URL" >"$OUT" 2>&1
if ! grep -Fq "browser_real_simulation_page_smoke=ok" "$OUT"; then
echo "browser real simulation page smoke failed" >&2
sed -n '1,260p' "$OUT" >&2
exit 1
fi
echo "browser_real_simulation_page_smoke=ok"

View File

@@ -14,6 +14,10 @@ const handoffText = readFileSync(resolve(root, "docs/project-release-handoff.md"
const readmeText = readFileSync(resolve(root, "README.md"), "utf8"); const readmeText = readFileSync(resolve(root, "README.md"), "utf8");
const panelEntryText = readFileSync(resolve(root, "docs/panel-entry.md"), "utf8"); const panelEntryText = readFileSync(resolve(root, "docs/panel-entry.md"), "utf8");
const sdkReadmeText = readFileSync(resolve(root, "runtime/sdk/README.md"), "utf8"); const sdkReadmeText = readFileSync(resolve(root, "runtime/sdk/README.md"), "utf8");
const realBrowserSimulationPriorityText = readFileSync(
resolve(root, "docs/real-browser-simulation-priority.md"),
"utf8",
);
const sourceReuseText = readFileSync(resolve(root, "docs/source-reuse-map.md"), "utf8"); const sourceReuseText = readFileSync(resolve(root, "docs/source-reuse-map.md"), "utf8");
const driftText = readFileSync(resolve(root, "docs/drift-report.md"), "utf8"); const driftText = readFileSync(resolve(root, "docs/drift-report.md"), "utf8");
const hostSmokeText = readFileSync(resolve(root, "tests/host/verify_host_smokes.sh"), "utf8"); const hostSmokeText = readFileSync(resolve(root, "tests/host/verify_host_smokes.sh"), "utf8");
@@ -25,12 +29,18 @@ for (const phrase of [
"docs/panel-entry.md", "docs/panel-entry.md",
"runtime/sdk/README.md", "runtime/sdk/README.md",
"docs/opfs-session-persistence.md", "docs/opfs-session-persistence.md",
"docs/real-browser-simulation-priority.md",
"docs/sim-configs-coverage-handoff.md", "docs/sim-configs-coverage-handoff.md",
"docs/host-runtime-boundary-handoff.md", "docs/host-runtime-boundary-handoff.md",
"docs/source-reuse-map.md", "docs/source-reuse-map.md",
"docs/drift-report.md", "docs/drift-report.md",
"PROJECT_COMPLETION_TRACKER.md", "PROJECT_COMPLETION_TRACKER.md",
"runtime/sdk/src/index.js", "runtime/sdk/src/index.js",
"real browser CNC simulation page",
"runtime/ui/simulation/index.html",
"verify_real_simulation_browser.sh",
"LinuxCNC-backed interpreter execution",
"toolpath/preview area",
"createProjectReleaseGateManifest()", "createProjectReleaseGateManifest()",
"createProjectReleaseGateResultMatrix()", "createProjectReleaseGateResultMatrix()",
"createProjectReleaseGateActionPlan()", "createProjectReleaseGateActionPlan()",
@@ -46,9 +56,48 @@ for (const phrase of [
"loadProjectReleaseReadinessArtifactUrlWorkflow()", "loadProjectReleaseReadinessArtifactUrlWorkflow()",
"createProjectReleaseReadinessArtifactUrlWorkflowActionPlan()", "createProjectReleaseReadinessArtifactUrlWorkflowActionPlan()",
"createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel()", "createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel()",
"createProjectBatchAcceptanceCapabilityMatrix()",
"createProjectBatchAcceptanceWorkflow()",
"createProjectBatchAcceptanceChecklist()",
"createProjectBatchAcceptanceReport()",
"createProjectBatchAcceptanceReportValidation()",
"createProjectBatchAcceptanceReportValidationSummaryViewModel()",
"createProjectBatchAcceptanceReportValidationActionPlan()",
"createProjectBatchAcceptanceReportJsonWorkflow()",
"loadProjectBatchAcceptanceReportUrlWorkflow()",
"createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel()",
"createProjectBatchAcceptanceReportUrlWorkflowActionPlan()",
"write_project_batch_acceptance_artifact.mjs",
"verify_project_batch_acceptance_artifact.sh",
"embedded gate manifest, execution manifest, result matrix, and", "embedded gate manifest, execution manifest, result matrix, and",
"validateWorkflowOverviewReleaseReadinessArtifactJson()", "validateWorkflowOverviewReleaseReadinessArtifactJson()",
"runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow()",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel()",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan()",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract()",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness()",
"renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()",
"mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()",
"loadWorkflowOverviewReleaseReadinessArtifactUrl()", "loadWorkflowOverviewReleaseReadinessArtifactUrl()",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel()",
"getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel()",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState()",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract()",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness()",
"renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()",
"mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan()",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState()",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract()",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness()",
"renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()",
"mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan()",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState()",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract()",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness()",
"renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()",
"mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel()", "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel()",
"render-state", "render-state",
"DOM readiness", "DOM readiness",
@@ -61,15 +110,21 @@ for (const phrase of [
"build/project-release-readiness.json", "build/project-release-readiness.json",
"verify_project_release_readiness_artifact.sh", "verify_project_release_readiness_artifact.sh",
"verify_project_release_artifact_url_workflow.sh", "verify_project_release_artifact_url_workflow.sh",
"verify_project_batch_acceptance_workflow.sh",
"verify_real_browser_simulation_priority_docs.sh",
"verify_opfs_session_workflow_browser.sh", "verify_opfs_session_workflow_browser.sh",
"host_wasm_opfs_browser_smokes=ok", "host_wasm_opfs_browser_smokes=ok",
"project_release_readiness_artifact_node_smoke=ok", "project_release_readiness_artifact_node_smoke=ok",
"project_release_artifact_url_workflow_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",
"real_browser_simulation_priority_docs_node_smoke=ok",
"project_release_gate=ok", "project_release_gate=ok",
"sim_configs_wasm_node_inventory_unexpected_fail=0", "sim_configs_wasm_node_inventory_unexpected_fail=0",
"browser_ini_shell_integration_workflow_smoke=ok", "browser_ini_shell_integration_workflow_smoke=ok",
"browser_opfs_session_workflow_smoke=ok", "browser_opfs_session_workflow_smoke=ok",
"browser_release_artifact_url_workflow_smoke=ok", "browser_release_artifact_url_workflow_smoke=ok",
"browser_real_simulation_page_smoke=ok",
"project_release_handoff_docs_node_smoke=ok", "project_release_handoff_docs_node_smoke=ok",
"L4-USER-M-PROCESS", "L4-USER-M-PROCESS",
"L4-TOOL-DB", "L4-TOOL-DB",
@@ -80,7 +135,9 @@ for (const phrase of [
for (const phrase of [ for (const phrase of [
"docs/project-release-handoff.md", "docs/project-release-handoff.md",
"docs/real-browser-simulation-priority.md",
"project_release_handoff_docs_node_smoke=ok", "project_release_handoff_docs_node_smoke=ok",
"real_browser_simulation_priority_docs_node_smoke=ok",
]) { ]) {
assert.match(readmeText, literalRegExp(phrase)); assert.match(readmeText, literalRegExp(phrase));
assert.match(hostSmokeText, literalRegExp("verify_project_release_handoff_docs.sh")); assert.match(hostSmokeText, literalRegExp("verify_project_release_handoff_docs.sh"));
@@ -95,11 +152,15 @@ for (const phrase of [
"verify_ini_panel_browser.sh", "verify_ini_panel_browser.sh",
"verify_opfs_session_workflow_browser.sh", "verify_opfs_session_workflow_browser.sh",
"verify_release_artifact_url_workflow_browser.sh", "verify_release_artifact_url_workflow_browser.sh",
"verify_project_batch_acceptance_workflow.sh",
"verify_real_browser_simulation_priority_docs.sh",
"verify_ui_node_smokes.sh", "verify_ui_node_smokes.sh",
"verify_host_smokes.sh", "verify_host_smokes.sh",
"write_project_release_readiness_artifact.mjs", "write_project_release_readiness_artifact.mjs",
"verify_project_release_readiness_artifact.sh", "verify_project_release_readiness_artifact.sh",
"verify_project_release_artifact_url_workflow.sh", "verify_project_release_artifact_url_workflow.sh",
"verify_project_batch_acceptance_workflow.sh",
"verify_real_browser_simulation_priority_docs.sh",
"project_release_gate=ok", "project_release_gate=ok",
]) { ]) {
assert.match(projectReleaseGateText, literalRegExp(phrase)); assert.match(projectReleaseGateText, literalRegExp(phrase));
@@ -136,8 +197,51 @@ for (const phrase of [
"loadProjectReleaseReadinessArtifactUrlWorkflow()", "loadProjectReleaseReadinessArtifactUrlWorkflow()",
"createProjectReleaseReadinessArtifactUrlWorkflowActionPlan()", "createProjectReleaseReadinessArtifactUrlWorkflowActionPlan()",
"createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel()", "createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel()",
"createProjectBatchAcceptanceCapabilityMatrix()",
"createProjectBatchAcceptanceWorkflow()",
"createProjectBatchAcceptanceChecklist()",
"createProjectBatchAcceptanceReport()",
"createProjectBatchAcceptanceReportValidation()",
"createProjectBatchAcceptanceReportValidationSummaryViewModel()",
"createProjectBatchAcceptanceReportValidationActionPlan()",
"createProjectBatchAcceptanceReportJsonWorkflow()",
"loadProjectBatchAcceptanceReportUrlWorkflow()",
"createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel()",
"createProjectBatchAcceptanceReportUrlWorkflowActionPlan()",
"createProjectBatchAcceptanceSummaryViewModel()",
"createProjectBatchAcceptanceActionPlan()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness()",
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()",
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness()",
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()",
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness()",
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()",
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState()",
"runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract()",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness()",
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()",
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState()",
"verify_project_release_artifact_url_workflow.sh", "verify_project_release_artifact_url_workflow.sh",
"verify_project_batch_acceptance_workflow.sh",
"verify_project_batch_acceptance_artifact.sh",
"project_release_artifact_url_workflow_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",
"build/project-release-readiness.json", "build/project-release-readiness.json",
"INI panel shell handoff exports", "INI panel shell handoff exports",
"createIniPanelShellApiSurfaceInventory()", "createIniPanelShellApiSurfaceInventory()",
@@ -148,7 +252,10 @@ for (const phrase of [
assert.match(sourceReuseText, literalRegExp("docs/project-release-handoff.md")); assert.match(sourceReuseText, literalRegExp("docs/project-release-handoff.md"));
assert.match(driftText, literalRegExp("docs/project-release-handoff.md")); assert.match(driftText, literalRegExp("docs/project-release-handoff.md"));
assert.match(realBrowserSimulationPriorityText, literalRegExp("first priority is to deliver a real browser CNC simulation page"));
assert.match(realBrowserSimulationPriorityText, literalRegExp("must not implement CNC semantics in JavaScript"));
assert.match(trackerText, /Documentation\/release gate/); assert.match(trackerText, /Documentation\/release gate/);
assert.match(trackerText, /Real browser simulation priority/);
assert.match(trackerText, /Project release gate wrapper/); assert.match(trackerText, /Project release gate wrapper/);
assert.match(trackerText, /Final Acceptance Checklist/); assert.match(trackerText, /Final Acceptance Checklist/);

View File

@@ -0,0 +1,53 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "../../..");
function literalRegExp(text) {
return new RegExp(text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
}
const priorityText = readFileSync(resolve(root, "docs/real-browser-simulation-priority.md"), "utf8");
const handoffText = readFileSync(resolve(root, "docs/project-release-handoff.md"), "utf8");
const readmeText = readFileSync(resolve(root, "README.md"), "utf8");
const trackerText = readFileSync(resolve(root, "../PROJECT_COMPLETION_TRACKER.md"), "utf8");
const hostSmokeText = readFileSync(resolve(root, "tests/host/verify_host_smokes.sh"), "utf8");
const releaseGateText = readFileSync(resolve(root, "tests/host/verify_project_release_gate.sh"), "utf8");
const simulationHtmlText = readFileSync(resolve(root, "runtime/ui/simulation/index.html"), "utf8");
const simulationSmokeText = readFileSync(resolve(root, "tests/browser/verify_real_simulation_browser.sh"), "utf8");
for (const phrase of [
"Real Browser Simulation Priority",
"first priority is to deliver a real browser CNC simulation page",
"machine/session loader",
"G-code program view",
"LinuxCNC-backed interpreter execution",
"toolpath/preview area",
"browser smoke coverage",
"must not implement CNC semantics in JavaScript",
"vendored LinuxCNC source",
"wasm-port/tests/docs/node/verify_real_browser_simulation_priority_docs.sh",
"runtime/ui/simulation/index.html",
"wasm-port/tests/browser/verify_real_simulation_browser.sh",
]) {
assert.match(priorityText, literalRegExp(phrase));
}
for (const text of [handoffText, readmeText, trackerText]) {
assert.match(text, literalRegExp("docs/real-browser-simulation-priority.md"));
assert.match(text, /real browser CNC simulation page|真实 UI\/browser 数控仿真页面/);
assert.match(text, /LinuxCNC semantic boundary|LinuxCNC 语义边界|LinuxCNC-backed/);
}
assert.match(hostSmokeText, /verify_real_browser_simulation_priority_docs\.sh/);
assert.match(hostSmokeText, /verify_real_simulation_browser\.sh/);
assert.match(releaseGateText, /verify_real_simulation_browser\.sh/);
assert.match(simulationHtmlText, /LinuxCNC Browser Simulation/);
assert.match(simulationHtmlText, /data-toolpath-svg/);
assert.match(simulationHtmlText, /data-program-lines/);
assert.match(simulationSmokeText, /browser_real_simulation_page_smoke=ok/);
console.log("real_browser_simulation_priority_docs_node_smoke=ok");

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
node "$ROOT_DIR/tests/docs/node/verify_real_browser_simulation_priority_docs.mjs"

View File

@@ -25,7 +25,7 @@
"gateManifest": { "gateManifest": {
"apiName": "project-release-gate-manifest", "apiName": "project-release-gate-manifest",
"manifestVersion": 1, "manifestVersion": 1,
"gateCount": 11, "gateCount": 12,
"gateIds": [ "gateIds": [
"diff-check", "diff-check",
"vendor-sync", "vendor-sync",
@@ -35,6 +35,7 @@
"ini-panel-browser", "ini-panel-browser",
"opfs-session-browser", "opfs-session-browser",
"release-artifact-url-browser", "release-artifact-url-browser",
"project-batch-acceptance",
"ui-node-smokes", "ui-node-smokes",
"host-smokes", "host-smokes",
"project-release-gate" "project-release-gate"
@@ -88,6 +89,12 @@
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh", "command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh",
"expectedOutput": "browser_release_artifact_url_workflow_smoke=ok" "expectedOutput": "browser_release_artifact_url_workflow_smoke=ok"
}, },
{
"id": "project-batch-acceptance",
"label": "Project batch acceptance workflow smoke",
"command": "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
"expectedOutput": "project_batch_acceptance_workflow_node_smoke=ok"
},
{ {
"id": "ui-node-smokes", "id": "ui-node-smokes",
"label": "UI Node smokes", "label": "UI Node smokes",
@@ -113,14 +120,14 @@
"manifestVersion": 1, "manifestVersion": 1,
"phase": "ready", "phase": "ready",
"ready": true, "ready": true,
"gateCount": 11, "gateCount": 12,
"passedCount": 11, "passedCount": 12,
"unknownCount": 0, "unknownCount": 0,
"missingGateIds": [], "missingGateIds": [],
"manifest": { "manifest": {
"apiName": "project-release-gate-manifest", "apiName": "project-release-gate-manifest",
"manifestVersion": 1, "manifestVersion": 1,
"gateCount": 11, "gateCount": 12,
"gateIds": [ "gateIds": [
"diff-check", "diff-check",
"vendor-sync", "vendor-sync",
@@ -130,6 +137,7 @@
"ini-panel-browser", "ini-panel-browser",
"opfs-session-browser", "opfs-session-browser",
"release-artifact-url-browser", "release-artifact-url-browser",
"project-batch-acceptance",
"ui-node-smokes", "ui-node-smokes",
"host-smokes", "host-smokes",
"project-release-gate" "project-release-gate"
@@ -183,6 +191,12 @@
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh", "command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh",
"expectedOutput": "browser_release_artifact_url_workflow_smoke=ok" "expectedOutput": "browser_release_artifact_url_workflow_smoke=ok"
}, },
{
"id": "project-batch-acceptance",
"label": "Project batch acceptance workflow smoke",
"command": "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
"expectedOutput": "project_batch_acceptance_workflow_node_smoke=ok"
},
{ {
"id": "ui-node-smokes", "id": "ui-node-smokes",
"label": "UI Node smokes", "label": "UI Node smokes",
@@ -210,7 +224,7 @@
"command": "git diff --check", "command": "git diff --check",
"expectedOutput": null, "expectedOutput": null,
"observedOutput": null, "observedOutput": null,
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "explicit-result" "evidence": "explicit-result"
@@ -221,7 +235,7 @@
"command": "wasm-port/tools/verify_vendor_sync.sh", "command": "wasm-port/tools/verify_vendor_sync.sh",
"expectedOutput": "vendor sync up to date", "expectedOutput": "vendor sync up to date",
"observedOutput": "vendor sync up to date", "observedOutput": "vendor sync up to date",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -232,7 +246,7 @@
"command": "wasm-port/tools/verify_no_standalone_cnc_semantics.sh", "command": "wasm-port/tools/verify_no_standalone_cnc_semantics.sh",
"expectedOutput": "standalone CNC semantics guard complete", "expectedOutput": "standalone CNC semantics guard complete",
"observedOutput": "standalone CNC semantics guard complete", "observedOutput": "standalone CNC semantics guard complete",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -243,7 +257,7 @@
"command": "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh", "command": "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh",
"expectedOutput": "interp_wasm_node_smoke=ok", "expectedOutput": "interp_wasm_node_smoke=ok",
"observedOutput": "interp_wasm_node_smoke=ok", "observedOutput": "interp_wasm_node_smoke=ok",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -254,7 +268,7 @@
"command": "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh", "command": "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh",
"expectedOutput": "sim_configs_wasm_node_inventory_unexpected_fail=0", "expectedOutput": "sim_configs_wasm_node_inventory_unexpected_fail=0",
"observedOutput": "sim_configs_wasm_node_inventory_unexpected_fail=0", "observedOutput": "sim_configs_wasm_node_inventory_unexpected_fail=0",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -265,7 +279,7 @@
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh", "command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh",
"expectedOutput": "browser_ini_shell_integration_workflow_smoke=ok", "expectedOutput": "browser_ini_shell_integration_workflow_smoke=ok",
"observedOutput": "browser_ini_shell_integration_workflow_smoke=ok", "observedOutput": "browser_ini_shell_integration_workflow_smoke=ok",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -276,7 +290,7 @@
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_opfs_session_workflow_browser.sh", "command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_opfs_session_workflow_browser.sh",
"expectedOutput": "browser_opfs_session_workflow_smoke=ok", "expectedOutput": "browser_opfs_session_workflow_smoke=ok",
"observedOutput": "browser_opfs_session_workflow_smoke=ok", "observedOutput": "browser_opfs_session_workflow_smoke=ok",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -287,7 +301,18 @@
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh", "command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh",
"expectedOutput": "browser_release_artifact_url_workflow_smoke=ok", "expectedOutput": "browser_release_artifact_url_workflow_smoke=ok",
"observedOutput": "browser_release_artifact_url_workflow_smoke=ok", "observedOutput": "browser_release_artifact_url_workflow_smoke=ok",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed",
"passed": true,
"evidence": "expected-output"
},
{
"id": "project-batch-acceptance",
"label": "Project batch acceptance workflow smoke",
"command": "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
"expectedOutput": "project_batch_acceptance_workflow_node_smoke=ok",
"observedOutput": "project_batch_acceptance_workflow_node_smoke=ok",
"observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -298,7 +323,7 @@
"command": "wasm-port/tests/ui/node/verify_ui_node_smokes.sh", "command": "wasm-port/tests/ui/node/verify_ui_node_smokes.sh",
"expectedOutput": "ui_node_smokes=ok", "expectedOutput": "ui_node_smokes=ok",
"observedOutput": "ui_node_smokes=ok", "observedOutput": "ui_node_smokes=ok",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -309,7 +334,7 @@
"command": "wasm-port/tests/host/verify_host_smokes.sh", "command": "wasm-port/tests/host/verify_host_smokes.sh",
"expectedOutput": "host_wasm_opfs_browser_smokes=ok", "expectedOutput": "host_wasm_opfs_browser_smokes=ok",
"observedOutput": "host_wasm_opfs_browser_smokes=ok", "observedOutput": "host_wasm_opfs_browser_smokes=ok",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -320,7 +345,7 @@
"command": "wasm-port/tests/host/verify_project_release_gate.sh", "command": "wasm-port/tests/host/verify_project_release_gate.sh",
"expectedOutput": "project_release_gate=ok", "expectedOutput": "project_release_gate=ok",
"observedOutput": "project_release_gate=ok", "observedOutput": "project_release_gate=ok",
"observedOutputCount": 10, "observedOutputCount": 11,
"status": "passed", "status": "passed",
"passed": true, "passed": true,
"evidence": "expected-output" "evidence": "expected-output"
@@ -336,20 +361,20 @@
"statusText": "Ready", "statusText": "Ready",
"detailText": "All release gate evidence present", "detailText": "All release gate evidence present",
"statusLine": "Ready: All release gate evidence present", "statusLine": "Ready: All release gate evidence present",
"gateCount": 11, "gateCount": 12,
"passedCount": 11, "passedCount": 12,
"unknownCount": 0, "unknownCount": 0,
"missingGateIds": [], "missingGateIds": [],
"nextGateId": null, "nextGateId": null,
"evidenceCounts": { "evidenceCounts": {
"explicit-result": 1, "explicit-result": 1,
"expected-output": 10 "expected-output": 11
}, },
"rows": [ "rows": [
{ {
"id": "gate-results", "id": "gate-results",
"label": "Release gate evidence", "label": "Release gate evidence",
"value": "11/11 passed" "value": "12/12 passed"
}, },
{ {
"id": "unknown-gates", "id": "unknown-gates",
@@ -364,7 +389,7 @@
{ {
"id": "expected-output-evidence", "id": "expected-output-evidence",
"label": "Expected-output evidence", "label": "Expected-output evidence",
"value": "10" "value": "11"
}, },
{ {
"id": "explicit-result-evidence", "id": "explicit-result-evidence",
@@ -458,6 +483,16 @@
"status": "passed", "status": "passed",
"passed": true "passed": true
}, },
{
"id": "project-batch-acceptance",
"label": "Project batch acceptance workflow smoke",
"command": "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
"expectedOutput": "project_batch_acceptance_workflow_node_smoke=ok",
"observedOutput": "project_batch_acceptance_workflow_node_smoke=ok",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{ {
"id": "ui-node-smokes", "id": "ui-node-smokes",
"label": "UI Node smokes", "label": "UI Node smokes",
@@ -495,14 +530,14 @@
"matrixVersion": 1, "matrixVersion": 1,
"phase": "ready", "phase": "ready",
"ready": true, "ready": true,
"gateCount": 11, "gateCount": 12,
"passedCount": 11, "passedCount": 12,
"unknownCount": 0, "unknownCount": 0,
"missingGateIds": [], "missingGateIds": [],
"manifest": { "manifest": {
"apiName": "project-release-gate-manifest", "apiName": "project-release-gate-manifest",
"manifestVersion": 1, "manifestVersion": 1,
"gateCount": 11, "gateCount": 12,
"gateIds": [ "gateIds": [
"diff-check", "diff-check",
"vendor-sync", "vendor-sync",
@@ -512,6 +547,7 @@
"ini-panel-browser", "ini-panel-browser",
"opfs-session-browser", "opfs-session-browser",
"release-artifact-url-browser", "release-artifact-url-browser",
"project-batch-acceptance",
"ui-node-smokes", "ui-node-smokes",
"host-smokes", "host-smokes",
"project-release-gate" "project-release-gate"
@@ -565,6 +601,12 @@
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh", "command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh",
"expectedOutput": "browser_release_artifact_url_workflow_smoke=ok" "expectedOutput": "browser_release_artifact_url_workflow_smoke=ok"
}, },
{
"id": "project-batch-acceptance",
"label": "Project batch acceptance workflow smoke",
"command": "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
"expectedOutput": "project_batch_acceptance_workflow_node_smoke=ok"
},
{ {
"id": "ui-node-smokes", "id": "ui-node-smokes",
"label": "UI Node smokes", "label": "UI Node smokes",
@@ -650,6 +692,14 @@
"status": "passed", "status": "passed",
"passed": true "passed": true
}, },
{
"id": "project-batch-acceptance",
"label": "Project batch acceptance workflow smoke",
"command": "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
"expectedOutput": "project_batch_acceptance_workflow_node_smoke=ok",
"status": "passed",
"passed": true
},
{ {
"id": "ui-node-smokes", "id": "ui-node-smokes",
"label": "UI Node smokes", "label": "UI Node smokes",
@@ -681,8 +731,8 @@
"planVersion": 1, "planVersion": 1,
"phase": "ready", "phase": "ready",
"ready": true, "ready": true,
"gateCount": 11, "gateCount": 12,
"completedCount": 11, "completedCount": 12,
"pendingCount": 0, "pendingCount": 0,
"completedGateIds": [ "completedGateIds": [
"diff-check", "diff-check",
@@ -693,6 +743,7 @@
"ini-panel-browser", "ini-panel-browser",
"opfs-session-browser", "opfs-session-browser",
"release-artifact-url-browser", "release-artifact-url-browser",
"project-batch-acceptance",
"ui-node-smokes", "ui-node-smokes",
"host-smokes", "host-smokes",
"project-release-gate" "project-release-gate"
@@ -769,6 +820,14 @@
"status": "passed", "status": "passed",
"passed": true "passed": true
}, },
{
"id": "project-batch-acceptance",
"label": "Project batch acceptance workflow smoke",
"command": "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
"expectedOutput": "project_batch_acceptance_workflow_node_smoke=ok",
"status": "passed",
"passed": true
},
{ {
"id": "ui-node-smokes", "id": "ui-node-smokes",
"label": "UI Node smokes", "label": "UI Node smokes",

View File

@@ -18,8 +18,10 @@ SKIP_TP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_tp_wasm.sh"
"$ROOT_DIR/tests/docs/node/verify_sim_configs_coverage_docs.sh" "$ROOT_DIR/tests/docs/node/verify_sim_configs_coverage_docs.sh"
"$ROOT_DIR/tests/docs/node/verify_host_runtime_boundary_docs.sh" "$ROOT_DIR/tests/docs/node/verify_host_runtime_boundary_docs.sh"
"$ROOT_DIR/tests/docs/node/verify_project_release_handoff_docs.sh" "$ROOT_DIR/tests/docs/node/verify_project_release_handoff_docs.sh"
"$ROOT_DIR/tests/docs/node/verify_real_browser_simulation_priority_docs.sh"
"$ROOT_DIR/tests/ui/node/verify_ui_node_smokes.sh" "$ROOT_DIR/tests/ui/node/verify_ui_node_smokes.sh"
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_ini_panel_browser.sh" SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_ini_panel_browser.sh"
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_real_simulation_browser.sh"
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_opfs_session_workflow_browser.sh" SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_opfs_session_workflow_browser.sh"
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_interp_browser.sh" SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_interp_browser.sh"

View File

@@ -12,10 +12,13 @@ git diff --check
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_interp_wasm.sh" SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_interp_wasm.sh"
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_sim_configs_inventory_wasm.sh" SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_sim_configs_inventory_wasm.sh"
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_ini_panel_browser.sh" SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_ini_panel_browser.sh"
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_real_simulation_browser.sh"
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_opfs_session_workflow_browser.sh" SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_opfs_session_workflow_browser.sh"
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_release_artifact_url_workflow_browser.sh" SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_release_artifact_url_workflow_browser.sh"
"$ROOT_DIR/tests/sdk/node/verify_project_batch_acceptance_workflow.sh"
"$ROOT_DIR/tests/ui/node/verify_ui_node_smokes.sh" "$ROOT_DIR/tests/ui/node/verify_ui_node_smokes.sh"
"$ROOT_DIR/tests/sdk/node/verify_project_release_artifact_url_workflow.sh" "$ROOT_DIR/tests/sdk/node/verify_project_release_artifact_url_workflow.sh"
"$ROOT_DIR/tests/docs/node/verify_real_browser_simulation_priority_docs.sh"
"$ROOT_DIR/tests/host/verify_host_smokes.sh" "$ROOT_DIR/tests/host/verify_host_smokes.sh"
node "$ROOT_DIR/tests/host/write_project_release_readiness_artifact.mjs" node "$ROOT_DIR/tests/host/write_project_release_readiness_artifact.mjs"

View File

@@ -20,8 +20,8 @@ assert.equal(validation.phase, "ready");
assert.deepEqual(validation.missing, []); assert.deepEqual(validation.missing, []);
assert.equal(validation.artifactApiName, "project-release-readiness-report"); assert.equal(validation.artifactApiName, "project-release-readiness-report");
assert.equal(validation.artifactVersion, 1); assert.equal(validation.artifactVersion, 1);
assert.equal(validation.gateCount, 11); assert.equal(validation.gateCount, 12);
assert.equal(validation.expectedGateCount, 11); assert.equal(validation.expectedGateCount, 12);
assert.equal(validation.gateManifestReady, true); assert.equal(validation.gateManifestReady, true);
assert.equal(validation.gateExecutionManifestReady, true); assert.equal(validation.gateExecutionManifestReady, true);
assert.equal(validation.gateExecutionSummaryReady, true); assert.equal(validation.gateExecutionSummaryReady, true);
@@ -36,15 +36,16 @@ assert.deepEqual(validation.expectedGateIds, [
"ini-panel-browser", "ini-panel-browser",
"opfs-session-browser", "opfs-session-browser",
"release-artifact-url-browser", "release-artifact-url-browser",
"project-batch-acceptance",
"ui-node-smokes", "ui-node-smokes",
"host-smokes", "host-smokes",
"project-release-gate", "project-release-gate",
]); ]);
assert.equal(artifact.gateManifest.apiName, "project-release-gate-manifest"); assert.equal(artifact.gateManifest.apiName, "project-release-gate-manifest");
assert.equal(artifact.gateExecutionManifest.apiName, "project-release-gate-execution-manifest"); assert.equal(artifact.gateExecutionManifest.apiName, "project-release-gate-execution-manifest");
assert.equal(artifact.gateExecutionManifest.passedCount, 11); assert.equal(artifact.gateExecutionManifest.passedCount, 12);
assert.equal(artifact.gateExecutionSummaryViewModel.apiName, "project-release-gate-execution-summary-view-model"); assert.equal(artifact.gateExecutionSummaryViewModel.apiName, "project-release-gate-execution-summary-view-model");
assert.equal(artifact.gateExecutionSummaryViewModel.rows[0].value, "11/11 passed"); assert.equal(artifact.gateExecutionSummaryViewModel.rows[0].value, "12/12 passed");
assert.equal(artifact.gateResultMatrix.apiName, "project-release-gate-result-matrix"); assert.equal(artifact.gateResultMatrix.apiName, "project-release-gate-result-matrix");
assert.equal(artifact.gateActionPlan.apiName, "project-release-gate-action-plan"); assert.equal(artifact.gateActionPlan.apiName, "project-release-gate-action-plan");
assert.equal(artifact.gateActionPlan.pendingCount, 0); assert.equal(artifact.gateActionPlan.pendingCount, 0);

View File

@@ -17,6 +17,7 @@ const passedGateResults = {
"ini-panel-browser": true, "ini-panel-browser": true,
"opfs-session-browser": true, "opfs-session-browser": true,
"release-artifact-url-browser": true, "release-artifact-url-browser": true,
"project-batch-acceptance": true,
"ui-node-smokes": true, "ui-node-smokes": true,
"host-smokes": true, "host-smokes": true,
"project-release-gate": true, "project-release-gate": true,
@@ -32,6 +33,7 @@ const report = createProjectReleaseReadinessReport({
"browser_ini_shell_integration_workflow_smoke=ok", "browser_ini_shell_integration_workflow_smoke=ok",
"browser_opfs_session_workflow_smoke=ok", "browser_opfs_session_workflow_smoke=ok",
"browser_release_artifact_url_workflow_smoke=ok", "browser_release_artifact_url_workflow_smoke=ok",
"project_batch_acceptance_workflow_node_smoke=ok",
"ui_node_smokes=ok", "ui_node_smokes=ok",
"host_wasm_opfs_browser_smokes=ok", "host_wasm_opfs_browser_smokes=ok",
"project_release_gate=ok", "project_release_gate=ok",

View File

@@ -0,0 +1,51 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import {
createProjectBatchAcceptanceReportJsonWorkflow,
createProjectBatchAcceptanceReportValidationActionPlan,
createProjectBatchAcceptanceReportValidationSummaryViewModel,
createProjectBatchAcceptanceReportValidation,
} from "../../../runtime/sdk/src/index.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "../../..");
const artifactPath = process.argv[2] ?? resolve(root, "build/project-batch-acceptance.json");
const artifactJson = readFileSync(artifactPath, "utf8");
const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson: artifactJson });
const validation = createProjectBatchAcceptanceReportValidation(jsonWorkflow.report);
const validationSummary = createProjectBatchAcceptanceReportValidationSummaryViewModel(validation);
const validationActionPlan = createProjectBatchAcceptanceReportValidationActionPlan(validation);
assert.equal(jsonWorkflow.apiName, "project-batch-acceptance-report-json-workflow");
assert.equal(jsonWorkflow.ready, true);
assert.equal(jsonWorkflow.phase, "ready");
assert.equal(jsonWorkflow.parsed, true);
assert.equal(jsonWorkflow.parseError, null);
assert.deepEqual(jsonWorkflow.missing, []);
assert.equal(validation.apiName, "project-batch-acceptance-report-validation");
assert.equal(validation.ready, true);
assert.equal(validation.phase, "ready");
assert.deepEqual(validation.missing, []);
assert.equal(validation.batchId, "project-batch-acceptance-artifact");
assert.equal(jsonWorkflow.report.apiName, "project-batch-acceptance-report");
assert.equal(jsonWorkflow.report.reportVersion, 1);
assert.equal(jsonWorkflow.report.ready, true);
assert.equal(jsonWorkflow.report.capabilityMatrix.ready, true);
assert.deepEqual(jsonWorkflow.report.capabilityMatrix.capabilityTypes, ["workflow", "gate"]);
assert.equal(jsonWorkflow.report.workflow.ready, true);
assert.equal(jsonWorkflow.report.summaryViewModel.statusLine, "Ready: Batch acceptance evidence complete");
assert.equal(jsonWorkflow.report.actionPlan.nextCommand, null);
assert.equal(jsonWorkflow.report.checklist.passedCount, 3);
assert.equal(jsonWorkflow.report.rows.find(({ id }) => id === "checklist")?.value, "3/3 passed");
assert.equal(validationSummary.apiName, "project-batch-acceptance-report-validation-summary-view-model");
assert.equal(validationSummary.statusLine, "Ready: Batch acceptance report evidence complete");
assert.equal(validationSummary.rows.find(({ id }) => id === "validation")?.value, "ready");
assert.equal(validationActionPlan.apiName, "project-batch-acceptance-report-validation-action-plan");
assert.equal(validationActionPlan.ready, true);
assert.equal(validationActionPlan.nextCommand, null);
assert.equal(validationActionPlan.shellScript, "# Project batch acceptance report validation is already ready.\n");
console.log("project_batch_acceptance_artifact_node_smoke=ok");

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
node "$ROOT_DIR/tests/sdk/node/verify_project_batch_acceptance_artifact.mjs" "$@"

View File

@@ -0,0 +1,507 @@
import assert from "node:assert/strict";
import {
createProjectBatchAcceptanceActionPlan,
createProjectBatchAcceptanceCapabilityMatrix,
createProjectBatchAcceptanceChecklist,
createProjectBatchAcceptanceReport,
createProjectBatchAcceptanceReportJsonWorkflow,
createProjectBatchAcceptanceReportUrlWorkflowActionPlan,
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel,
createProjectBatchAcceptanceReportValidationActionPlan,
createProjectBatchAcceptanceReportValidationSummaryViewModel,
createProjectBatchAcceptanceReportValidation,
createProjectBatchAcceptanceSummaryViewModel,
createProjectBatchAcceptanceWorkflow,
loadProjectBatchAcceptanceReportUrlWorkflow,
} from "../../../runtime/sdk/src/index.js";
const readyCapabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({
capabilities: [
{
id: "callable-api",
type: "api",
label: "Callable API",
evidence: "createProjectBatchAcceptanceCapabilityMatrix",
},
{
id: "browser-smoke",
type: "browser",
label: "Browser smoke",
evidence: "browser smoke output",
},
{
id: "docs-only-note",
type: "docs",
label: "Docs-only note",
},
],
});
assert.equal(readyCapabilityMatrix.apiName, "project-batch-acceptance-capability-matrix");
assert.equal(readyCapabilityMatrix.matrixVersion, 1);
assert.equal(readyCapabilityMatrix.phase, "ready");
assert.equal(readyCapabilityMatrix.ready, true);
assert.deepEqual(readyCapabilityMatrix.acceptedCapabilityTypes, ["api", "workflow", "gate", "browser"]);
assert.deepEqual(readyCapabilityMatrix.capabilityTypes, ["api", "browser"]);
assert.equal(readyCapabilityMatrix.capabilityCount, 2);
assert.equal(readyCapabilityMatrix.acceptedCount, 2);
assert.equal(readyCapabilityMatrix.rejectedCount, 1);
assert.deepEqual(readyCapabilityMatrix.countsByType, {
api: 1,
workflow: 0,
gate: 0,
browser: 1,
});
assert.equal(readyCapabilityMatrix.rejectedCapabilities[0].type, "docs");
assert.deepEqual(readyCapabilityMatrix.missing, []);
assert.deepEqual(
readyCapabilityMatrix.rows.map(({ id, value }) => [id, value]),
[
["accepted-capabilities", "2"],
["accepted-types", "api, browser"],
["rejected-capabilities", "1"],
["missing", "none"],
],
);
const blockedCapabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({
capabilities: [
{
id: "docs-only-note",
type: "docs",
label: "Docs-only note",
},
],
});
assert.equal(blockedCapabilityMatrix.phase, "blocked");
assert.equal(blockedCapabilityMatrix.ready, false);
assert.equal(blockedCapabilityMatrix.acceptedCount, 0);
assert.equal(blockedCapabilityMatrix.rejectedCount, 1);
assert.deepEqual(blockedCapabilityMatrix.missing, ["batch-capability"]);
const readyWorkflow = createProjectBatchAcceptanceWorkflow({
batchId: "batch-acceptance-workflow",
capabilities: [
{
id: "project-batch-acceptance-workflow-api",
type: "api",
label: "Project batch acceptance workflow API",
evidence: "createProjectBatchAcceptanceWorkflow",
},
{
id: "project-batch-acceptance-node-gate",
type: "gate",
label: "Project batch acceptance Node gate",
evidence: "project_batch_acceptance_workflow_node_smoke=ok",
command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
},
],
observedOutputs: ["project_batch_acceptance_workflow_node_smoke=ok"],
});
assert.equal(readyWorkflow.apiName, "project-batch-acceptance-workflow");
assert.equal(readyWorkflow.workflowVersion, 1);
assert.equal(readyWorkflow.phase, "ready");
assert.equal(readyWorkflow.ready, true);
assert.equal(readyWorkflow.batchId, "batch-acceptance-workflow");
assert.deepEqual(readyWorkflow.acceptedCapabilityTypes, ["api", "workflow", "gate", "browser"]);
assert.deepEqual(readyWorkflow.capabilityTypes, ["api", "gate"]);
assert.equal(readyWorkflow.capabilityCount, 2);
assert.equal(readyWorkflow.capabilityMatrix.apiName, "project-batch-acceptance-capability-matrix");
assert.equal(readyWorkflow.capabilityMatrix.ready, true);
assert.deepEqual(readyWorkflow.missing, []);
assert.equal(
readyWorkflow.gateResultMatrix.rows.find(({ id }) => id === "project-batch-acceptance")?.passed,
true,
);
assert.deepEqual(
readyWorkflow.rows.map(({ id, value }) => [id, value]),
[
["batch", "batch-acceptance-workflow"],
["capabilities", "api, gate"],
["project-batch-acceptance", "passed"],
["missing", "none"],
],
);
const readySummary = createProjectBatchAcceptanceSummaryViewModel(readyWorkflow);
assert.equal(readySummary.apiName, "project-batch-acceptance-summary-view-model");
assert.equal(readySummary.phase, "ready");
assert.equal(readySummary.statusLine, "Ready: Batch acceptance evidence complete");
assert.equal(readySummary.rows.find(({ id }) => id === "capability-count")?.value, "2");
const readyActionPlan = createProjectBatchAcceptanceActionPlan(readyWorkflow);
assert.equal(readyActionPlan.apiName, "project-batch-acceptance-action-plan");
assert.equal(readyActionPlan.phase, "ready");
assert.equal(readyActionPlan.ready, true);
assert.equal(readyActionPlan.commandCount, 0);
assert.equal(readyActionPlan.nextCommand, null);
assert.equal(readyActionPlan.shellScript, "# Project batch acceptance workflow is already ready.\n");
const readyChecklist = createProjectBatchAcceptanceChecklist({
workflow: readyWorkflow,
actionPlan: readyActionPlan,
});
assert.equal(readyChecklist.apiName, "project-batch-acceptance-checklist");
assert.equal(readyChecklist.checklistVersion, 1);
assert.equal(readyChecklist.phase, "ready");
assert.equal(readyChecklist.ready, true);
assert.equal(readyChecklist.batchId, "batch-acceptance-workflow");
assert.equal(readyChecklist.passedCount, 3);
assert.equal(readyChecklist.blockedCount, 0);
assert.deepEqual(
readyChecklist.rows.map(({ id, value }) => [id, value]),
[
["accepted-capability", "pass: api, gate"],
["batch-acceptance-gate", "pass: passed"],
["next-action", "pass: none"],
],
);
const readyReport = createProjectBatchAcceptanceReport({
batchId: "batch-acceptance-workflow",
capabilities: readyWorkflow.capabilities,
observedOutputs: ["project_batch_acceptance_workflow_node_smoke=ok"],
});
assert.equal(readyReport.apiName, "project-batch-acceptance-report");
assert.equal(readyReport.reportVersion, 1);
assert.equal(readyReport.phase, "ready");
assert.equal(readyReport.ready, true);
assert.equal(readyReport.batchId, "batch-acceptance-workflow");
assert.deepEqual(readyReport.missing, []);
assert.equal(readyReport.capabilityMatrix.apiName, "project-batch-acceptance-capability-matrix");
assert.equal(readyReport.workflow.apiName, "project-batch-acceptance-workflow");
assert.equal(readyReport.summaryViewModel.statusLine, "Ready: Batch acceptance evidence complete");
assert.equal(readyReport.actionPlan.nextCommand, null);
assert.equal(readyReport.checklist.passedCount, 3);
assert.deepEqual(
readyReport.rows.map(({ id, value }) => [id, value]),
[
["summary", "Ready: Batch acceptance evidence complete"],
["capabilities", "api, gate"],
["checklist", "3/3 passed"],
["next-command", "none"],
],
);
const readyReportValidation = createProjectBatchAcceptanceReportValidation(readyReport);
const readyReportValidationSummary = createProjectBatchAcceptanceReportValidationSummaryViewModel(
readyReportValidation,
);
const readyReportValidationActionPlan = createProjectBatchAcceptanceReportValidationActionPlan(
readyReportValidation,
);
assert.equal(readyReportValidation.apiName, "project-batch-acceptance-report-validation");
assert.equal(readyReportValidation.validationVersion, 1);
assert.equal(readyReportValidation.phase, "ready");
assert.equal(readyReportValidation.ready, true);
assert.deepEqual(readyReportValidation.missing, []);
assert.equal(readyReportValidation.batchId, "batch-acceptance-workflow");
assert.deepEqual(
readyReportValidation.rows.map(({ id, value }) => [id, value]),
[
["report", "project-batch-acceptance-report"],
["capability-matrix", "ready"],
["workflow", "ready"],
["checklist", "ready"],
["missing", "none"],
],
);
assert.equal(
readyReportValidationSummary.statusLine,
"Ready: Batch acceptance report evidence complete",
);
assert.deepEqual(
readyReportValidationSummary.rows.map(({ id, value }) => [id, value]),
[
["report", "project-batch-acceptance-report"],
["batch", "batch-acceptance-workflow"],
["validation", "ready"],
["missing", "none"],
],
);
assert.deepEqual(readyReportValidationActionPlan, {
apiName: "project-batch-acceptance-report-validation-action-plan",
planVersion: 1,
phase: "ready",
ready: true,
missing: [],
missingCount: 0,
commandCount: 0,
nextActionId: null,
nextCommand: null,
commands: [],
shellScript: "# Project batch acceptance report validation is already ready.\n",
rows: [
["report-validation", "Report validation", "ready"],
["missing", "Missing report evidence", "none"],
["next-command", "Next command", "none"],
].map(([id, label, value]) => ({ id, label, value })),
});
const readyReportJsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({
reportJson: JSON.stringify(readyReport),
});
assert.equal(readyReportJsonWorkflow.apiName, "project-batch-acceptance-report-json-workflow");
assert.equal(readyReportJsonWorkflow.workflowVersion, 1);
assert.equal(readyReportJsonWorkflow.phase, "ready");
assert.equal(readyReportJsonWorkflow.ready, true);
assert.equal(readyReportJsonWorkflow.parsed, true);
assert.equal(readyReportJsonWorkflow.parseError, null);
assert.equal(readyReportJsonWorkflow.validation.ready, true);
assert.deepEqual(readyReportJsonWorkflow.missing, []);
let fetchedReportUrl = null;
const readyReportUrlWorkflow = await loadProjectBatchAcceptanceReportUrlWorkflow({
reportUrl: "/project-batch-acceptance.json",
fetchRef: async (url) => {
fetchedReportUrl = url;
return {
ok: true,
status: 200,
text: async () => JSON.stringify(readyReport),
};
},
});
const readyReportUrlSummary = createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel(
readyReportUrlWorkflow,
);
const readyReportUrlActionPlan = createProjectBatchAcceptanceReportUrlWorkflowActionPlan(
readyReportUrlWorkflow,
);
assert.equal(fetchedReportUrl, "/project-batch-acceptance.json");
assert.equal(readyReportUrlWorkflow.apiName, "project-batch-acceptance-report-url-workflow");
assert.equal(readyReportUrlWorkflow.workflowVersion, 1);
assert.equal(readyReportUrlWorkflow.phase, "ready");
assert.equal(readyReportUrlWorkflow.ready, true);
assert.equal(readyReportUrlWorkflow.fetched, true);
assert.equal(readyReportUrlWorkflow.httpStatus, 200);
assert.equal(readyReportUrlWorkflow.fetchError, null);
assert.equal(readyReportUrlWorkflow.jsonWorkflow.ready, true);
assert.equal(readyReportUrlWorkflow.validation.ready, true);
assert.deepEqual(readyReportUrlWorkflow.missing, []);
assert.equal(
readyReportUrlSummary.statusLine,
"Ready: Batch report URL workflow complete",
);
assert.deepEqual(
readyReportUrlSummary.rows.map(({ id, value }) => [id, value]),
[
["report-url", "/project-batch-acceptance.json"],
["fetch", "ready (200)"],
["json-workflow", "ready"],
["report-validation", "ready"],
["missing", "none"],
],
);
assert.deepEqual(readyReportUrlActionPlan, {
apiName: "project-batch-acceptance-report-url-workflow-action-plan",
planVersion: 1,
phase: "ready",
ready: true,
missing: [],
actionCount: 0,
commandCount: 0,
nextActionId: null,
nextCommand: null,
actions: [],
commands: [],
shellScript: "# Project batch acceptance report URL workflow is already ready.\n",
rows: [],
});
const blockedWorkflow = createProjectBatchAcceptanceWorkflow({
batchId: "docs-only-batch",
capabilities: [
{
id: "docs-only-note",
type: "docs",
label: "Docs-only note",
},
],
});
assert.equal(blockedWorkflow.phase, "blocked");
assert.equal(blockedWorkflow.ready, false);
assert.deepEqual(blockedWorkflow.capabilityTypes, []);
assert.equal(blockedWorkflow.rejectedCapabilities[0].type, "docs");
assert.deepEqual(blockedWorkflow.missing, ["batch-capability", "project-batch-acceptance"]);
const blockedSummary = createProjectBatchAcceptanceSummaryViewModel(blockedWorkflow);
assert.equal(blockedSummary.statusLine, "Blocked: batch-capability, project-batch-acceptance");
const blockedActionPlan = createProjectBatchAcceptanceActionPlan(blockedWorkflow);
assert.equal(blockedActionPlan.phase, "blocked");
assert.equal(blockedActionPlan.ready, false);
assert.equal(blockedActionPlan.commandCount, 1);
assert.equal(blockedActionPlan.nextActionId, "project-batch-acceptance");
assert.equal(
blockedActionPlan.nextCommand,
"wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
);
assert.match(blockedActionPlan.shellScript, /verify_project_batch_acceptance_workflow\.sh/);
const blockedChecklist = createProjectBatchAcceptanceChecklist({
workflow: blockedWorkflow,
actionPlan: blockedActionPlan,
});
assert.equal(blockedChecklist.phase, "blocked");
assert.equal(blockedChecklist.ready, false);
assert.equal(blockedChecklist.passedCount, 0);
assert.equal(blockedChecklist.blockedCount, 3);
assert.deepEqual(
blockedChecklist.items.map(({ id, status }) => [id, status]),
[
["accepted-capability", "blocked"],
["batch-acceptance-gate", "blocked"],
["next-action", "blocked"],
],
);
const blockedReport = createProjectBatchAcceptanceReport({
batchId: "docs-only-batch",
capabilities: blockedWorkflow.rejectedCapabilities,
});
assert.equal(blockedReport.phase, "blocked");
assert.equal(blockedReport.ready, false);
assert.deepEqual(blockedReport.missing, ["batch-capability", "project-batch-acceptance"]);
assert.equal(blockedReport.checklist.blockedCount, 3);
assert.equal(
blockedReport.rows.find(({ id }) => id === "next-command")?.value,
"wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
);
const blockedReportValidation = createProjectBatchAcceptanceReportValidation(blockedReport);
const blockedReportValidationSummary = createProjectBatchAcceptanceReportValidationSummaryViewModel(
blockedReportValidation,
);
const blockedReportValidationActionPlan = createProjectBatchAcceptanceReportValidationActionPlan(
blockedReportValidation,
);
assert.equal(blockedReportValidation.phase, "blocked");
assert.equal(blockedReportValidation.ready, false);
assert.deepEqual(blockedReportValidation.missing, [
"phase",
"ready",
"missing",
"capabilityMatrix",
"workflow",
"summaryViewModel",
"actionPlan",
"checklist",
"rows.checklist",
]);
assert.match(blockedReportValidationSummary.statusLine, /^Blocked: phase, ready, missing/);
assert.equal(blockedReportValidationSummary.rows.find(({ id }) => id === "validation")?.value, "blocked");
assert.equal(blockedReportValidationActionPlan.phase, "blocked");
assert.equal(blockedReportValidationActionPlan.ready, false);
assert.equal(blockedReportValidationActionPlan.commandCount, 1);
assert.equal(
blockedReportValidationActionPlan.nextCommand,
"wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
);
assert.equal(
blockedReportValidationActionPlan.commands[0].expectedOutput,
"project_batch_acceptance_artifact_node_smoke=ok",
);
const invalidReportJsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({
reportJson: "{not-json",
});
assert.equal(invalidReportJsonWorkflow.phase, "blocked");
assert.equal(invalidReportJsonWorkflow.ready, false);
assert.equal(invalidReportJsonWorkflow.parsed, false);
assert.match(invalidReportJsonWorkflow.parseError, /JSON/);
assert.equal(invalidReportJsonWorkflow.missing[0], "report-json");
const missingInputReportUrlWorkflow = await loadProjectBatchAcceptanceReportUrlWorkflow({
reportUrl: "",
fetchRef: null,
});
const missingInputReportUrlActionPlan = createProjectBatchAcceptanceReportUrlWorkflowActionPlan(
missingInputReportUrlWorkflow,
);
assert.equal(missingInputReportUrlWorkflow.ready, false);
assert.equal(missingInputReportUrlWorkflow.fetched, false);
assert.deepEqual(missingInputReportUrlWorkflow.missing.slice(0, 2), ["report-url", "fetch"]);
assert.match(
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel(
missingInputReportUrlWorkflow,
).statusLine,
/^Blocked: report-url, fetch/,
);
assert.equal(missingInputReportUrlActionPlan.actionCount, 3);
assert.equal(missingInputReportUrlActionPlan.commandCount, 1);
assert.equal(missingInputReportUrlActionPlan.nextActionId, "provide-report-url");
assert.equal(
missingInputReportUrlActionPlan.nextCommand,
"wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
);
assert.deepEqual(
missingInputReportUrlActionPlan.actions.slice(0, 2).map(({ id, kind, command }) => [id, kind, command]),
[
["provide-report-url", "input", null],
["provide-fetch", "input", null],
],
);
const httpFailureReportUrlWorkflow = await loadProjectBatchAcceptanceReportUrlWorkflow({
reportUrl: "/missing-batch-report.json",
fetchRef: async () => ({
ok: false,
status: 404,
text: async () => "",
}),
});
const httpFailureReportUrlActionPlan = createProjectBatchAcceptanceReportUrlWorkflowActionPlan(
httpFailureReportUrlWorkflow,
);
assert.equal(httpFailureReportUrlWorkflow.ready, false);
assert.equal(httpFailureReportUrlWorkflow.fetched, false);
assert.equal(httpFailureReportUrlWorkflow.httpStatus, 404);
assert.match(httpFailureReportUrlWorkflow.fetchError, /404/);
assert.equal(httpFailureReportUrlWorkflow.missing[0], "report-fetch");
assert.match(
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel(
httpFailureReportUrlWorkflow,
).statusLine,
/^Blocked: report-fetch/,
);
assert.equal(httpFailureReportUrlActionPlan.nextActionId, "verify-report-url-fetch");
assert.equal(httpFailureReportUrlActionPlan.commands.length, 1);
const thrownFetchReportUrlWorkflow = await loadProjectBatchAcceptanceReportUrlWorkflow({
reportUrl: "/throws-batch-report.json",
fetchRef: async () => {
throw new Error("batch report network unavailable");
},
});
assert.equal(thrownFetchReportUrlWorkflow.ready, false);
assert.equal(thrownFetchReportUrlWorkflow.fetched, false);
assert.equal(thrownFetchReportUrlWorkflow.httpStatus, null);
assert.equal(thrownFetchReportUrlWorkflow.fetchError, "batch report network unavailable");
assert.equal(thrownFetchReportUrlWorkflow.missing[0], "report-fetch");
assert.equal(
createProjectBatchAcceptanceReportUrlWorkflowActionPlan(
thrownFetchReportUrlWorkflow,
).nextActionId,
"verify-report-url-fetch",
);
const capabilityOnlyWorkflow = createProjectBatchAcceptanceWorkflow({
capabilities: [
{
id: "callable-helper",
type: "api",
label: "Callable helper",
},
],
});
assert.deepEqual(capabilityOnlyWorkflow.missing, ["project-batch-acceptance"]);
assert.equal(
createProjectBatchAcceptanceActionPlan(capabilityOnlyWorkflow).nextCommand,
"wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
);
console.log("project_batch_acceptance_workflow_node_smoke=ok");

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
ARTIFACT_PATH="${1:-$ROOT_DIR/build/project-batch-acceptance.json}"
node "$ROOT_DIR/tests/sdk/node/verify_project_batch_acceptance_workflow.mjs"
node "$ROOT_DIR/tests/sdk/node/write_project_batch_acceptance_artifact.mjs" "$ARTIFACT_PATH"
"$ROOT_DIR/tests/sdk/node/verify_project_batch_acceptance_artifact.sh" "$ARTIFACT_PATH"

View File

@@ -20,7 +20,7 @@ const manifest = createProjectReleaseGateManifest();
assert.equal(manifest.apiName, "project-release-gate-manifest"); assert.equal(manifest.apiName, "project-release-gate-manifest");
assert.equal(manifest.manifestVersion, 1); assert.equal(manifest.manifestVersion, 1);
assert.equal(manifest.gateCount, 11); assert.equal(manifest.gateCount, 12);
assert.deepEqual(manifest.gateIds, [ assert.deepEqual(manifest.gateIds, [
"diff-check", "diff-check",
"vendor-sync", "vendor-sync",
@@ -30,6 +30,7 @@ assert.deepEqual(manifest.gateIds, [
"ini-panel-browser", "ini-panel-browser",
"opfs-session-browser", "opfs-session-browser",
"release-artifact-url-browser", "release-artifact-url-browser",
"project-batch-acceptance",
"ui-node-smokes", "ui-node-smokes",
"host-smokes", "host-smokes",
"project-release-gate", "project-release-gate",
@@ -45,6 +46,7 @@ assert.deepEqual(
"browser_ini_shell_integration_workflow_smoke=ok", "browser_ini_shell_integration_workflow_smoke=ok",
"browser_opfs_session_workflow_smoke=ok", "browser_opfs_session_workflow_smoke=ok",
"browser_release_artifact_url_workflow_smoke=ok", "browser_release_artifact_url_workflow_smoke=ok",
"project_batch_acceptance_workflow_node_smoke=ok",
"ui_node_smokes=ok", "ui_node_smokes=ok",
"host_wasm_opfs_browser_smokes=ok", "host_wasm_opfs_browser_smokes=ok",
"project_release_gate=ok", "project_release_gate=ok",
@@ -58,6 +60,10 @@ assert.equal(
manifest.gates.find(({ id }) => id === "opfs-session-browser")?.command, manifest.gates.find(({ id }) => id === "opfs-session-browser")?.command,
"SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_opfs_session_workflow_browser.sh", "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_opfs_session_workflow_browser.sh",
); );
assert.equal(
manifest.gates.find(({ id }) => id === "project-batch-acceptance")?.command,
"wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
);
const partialMatrix = createProjectReleaseGateResultMatrix({ const partialMatrix = createProjectReleaseGateResultMatrix({
gateResults: { gateResults: {
@@ -72,15 +78,16 @@ assert.equal(partialMatrix.apiName, "project-release-gate-result-matrix");
assert.equal(partialMatrix.matrixVersion, 1); assert.equal(partialMatrix.matrixVersion, 1);
assert.equal(partialMatrix.phase, "waiting"); assert.equal(partialMatrix.phase, "waiting");
assert.equal(partialMatrix.ready, false); assert.equal(partialMatrix.ready, false);
assert.equal(partialMatrix.gateCount, 11); assert.equal(partialMatrix.gateCount, 12);
assert.equal(partialMatrix.passedCount, 3); assert.equal(partialMatrix.passedCount, 3);
assert.equal(partialMatrix.unknownCount, 8); assert.equal(partialMatrix.unknownCount, 9);
assert.deepEqual(partialMatrix.missingGateIds, [ assert.deepEqual(partialMatrix.missingGateIds, [
"standalone-cnc-semantics", "standalone-cnc-semantics",
"interp-wasm", "interp-wasm",
"sim-config-inventory", "sim-config-inventory",
"ini-panel-browser", "ini-panel-browser",
"opfs-session-browser", "opfs-session-browser",
"project-batch-acceptance",
"ui-node-smokes", "ui-node-smokes",
"host-smokes", "host-smokes",
"project-release-gate", "project-release-gate",
@@ -107,9 +114,9 @@ assert.equal(partialExecutionManifest.apiName, "project-release-gate-execution-m
assert.equal(partialExecutionManifest.manifestVersion, 1); assert.equal(partialExecutionManifest.manifestVersion, 1);
assert.equal(partialExecutionManifest.phase, "waiting"); assert.equal(partialExecutionManifest.phase, "waiting");
assert.equal(partialExecutionManifest.ready, false); assert.equal(partialExecutionManifest.ready, false);
assert.equal(partialExecutionManifest.gateCount, 11); assert.equal(partialExecutionManifest.gateCount, 12);
assert.equal(partialExecutionManifest.passedCount, 3); assert.equal(partialExecutionManifest.passedCount, 3);
assert.equal(partialExecutionManifest.unknownCount, 8); assert.equal(partialExecutionManifest.unknownCount, 9);
assert.deepEqual(partialExecutionManifest.missingGateIds, partialMatrix.missingGateIds); assert.deepEqual(partialExecutionManifest.missingGateIds, partialMatrix.missingGateIds);
assert.deepEqual( assert.deepEqual(
partialExecutionManifest.rows.filter(({ passed }) => passed).map(({ id, evidence }) => [id, evidence]), partialExecutionManifest.rows.filter(({ passed }) => passed).map(({ id, evidence }) => [id, evidence]),
@@ -132,25 +139,25 @@ assert.equal(partialExecutionSummary.apiName, "project-release-gate-execution-su
assert.equal(partialExecutionSummary.viewModelVersion, 1); assert.equal(partialExecutionSummary.viewModelVersion, 1);
assert.equal(partialExecutionSummary.phase, "waiting"); assert.equal(partialExecutionSummary.phase, "waiting");
assert.equal(partialExecutionSummary.ready, false); assert.equal(partialExecutionSummary.ready, false);
assert.equal(partialExecutionSummary.statusLine, "Waiting: standalone-cnc-semantics, interp-wasm, sim-config-inventory, ini-panel-browser, opfs-session-browser, ui-node-smokes, host-smokes, project-release-gate"); assert.equal(partialExecutionSummary.statusLine, "Waiting: standalone-cnc-semantics, interp-wasm, sim-config-inventory, ini-panel-browser, opfs-session-browser, project-batch-acceptance, ui-node-smokes, host-smokes, project-release-gate");
assert.equal(partialExecutionSummary.gateCount, 11); assert.equal(partialExecutionSummary.gateCount, 12);
assert.equal(partialExecutionSummary.passedCount, 3); assert.equal(partialExecutionSummary.passedCount, 3);
assert.equal(partialExecutionSummary.unknownCount, 8); assert.equal(partialExecutionSummary.unknownCount, 9);
assert.equal(partialExecutionSummary.nextGateId, "standalone-cnc-semantics"); assert.equal(partialExecutionSummary.nextGateId, "standalone-cnc-semantics");
assert.deepEqual(partialExecutionSummary.evidenceCounts, { assert.deepEqual(partialExecutionSummary.evidenceCounts, {
"explicit-result": 1, "explicit-result": 1,
"expected-output": 2, "expected-output": 2,
missing: 8, missing: 9,
}); });
assert.deepEqual( assert.deepEqual(
partialExecutionSummary.rows.map(({ id, value }) => [id, value]), partialExecutionSummary.rows.map(({ id, value }) => [id, value]),
[ [
["gate-results", "3/11 passed"], ["gate-results", "3/12 passed"],
["unknown-gates", "8"], ["unknown-gates", "9"],
["next-gate", "standalone-cnc-semantics"], ["next-gate", "standalone-cnc-semantics"],
["expected-output-evidence", "2"], ["expected-output-evidence", "2"],
["explicit-result-evidence", "1"], ["explicit-result-evidence", "1"],
["missing", "standalone-cnc-semantics, interp-wasm, sim-config-inventory, ini-panel-browser, opfs-session-browser, ui-node-smokes, host-smokes, project-release-gate"], ["missing", "standalone-cnc-semantics, interp-wasm, sim-config-inventory, ini-panel-browser, opfs-session-browser, project-batch-acceptance, ui-node-smokes, host-smokes, project-release-gate"],
], ],
); );
assert.equal(partialExecutionSummary.gateRows.length, manifest.gateCount); assert.equal(partialExecutionSummary.gateRows.length, manifest.gateCount);
@@ -164,9 +171,9 @@ assert.equal(partialActionPlan.apiName, "project-release-gate-action-plan");
assert.equal(partialActionPlan.planVersion, 1); assert.equal(partialActionPlan.planVersion, 1);
assert.equal(partialActionPlan.phase, "waiting"); assert.equal(partialActionPlan.phase, "waiting");
assert.equal(partialActionPlan.ready, false); assert.equal(partialActionPlan.ready, false);
assert.equal(partialActionPlan.gateCount, 11); assert.equal(partialActionPlan.gateCount, 12);
assert.equal(partialActionPlan.completedCount, 3); assert.equal(partialActionPlan.completedCount, 3);
assert.equal(partialActionPlan.pendingCount, 8); assert.equal(partialActionPlan.pendingCount, 9);
assert.deepEqual(partialActionPlan.completedGateIds, [ assert.deepEqual(partialActionPlan.completedGateIds, [
"diff-check", "diff-check",
"vendor-sync", "vendor-sync",
@@ -178,13 +185,14 @@ assert.deepEqual(partialActionPlan.pendingGateIds, [
"sim-config-inventory", "sim-config-inventory",
"ini-panel-browser", "ini-panel-browser",
"opfs-session-browser", "opfs-session-browser",
"project-batch-acceptance",
"ui-node-smokes", "ui-node-smokes",
"host-smokes", "host-smokes",
"project-release-gate", "project-release-gate",
]); ]);
assert.equal(partialActionPlan.nextGateId, "standalone-cnc-semantics"); assert.equal(partialActionPlan.nextGateId, "standalone-cnc-semantics");
assert.equal(partialActionPlan.nextCommand, "wasm-port/tools/verify_no_standalone_cnc_semantics.sh"); assert.equal(partialActionPlan.nextCommand, "wasm-port/tools/verify_no_standalone_cnc_semantics.sh");
assert.equal(partialActionPlan.commands.length, 8); assert.equal(partialActionPlan.commands.length, 9);
assert.equal(partialActionPlan.commands[0].step, 1); assert.equal(partialActionPlan.commands[0].step, 1);
assert.equal(partialActionPlan.commands[0].gateId, "standalone-cnc-semantics"); assert.equal(partialActionPlan.commands[0].gateId, "standalone-cnc-semantics");
assert.equal(partialActionPlan.rows[0].id, "standalone-cnc-semantics"); assert.equal(partialActionPlan.rows[0].id, "standalone-cnc-semantics");
@@ -200,7 +208,7 @@ assert.equal(report.gateExecutionManifest.ready, true);
assert.equal(report.gateExecutionManifest.passedCount, manifest.gateCount); assert.equal(report.gateExecutionManifest.passedCount, manifest.gateCount);
assert.equal(report.gateExecutionSummaryViewModel.apiName, "project-release-gate-execution-summary-view-model"); assert.equal(report.gateExecutionSummaryViewModel.apiName, "project-release-gate-execution-summary-view-model");
assert.equal(report.gateExecutionSummaryViewModel.statusLine, "Ready: All release gate evidence present"); assert.equal(report.gateExecutionSummaryViewModel.statusLine, "Ready: All release gate evidence present");
assert.equal(report.gateExecutionSummaryViewModel.rows[0].value, "11/11 passed"); assert.equal(report.gateExecutionSummaryViewModel.rows[0].value, "12/12 passed");
assert.equal(report.gateExecutionSummaryViewModel.nextGateId, null); assert.equal(report.gateExecutionSummaryViewModel.nextGateId, null);
assert.equal(report.gateResultMatrix.ready, true); assert.equal(report.gateResultMatrix.ready, true);
assert.equal(report.gateResultMatrix.passedCount, manifest.gateCount); assert.equal(report.gateResultMatrix.passedCount, manifest.gateCount);
@@ -223,7 +231,7 @@ assert.deepEqual(createProjectReleaseReadinessSummaryViewModel(report), {
{ {
id: "gate-results", id: "gate-results",
label: "Release gates", label: "Release gates",
value: "11/11 passed", value: "12/12 passed",
}, },
{ {
id: "unknown-gates", id: "unknown-gates",
@@ -289,7 +297,7 @@ assert.deepEqual(
artifactValidationSummary.rows.map(({ id, value }) => [id, value]), artifactValidationSummary.rows.map(({ id, value }) => [id, value]),
[ [
["artifact", "project-release-readiness-report"], ["artifact", "project-release-readiness-report"],
["gate-count", "11/11"], ["gate-count", "12/12"],
["gate-manifest", "ready"], ["gate-manifest", "ready"],
["gate-execution-manifest", "ready"], ["gate-execution-manifest", "ready"],
["gate-execution-summary", "ready"], ["gate-execution-summary", "ready"],

View File

@@ -25,8 +25,12 @@ import {
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
createLinuxCncIniSdk, createLinuxCncIniSdk,
createLinuxCncInterpSdk, createLinuxCncInterpSdk,
@@ -34,6 +38,18 @@ import {
createMachineSessionPersistenceDisplayViewModel, createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState, createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary, createMachineSessionPersistenceSummary,
createProjectBatchAcceptanceActionPlan,
createProjectBatchAcceptanceCapabilityMatrix,
createProjectBatchAcceptanceChecklist,
createProjectBatchAcceptanceReport,
createProjectBatchAcceptanceReportJsonWorkflow,
createProjectBatchAcceptanceReportUrlWorkflowActionPlan,
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel,
createProjectBatchAcceptanceReportValidationActionPlan,
createProjectBatchAcceptanceReportValidationSummaryViewModel,
createProjectBatchAcceptanceReportValidation,
createProjectBatchAcceptanceSummaryViewModel,
createProjectBatchAcceptanceWorkflow,
createProjectReleaseGateActionPlan, createProjectReleaseGateActionPlan,
createProjectReleaseGateExecutionManifest, createProjectReleaseGateExecutionManifest,
createProjectReleaseGateExecutionSummaryViewModel, createProjectReleaseGateExecutionSummaryViewModel,
@@ -60,6 +76,30 @@ import {
isSupportedIniPanelLaunchApiManifest, isSupportedIniPanelLaunchApiManifest,
isSupportedIniPanelShellIntegrationManifest, isSupportedIniPanelShellIntegrationManifest,
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
loadProjectBatchAcceptanceReportUrlWorkflow,
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
loadProjectReleaseReadinessArtifactUrlWorkflow, loadProjectReleaseReadinessArtifactUrlWorkflow,
loadMachineSessionFromOpfs, loadMachineSessionFromOpfs,
loadMachineSessionSnapshot, loadMachineSessionSnapshot,
@@ -97,6 +137,30 @@ const trackerText = readFileSync(resolve(root, "../PROJECT_COMPLETION_TRACKER.md
const requiredExports = [ const requiredExports = [
["createLinuxCncIniSdk", createLinuxCncIniSdk], ["createLinuxCncIniSdk", createLinuxCncIniSdk],
["createLinuxCncInterpSdk", createLinuxCncInterpSdk], ["createLinuxCncInterpSdk", createLinuxCncInterpSdk],
["createProjectBatchAcceptanceActionPlan", createProjectBatchAcceptanceActionPlan],
["createProjectBatchAcceptanceCapabilityMatrix", createProjectBatchAcceptanceCapabilityMatrix],
["createProjectBatchAcceptanceChecklist", createProjectBatchAcceptanceChecklist],
["createProjectBatchAcceptanceReport", createProjectBatchAcceptanceReport],
["createProjectBatchAcceptanceReportJsonWorkflow", createProjectBatchAcceptanceReportJsonWorkflow],
[
"createProjectBatchAcceptanceReportUrlWorkflowActionPlan",
createProjectBatchAcceptanceReportUrlWorkflowActionPlan,
],
[
"createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel",
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel,
],
[
"createProjectBatchAcceptanceReportValidationActionPlan",
createProjectBatchAcceptanceReportValidationActionPlan,
],
[
"createProjectBatchAcceptanceReportValidationSummaryViewModel",
createProjectBatchAcceptanceReportValidationSummaryViewModel,
],
["createProjectBatchAcceptanceReportValidation", createProjectBatchAcceptanceReportValidation],
["createProjectBatchAcceptanceSummaryViewModel", createProjectBatchAcceptanceSummaryViewModel],
["createProjectBatchAcceptanceWorkflow", createProjectBatchAcceptanceWorkflow],
["createProjectReleaseGateActionPlan", createProjectReleaseGateActionPlan], ["createProjectReleaseGateActionPlan", createProjectReleaseGateActionPlan],
["createProjectReleaseGateExecutionManifest", createProjectReleaseGateExecutionManifest], ["createProjectReleaseGateExecutionManifest", createProjectReleaseGateExecutionManifest],
["createProjectReleaseGateExecutionSummaryViewModel", createProjectReleaseGateExecutionSummaryViewModel], ["createProjectReleaseGateExecutionSummaryViewModel", createProjectReleaseGateExecutionSummaryViewModel],
@@ -127,10 +191,103 @@ const requiredExports = [
"validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson", "validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson",
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson, validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson,
], ],
[
"runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow",
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
],
[
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
],
[
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
],
[
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
],
[
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
],
[
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
],
[
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
],
[
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
],
[
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
],
[ [
"loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl", "loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl",
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
], ],
["loadProjectBatchAcceptanceReportUrlWorkflow", loadProjectBatchAcceptanceReportUrlWorkflow],
["loadProjectReleaseReadinessArtifactUrlWorkflow", loadProjectReleaseReadinessArtifactUrlWorkflow], ["loadProjectReleaseReadinessArtifactUrlWorkflow", loadProjectReleaseReadinessArtifactUrlWorkflow],
["planIniFileContextStaging", planIniFileContextStaging], ["planIniFileContextStaging", planIniFileContextStaging],
["planSimConfigStaging", planSimConfigStaging], ["planSimConfigStaging", planSimConfigStaging],
@@ -194,10 +351,26 @@ const requiredExports = [
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel", "createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
], ],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
],
[ [
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel", "createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
], ],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
],
[
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
],
[ [
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel", "createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel",
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel,
@@ -246,6 +419,106 @@ assert.equal(normalizeOpfsPath("linuxcnc/machines/sdk-mill/tool.tbl"), "linuxcnc
assert.equal(gcodeFilenameFromProgramPath("linuxcnc/gcode/demo.ngc"), "demo.ngc"); assert.equal(gcodeFilenameFromProgramPath("linuxcnc/gcode/demo.ngc"), "demo.ngc");
const releaseReadinessWaiting = createProjectReleaseReadinessReport(); const releaseReadinessWaiting = createProjectReleaseReadinessReport();
const batchCapabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({
capabilities: [
{
id: "sdk-surface-api",
type: "api",
label: "SDK surface API",
},
],
});
assert.equal(batchCapabilityMatrix.ready, true);
assert.equal(batchCapabilityMatrix.countsByType.api, 1);
const batchAcceptanceWorkflow = createProjectBatchAcceptanceWorkflow({
batchId: "sdk-surface-batch",
capabilities: [
{
id: "sdk-surface-api",
type: "api",
label: "SDK surface API",
},
],
observedOutputs: ["project_batch_acceptance_workflow_node_smoke=ok"],
});
assert.equal(batchAcceptanceWorkflow.ready, true);
assert.equal(batchAcceptanceWorkflow.capabilityTypes[0], "api");
assert.equal(
createProjectBatchAcceptanceSummaryViewModel(batchAcceptanceWorkflow).statusLine,
"Ready: Batch acceptance evidence complete",
);
assert.equal(
createProjectBatchAcceptanceActionPlan(batchAcceptanceWorkflow).shellScript,
"# Project batch acceptance workflow is already ready.\n",
);
assert.equal(
createProjectBatchAcceptanceChecklist({ workflow: batchAcceptanceWorkflow }).rows[0].value,
"pass: api",
);
assert.equal(
createProjectBatchAcceptanceReport({
batchId: "sdk-surface-batch",
capabilities: batchAcceptanceWorkflow.capabilities,
observedOutputs: ["project_batch_acceptance_workflow_node_smoke=ok"],
}).rows.find(({ id }) => id === "checklist")?.value,
"3/3 passed",
);
const batchAcceptanceReport = createProjectBatchAcceptanceReport({
batchId: "sdk-surface-batch",
capabilities: batchAcceptanceWorkflow.capabilities,
observedOutputs: ["project_batch_acceptance_workflow_node_smoke=ok"],
});
assert.equal(createProjectBatchAcceptanceReportValidation(batchAcceptanceReport).ready, true);
assert.equal(
createProjectBatchAcceptanceReportValidationSummaryViewModel(
createProjectBatchAcceptanceReportValidation(batchAcceptanceReport),
).statusLine,
"Ready: Batch acceptance report evidence complete",
);
assert.equal(
createProjectBatchAcceptanceReportValidationActionPlan(
createProjectBatchAcceptanceReportValidation(batchAcceptanceReport),
).shellScript,
"# Project batch acceptance report validation is already ready.\n",
);
assert.equal(
createProjectBatchAcceptanceReportJsonWorkflow({
reportJson: JSON.stringify(batchAcceptanceReport),
}).ready,
true,
);
const batchAcceptanceReportUrlWorkflow = await loadProjectBatchAcceptanceReportUrlWorkflow({
reportUrl: "/project-batch-acceptance.json",
fetchRef: async () => ({
ok: true,
status: 200,
text: async () => JSON.stringify(batchAcceptanceReport),
}),
});
assert.equal(batchAcceptanceReportUrlWorkflow.ready, true);
assert.equal(
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel(
batchAcceptanceReportUrlWorkflow,
).statusLine,
"Ready: Batch report URL workflow complete",
);
assert.equal(
createProjectBatchAcceptanceReportUrlWorkflowActionPlan(
batchAcceptanceReportUrlWorkflow,
).shellScript,
"# Project batch acceptance report URL workflow is already ready.\n",
);
assert.equal(
(await loadProjectBatchAcceptanceReportUrlWorkflow({
reportUrl: "/missing-project-batch-acceptance.json",
fetchRef: async () => ({ ok: false, status: 404, text: async () => "" }),
})).missing[0],
"report-fetch",
);
assert.equal(
createProjectBatchAcceptanceActionPlan(createProjectBatchAcceptanceWorkflow()).nextCommand,
"wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
);
assert.equal(releaseReadinessWaiting.apiName, "project-release-readiness-report"); assert.equal(releaseReadinessWaiting.apiName, "project-release-readiness-report");
assert.equal(releaseReadinessWaiting.ready, false); assert.equal(releaseReadinessWaiting.ready, false);
assert.deepEqual(releaseReadinessWaiting.missing, ["project-release-gate"]); assert.deepEqual(releaseReadinessWaiting.missing, ["project-release-gate"]);
@@ -446,6 +719,44 @@ assert.equal(
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(JSON.stringify(releaseReadinessArtifact)).ready, validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(JSON.stringify(releaseReadinessArtifact)).ready,
true, true,
); );
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(JSON.stringify(releaseReadinessArtifact)),
).shellScript,
"# Project release readiness artifact validation is already ready.\n",
);
assert.equal(
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson: JSON.stringify(releaseReadinessArtifact),
}).statusLine,
"Ready: Artifact JSON workflow complete",
);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson: JSON.stringify(releaseReadinessArtifact),
}),
).statusLine,
"Ready: Artifact JSON workflow complete",
);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan(
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson: JSON.stringify(releaseReadinessArtifact),
}),
).nextCommand,
null,
);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson: JSON.stringify(releaseReadinessArtifact),
}),
),
).dataset.handoffScope,
"workflow-overview-release-readiness-artifact-json-workflow",
);
const releaseReadinessArtifactUrlWorkflow = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({ const releaseReadinessArtifactUrlWorkflow = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({
artifactUrl: "/project-release-readiness.json", artifactUrl: "/project-release-readiness.json",
fetchRef: async () => ({ fetchRef: async () => ({
@@ -465,6 +776,12 @@ assert.equal(
).statusLine, ).statusLine,
"Ready: Artifact URL workflow complete", "Ready: Artifact URL workflow complete",
); );
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(
releaseReadinessArtifactUrlWorkflow,
).shellScript,
"# Project release readiness artifact URL workflow is already ready.\n",
);
assert.equal( assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState( createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel( createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(

View File

@@ -6,3 +6,4 @@ ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
node "$ROOT_DIR/tests/sdk/node/verify_sdk_surface.mjs" node "$ROOT_DIR/tests/sdk/node/verify_sdk_surface.mjs"
"$ROOT_DIR/tests/sdk/node/verify_project_release_gate_manifest.sh" "$ROOT_DIR/tests/sdk/node/verify_project_release_gate_manifest.sh"
"$ROOT_DIR/tests/sdk/node/verify_project_release_artifact_url_workflow.sh" "$ROOT_DIR/tests/sdk/node/verify_project_release_artifact_url_workflow.sh"
"$ROOT_DIR/tests/sdk/node/verify_project_batch_acceptance_workflow.sh"

View File

@@ -0,0 +1,36 @@
import { mkdirSync, renameSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { createProjectBatchAcceptanceReport } from "../../../runtime/sdk/src/index.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "../../..");
const outputPath = process.argv[2] ?? resolve(root, "build/project-batch-acceptance.json");
const report = createProjectBatchAcceptanceReport({
batchId: "project-batch-acceptance-artifact",
capabilities: [
{
id: "project-batch-acceptance-report-artifact",
type: "workflow",
label: "Project batch acceptance report artifact",
evidence: "project_batch_acceptance_artifact_node_smoke=ok",
command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
},
{
id: "project-batch-acceptance-workflow-gate",
type: "gate",
label: "Project batch acceptance workflow gate",
evidence: "project_batch_acceptance_workflow_node_smoke=ok",
command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh",
},
],
observedOutputs: ["project_batch_acceptance_workflow_node_smoke=ok"],
});
mkdirSync(dirname(outputPath), { recursive: true });
writeFileSync(`${outputPath}.tmp`, `${JSON.stringify(report, null, 2)}\n`);
renameSync(`${outputPath}.tmp`, outputPath);
console.log(`project_batch_acceptance_artifact=${outputPath}`);

View File

@@ -163,9 +163,34 @@ const requiredShellExports = [
"renderIniPanelShellWorkflowOverviewEmbeddingMountState", "renderIniPanelShellWorkflowOverviewEmbeddingMountState",
"mountIniPanelShellWorkflowOverviewEmbeddingMountState", "mountIniPanelShellWorkflowOverviewEmbeddingMountState",
"validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson", "validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson",
"runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness",
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness",
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl", "loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel", "createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel", "createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness",
"renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel", "createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState", "createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState",
"createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract", "createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract",

View File

@@ -82,9 +82,36 @@ assert.deepEqual(manifest, {
"getWorkflowOverviewContract", "getWorkflowOverviewContract",
"getWorkflowOverviewReadiness", "getWorkflowOverviewReadiness",
"mountWorkflowOverviewEmbedding", "mountWorkflowOverviewEmbedding",
"runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"loadWorkflowOverviewReleaseReadinessArtifactUrl", "loadWorkflowOverviewReleaseReadinessArtifactUrl",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel", "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel", "getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"getWorkflowOverviewEmbeddingReport", "getWorkflowOverviewEmbeddingReport",
"getWorkflowOverviewEmbeddingDisplayViewModel", "getWorkflowOverviewEmbeddingDisplayViewModel",
"getWorkflowOverviewEmbeddingRenderState", "getWorkflowOverviewEmbeddingRenderState",
@@ -244,9 +271,36 @@ assert.match(launchText, /\bmountShellSessionHandoffWorkflow\b/);
assert.match(launchText, /\bgetWorkflowOverviewContract\b/); assert.match(launchText, /\bgetWorkflowOverviewContract\b/);
assert.match(launchText, /\bgetWorkflowOverviewReadiness\b/); assert.match(launchText, /\bgetWorkflowOverviewReadiness\b/);
assert.match(launchText, /\bmountWorkflowOverviewEmbedding\b/); assert.match(launchText, /\bmountWorkflowOverviewEmbedding\b/);
assert.match(launchText, /\brunWorkflowOverviewReleaseReadinessArtifactJsonWorkflow\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness\b/);
assert.match(launchText, /\brenderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState\b/);
assert.match(launchText, /\bmountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState\b/);
assert.match(launchText, /\bloadWorkflowOverviewReleaseReadinessArtifactUrl\b/); assert.match(launchText, /\bloadWorkflowOverviewReleaseReadinessArtifactUrl\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel\b/); assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness\b/);
assert.match(launchText, /\brenderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState\b/);
assert.match(launchText, /\bmountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel\b/); assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactValidationActionPlan\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness\b/);
assert.match(launchText, /\brenderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState\b/);
assert.match(launchText, /\bmountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract\b/);
assert.match(launchText, /\bgetWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness\b/);
assert.match(launchText, /\brenderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState\b/);
assert.match(launchText, /\bmountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState\b/);
assert.match(launchText, /\bgetWorkflowOverviewEmbeddingReport\b/); assert.match(launchText, /\bgetWorkflowOverviewEmbeddingReport\b/);
assert.match(launchText, /\bgetWorkflowOverviewEmbeddingDisplayViewModel\b/); assert.match(launchText, /\bgetWorkflowOverviewEmbeddingDisplayViewModel\b/);
assert.match(launchText, /\bgetWorkflowOverviewEmbeddingRenderState\b/); assert.match(launchText, /\bgetWorkflowOverviewEmbeddingRenderState\b/);

View File

@@ -52,9 +52,36 @@ import {
renderIniPanelShellWorkflowOverviewEmbeddingMountState, renderIniPanelShellWorkflowOverviewEmbeddingMountState,
mountIniPanelShellWorkflowOverviewEmbeddingMountState, mountIniPanelShellWorkflowOverviewEmbeddingMountState,
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson, validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson,
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract,
@@ -189,7 +216,7 @@ assert.deepEqual(readiness, {
counts: { counts: {
pages: 3, pages: 3,
launcherLinks: 3, launcherLinks: 3,
launchMethods: 61, launchMethods: 88,
controlPageMethods: 11, controlPageMethods: 11,
persistenceCapabilities: 3, persistenceCapabilities: 3,
}, },
@@ -252,7 +279,7 @@ assert.deepEqual(handoffSummary, {
counts: { counts: {
pages: 3, pages: 3,
launcherLinks: 3, launcherLinks: 3,
launchMethods: 61, launchMethods: 88,
controlPageMethods: 11, controlPageMethods: 11,
persistenceCapabilities: 3, persistenceCapabilities: 3,
}, },
@@ -791,9 +818,36 @@ assert.deepEqual(createIniPanelShellWorkflowOverviewContract(), {
"getWorkflowOverviewApiSurfaceInventory", "getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary", "getWorkflowOverviewPersistenceSummary",
"validateWorkflowOverviewReleaseReadinessArtifactJson", "validateWorkflowOverviewReleaseReadinessArtifactJson",
"runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"loadWorkflowOverviewReleaseReadinessArtifactUrl", "loadWorkflowOverviewReleaseReadinessArtifactUrl",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel", "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel", "getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel", "getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel",
"getWorkflowOverviewReleaseReadinessArtifactRenderState", "getWorkflowOverviewReleaseReadinessArtifactRenderState",
"getWorkflowOverviewReleaseReadinessArtifactDomContract", "getWorkflowOverviewReleaseReadinessArtifactDomContract",
@@ -838,9 +892,36 @@ assert.equal(typeof createIniPanelShellWorkflowOverviewEmbeddingMountDomReadines
assert.equal(typeof renderIniPanelShellWorkflowOverviewEmbeddingMountState, "function"); assert.equal(typeof renderIniPanelShellWorkflowOverviewEmbeddingMountState, "function");
assert.equal(typeof mountIniPanelShellWorkflowOverviewEmbeddingMountState, "function"); assert.equal(typeof mountIniPanelShellWorkflowOverviewEmbeddingMountState, "function");
assert.equal(typeof validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson, "function"); assert.equal(typeof validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson, "function");
assert.equal(typeof runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness, "function");
assert.equal(typeof renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState, "function");
assert.equal(typeof mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState, "function");
assert.equal(typeof loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, "function"); assert.equal(typeof loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, "function"); assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness, "function");
assert.equal(typeof renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState, "function");
assert.equal(typeof mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, "function"); assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness, "function");
assert.equal(typeof renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState, "function");
assert.equal(typeof mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness, "function");
assert.equal(typeof renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState, "function");
assert.equal(typeof mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, "function"); assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState, "function"); assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState, "function");
assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, "function"); assert.equal(typeof createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, "function");
@@ -872,9 +953,36 @@ assert.deepEqual(
"getWorkflowOverviewSummary", "getWorkflowOverviewSummary",
"getWorkflowOverviewPersistenceSummary", "getWorkflowOverviewPersistenceSummary",
"validateWorkflowOverviewReleaseReadinessArtifactJson", "validateWorkflowOverviewReleaseReadinessArtifactJson",
"runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"loadWorkflowOverviewReleaseReadinessArtifactUrl", "loadWorkflowOverviewReleaseReadinessArtifactUrl",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel", "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel", "getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel", "getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel",
"getWorkflowOverviewReleaseReadinessArtifactRenderState", "getWorkflowOverviewReleaseReadinessArtifactRenderState",
"getWorkflowOverviewReleaseReadinessArtifactDomContract", "getWorkflowOverviewReleaseReadinessArtifactDomContract",
@@ -1300,7 +1408,7 @@ assert.deepEqual(createIniPanelShellIntegrationReadiness(blockedManifest), {
counts: { counts: {
pages: 3, pages: 3,
launcherLinks: 3, launcherLinks: 3,
launchMethods: 61, launchMethods: 88,
controlPageMethods: 11, controlPageMethods: 11,
persistenceCapabilities: 3, persistenceCapabilities: 3,
}, },

View File

@@ -57,9 +57,36 @@ import {
renderIniPanelShellWorkflowOverviewEmbeddingMountState, renderIniPanelShellWorkflowOverviewEmbeddingMountState,
mountIniPanelShellWorkflowOverviewEmbeddingMountState, mountIniPanelShellWorkflowOverviewEmbeddingMountState,
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson, validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson,
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract,
@@ -690,9 +717,36 @@ assert.deepEqual(shellViewModel.shellWorkflowOverviewContract, {
"getWorkflowOverviewApiSurfaceInventory", "getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary", "getWorkflowOverviewPersistenceSummary",
"validateWorkflowOverviewReleaseReadinessArtifactJson", "validateWorkflowOverviewReleaseReadinessArtifactJson",
"runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"loadWorkflowOverviewReleaseReadinessArtifactUrl", "loadWorkflowOverviewReleaseReadinessArtifactUrl",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel", "getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel", "getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel", "getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel",
"getWorkflowOverviewReleaseReadinessArtifactRenderState", "getWorkflowOverviewReleaseReadinessArtifactRenderState",
"getWorkflowOverviewReleaseReadinessArtifactDomContract", "getWorkflowOverviewReleaseReadinessArtifactDomContract",
@@ -1300,13 +1354,104 @@ const releaseReadinessArtifactJson = JSON.stringify(createProjectReleaseReadines
const releaseArtifactValidation = validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson( const releaseArtifactValidation = validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(
releaseReadinessArtifactJson, releaseReadinessArtifactJson,
); );
const releaseArtifactJsonWorkflow = runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson: releaseReadinessArtifactJson,
});
assert.equal(
releaseArtifactJsonWorkflow.apiName,
"ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow",
);
assert.equal(releaseArtifactJsonWorkflow.ready, true);
assert.equal(releaseArtifactJsonWorkflow.parsed, true);
assert.equal(releaseArtifactJsonWorkflow.statusLine, "Ready: Artifact JSON workflow complete");
assert.equal(releaseArtifactJsonWorkflow.actionPlan.nextCommand, null);
assert.equal(releaseArtifactJsonWorkflow.gateExecutionSummaryViewModel.statusLine, "Ready: All release gate evidence present");
const releaseArtifactJsonWorkflowSummary =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(
releaseArtifactJsonWorkflow,
);
const releaseArtifactJsonWorkflowActionPlan =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan(
releaseArtifactJsonWorkflow,
);
const releaseArtifactJsonWorkflowRenderState =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(
releaseArtifactJsonWorkflowSummary,
);
assert.equal(
releaseArtifactJsonWorkflowSummary.statusLine,
"Ready: Artifact JSON workflow complete",
);
assert.equal(
releaseArtifactJsonWorkflowActionPlan.shellScript,
"# Project release readiness artifact validation is already ready.\n",
);
assert.equal(
releaseArtifactJsonWorkflowSummary.rows.find(({ id }) => id === "action-plan")?.value,
"ready",
);
assert.equal(releaseArtifactJsonWorkflowRenderState.statusLine, "Ready: Artifact JSON workflow complete");
assert.equal(
releaseArtifactJsonWorkflowRenderState.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-json-workflow",
);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract().selectors.mount,
"[data-workflow-overview-release-readiness-artifact-json-workflow]",
);
assert.equal(createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness().ready, false);
const releaseArtifactJsonWorkflowMountNode = mountDocument.createElement("section");
releaseArtifactJsonWorkflowMountNode.dataset.workflowOverviewReleaseReadinessArtifactJsonWorkflow = "";
const releaseArtifactJsonWorkflowStatusNode = mountDocument.createElement("p");
releaseArtifactJsonWorkflowStatusNode.dataset.workflowOverviewReleaseReadinessArtifactJsonWorkflowStatus = "";
const releaseArtifactJsonWorkflowRowsNode = {
...mountDocument.createElement("dl"),
children: [],
replaceChildren() {
this.children = [];
},
append(...nodes) {
this.children.push(...nodes);
},
};
releaseArtifactJsonWorkflowRowsNode.dataset.workflowOverviewReleaseReadinessArtifactJsonWorkflowRows = "";
const releaseArtifactJsonWorkflowRenderResult =
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
releaseArtifactJsonWorkflowRenderState,
{
documentRef: mountDocument,
mountNode: releaseArtifactJsonWorkflowMountNode,
statusNode: releaseArtifactJsonWorkflowStatusNode,
rowsNode: releaseArtifactJsonWorkflowRowsNode,
},
);
const releaseArtifactJsonWorkflowMountResult =
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState({
renderState: releaseArtifactJsonWorkflowRenderState,
documentRef: mountDocument,
mountNode: releaseArtifactJsonWorkflowMountNode,
statusNode: releaseArtifactJsonWorkflowStatusNode,
rowsNode: releaseArtifactJsonWorkflowRowsNode,
});
assert.equal(releaseArtifactJsonWorkflowRenderResult.rendered, true);
assert.equal(releaseArtifactJsonWorkflowRenderResult.rowCount, 5);
assert.equal(
releaseArtifactJsonWorkflowRenderResult.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-json-workflow",
);
assert.equal(
releaseArtifactJsonWorkflowRenderResult.rowIds.includes("gate-execution-summary"),
true,
);
assert.equal(releaseArtifactJsonWorkflowMountResult.ready, true);
assert.equal(releaseArtifactJsonWorkflowMountResult.renderResult.rowCount, 5);
assert.equal( assert.equal(
releaseArtifactValidation.apiName, releaseArtifactValidation.apiName,
"ini-panel-shell-workflow-overview-release-readiness-artifact-validation", "ini-panel-shell-workflow-overview-release-readiness-artifact-validation",
); );
assert.equal(releaseArtifactValidation.ready, true); assert.equal(releaseArtifactValidation.ready, true);
assert.equal(releaseArtifactValidation.validation.ready, true); assert.equal(releaseArtifactValidation.validation.ready, true);
assert.equal(releaseArtifactValidation.gateCount, 11); assert.equal(releaseArtifactValidation.gateCount, 12);
const releaseArtifactValidationSummary = const releaseArtifactValidationSummary =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel( createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(
releaseArtifactValidation, releaseArtifactValidation,
@@ -1316,6 +1461,150 @@ assert.equal(
"project-release-readiness-artifact-validation-summary-view-model", "project-release-readiness-artifact-validation-summary-view-model",
); );
assert.equal(releaseArtifactValidationSummary.statusLine, "Ready: Artifact evidence complete"); assert.equal(releaseArtifactValidationSummary.statusLine, "Ready: Artifact evidence complete");
assert.equal(releaseArtifactValidation.actionPlan.ready, true);
assert.equal(releaseArtifactValidation.actionPlan.nextCommand, null);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(
releaseArtifactValidation,
).shellScript,
"# Project release readiness artifact validation is already ready.\n",
);
const releaseArtifactValidationActionPlan =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(
releaseArtifactValidation,
);
const releaseArtifactValidationActionPlanRenderState =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(
releaseArtifactValidationActionPlan,
);
assert.equal(
releaseArtifactValidationActionPlanRenderState.statusLine,
"Ready: Artifact validation action plan complete",
);
assert.equal(releaseArtifactValidationActionPlanRenderState.rows.length, 3);
assert.equal(
releaseArtifactValidationActionPlanRenderState.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-validation-action-plan",
);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract().selectors.mount,
"[data-workflow-overview-release-readiness-artifact-validation-action-plan]",
);
assert.equal(createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness().ready, false);
const releaseArtifactValidationActionPlanMountNode = mountDocument.createElement("section");
releaseArtifactValidationActionPlanMountNode.dataset.workflowOverviewReleaseReadinessArtifactValidationActionPlan = "";
const releaseArtifactValidationActionPlanStatusNode = mountDocument.createElement("p");
releaseArtifactValidationActionPlanStatusNode.dataset.workflowOverviewReleaseReadinessArtifactValidationActionPlanStatus = "";
const releaseArtifactValidationActionPlanRowsNode = {
...mountDocument.createElement("dl"),
children: [],
replaceChildren() {
this.children = [];
},
append(...nodes) {
this.children.push(...nodes);
},
};
releaseArtifactValidationActionPlanRowsNode.dataset.workflowOverviewReleaseReadinessArtifactValidationActionPlanRows = "";
const releaseArtifactValidationActionPlanRenderResult =
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
releaseArtifactValidationActionPlanRenderState,
{
documentRef: mountDocument,
mountNode: releaseArtifactValidationActionPlanMountNode,
statusNode: releaseArtifactValidationActionPlanStatusNode,
rowsNode: releaseArtifactValidationActionPlanRowsNode,
},
);
const releaseArtifactValidationActionPlanMountResult =
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState({
renderState: releaseArtifactValidationActionPlanRenderState,
documentRef: mountDocument,
mountNode: releaseArtifactValidationActionPlanMountNode,
statusNode: releaseArtifactValidationActionPlanStatusNode,
rowsNode: releaseArtifactValidationActionPlanRowsNode,
});
assert.equal(releaseArtifactValidationActionPlanRenderResult.rendered, true);
assert.equal(releaseArtifactValidationActionPlanRenderResult.rowCount, 3);
assert.equal(
releaseArtifactValidationActionPlanRenderResult.rowIds.includes("next-command"),
true,
);
assert.equal(releaseArtifactValidationActionPlanMountResult.ready, true);
assert.equal(releaseArtifactValidationActionPlanMountResult.renderResult.rowCount, 3);
const releaseArtifactGateExecutionSummary =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(
releaseArtifactValidation,
);
assert.equal(
releaseArtifactGateExecutionSummary.apiName,
"project-release-gate-execution-summary-view-model",
);
assert.equal(
releaseArtifactGateExecutionSummary.statusLine,
"Ready: All release gate evidence present",
);
assert.equal(releaseArtifactGateExecutionSummary.rows[0].value, "12/12 passed");
const releaseArtifactGateExecutionSummaryRenderState =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(
releaseArtifactGateExecutionSummary,
);
assert.equal(
releaseArtifactGateExecutionSummaryRenderState.statusLine,
"Ready: All release gate evidence present",
);
assert.equal(releaseArtifactGateExecutionSummaryRenderState.rows.length, 18);
assert.equal(releaseArtifactGateExecutionSummaryRenderState.gateRows.length, 12);
assert.equal(
releaseArtifactGateExecutionSummaryRenderState.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-gate-execution-summary",
);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract().selectors.mount,
"[data-workflow-overview-release-readiness-artifact-gate-execution-summary]",
);
assert.equal(createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness().ready, false);
const releaseArtifactGateExecutionSummaryMountNode = mountDocument.createElement("section");
releaseArtifactGateExecutionSummaryMountNode.dataset.workflowOverviewReleaseReadinessArtifactGateExecutionSummary = "";
const releaseArtifactGateExecutionSummaryStatusNode = mountDocument.createElement("p");
releaseArtifactGateExecutionSummaryStatusNode.dataset.workflowOverviewReleaseReadinessArtifactGateExecutionSummaryStatus = "";
const releaseArtifactGateExecutionSummaryRowsNode = {
...mountDocument.createElement("dl"),
children: [],
replaceChildren() {
this.children = [];
},
append(...nodes) {
this.children.push(...nodes);
},
};
releaseArtifactGateExecutionSummaryRowsNode.dataset.workflowOverviewReleaseReadinessArtifactGateExecutionSummaryRows = "";
const releaseArtifactGateExecutionSummaryRenderResult =
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
releaseArtifactGateExecutionSummaryRenderState,
{
documentRef: mountDocument,
mountNode: releaseArtifactGateExecutionSummaryMountNode,
statusNode: releaseArtifactGateExecutionSummaryStatusNode,
rowsNode: releaseArtifactGateExecutionSummaryRowsNode,
},
);
const releaseArtifactGateExecutionSummaryMountResult =
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState({
renderState: releaseArtifactGateExecutionSummaryRenderState,
documentRef: mountDocument,
mountNode: releaseArtifactGateExecutionSummaryMountNode,
statusNode: releaseArtifactGateExecutionSummaryStatusNode,
rowsNode: releaseArtifactGateExecutionSummaryRowsNode,
});
assert.equal(releaseArtifactGateExecutionSummaryRenderResult.rendered, true);
assert.equal(releaseArtifactGateExecutionSummaryRenderResult.rowCount, 18);
assert.equal(
releaseArtifactGateExecutionSummaryRenderResult.rowIds.includes("gate-ui-node-smokes"),
true,
);
assert.equal(releaseArtifactGateExecutionSummaryMountResult.ready, true);
assert.equal(releaseArtifactGateExecutionSummaryMountResult.renderResult.rowCount, 18);
assert.equal( assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel().phase, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel().phase,
"blocked", "blocked",
@@ -1435,6 +1724,86 @@ assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "validation-summary")?.value, releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "validation-summary")?.value,
"Ready: Artifact evidence complete", "Ready: Artifact evidence complete",
); );
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "gate-execution-summary")?.value,
"Ready: All release gate evidence present",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "action-plan")?.value,
"ready",
);
assert.equal(releaseArtifactUrlWorkflow.actionPlan.ready, true);
assert.equal(releaseArtifactUrlWorkflow.actionPlan.nextCommand, null);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(
releaseArtifactUrlWorkflow,
).shellScript,
"# Project release readiness artifact URL workflow is already ready.\n",
);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel(
releaseArtifactUrlWorkflow,
).statusLine,
"Ready: All release gate evidence present",
);
const releaseArtifactUrlWorkflowRenderState =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(
releaseArtifactUrlWorkflowSummary,
);
assert.equal(
releaseArtifactUrlWorkflowRenderState.statusLine,
"Ready: Artifact URL workflow complete",
);
assert.equal(
releaseArtifactUrlWorkflowRenderState.dataset.handoffScope,
"workflow-overview-release-readiness-artifact-url-workflow",
);
assert.equal(
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract().selectors.mount,
"[data-workflow-overview-release-readiness-artifact-url-workflow]",
);
assert.equal(createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness().ready, false);
const releaseArtifactUrlWorkflowMountNode = mountDocument.createElement("section");
releaseArtifactUrlWorkflowMountNode.dataset.workflowOverviewReleaseReadinessArtifactUrlWorkflow = "";
const releaseArtifactUrlWorkflowStatusNode = mountDocument.createElement("p");
releaseArtifactUrlWorkflowStatusNode.dataset.workflowOverviewReleaseReadinessArtifactUrlWorkflowStatus = "";
const releaseArtifactUrlWorkflowRowsNode = {
...mountDocument.createElement("dl"),
children: [],
replaceChildren() {
this.children = [];
},
append(...nodes) {
this.children.push(...nodes);
},
};
releaseArtifactUrlWorkflowRowsNode.dataset.workflowOverviewReleaseReadinessArtifactUrlWorkflowRows = "";
const releaseArtifactUrlWorkflowRenderResult =
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
releaseArtifactUrlWorkflowRenderState,
{
documentRef: mountDocument,
mountNode: releaseArtifactUrlWorkflowMountNode,
statusNode: releaseArtifactUrlWorkflowStatusNode,
rowsNode: releaseArtifactUrlWorkflowRowsNode,
},
);
const releaseArtifactUrlWorkflowMountResult =
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState({
renderState: releaseArtifactUrlWorkflowRenderState,
documentRef: mountDocument,
mountNode: releaseArtifactUrlWorkflowMountNode,
statusNode: releaseArtifactUrlWorkflowStatusNode,
rowsNode: releaseArtifactUrlWorkflowRowsNode,
});
assert.equal(releaseArtifactUrlWorkflowRenderResult.rendered, true);
assert.equal(releaseArtifactUrlWorkflowRenderResult.rowCount, 8);
assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("mount-result"),
true,
);
assert.equal(releaseArtifactUrlWorkflowMountResult.ready, true);
assert.equal(releaseArtifactUrlWorkflowMountResult.renderResult.rowCount, 8);
const releaseArtifactUrlWorkflowMissingDom = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({ const releaseArtifactUrlWorkflowMissingDom = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({
artifactUrl: "/project-release-readiness.json", artifactUrl: "/project-release-readiness.json",
fetchRef: async () => ({ fetchRef: async () => ({
@@ -1473,9 +1842,80 @@ const workflowOverviewApi = {
getWorkflowOverviewApiSurfaceInventory: () => shellViewModel.shellApiSurfaceInventory, getWorkflowOverviewApiSurfaceInventory: () => shellViewModel.shellApiSurfaceInventory,
getWorkflowOverviewPersistenceSummary: () => shellViewModel.shellPersistenceSummary, getWorkflowOverviewPersistenceSummary: () => shellViewModel.shellPersistenceSummary,
validateWorkflowOverviewReleaseReadinessArtifactJson: () => ({ ready: true }), validateWorkflowOverviewReleaseReadinessArtifactJson: () => ({ ready: true }),
runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow: () => releaseArtifactJsonWorkflow,
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel: () => releaseArtifactJsonWorkflowSummary,
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan: () => releaseArtifactJsonWorkflowActionPlan,
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState: () => releaseArtifactJsonWorkflowRenderState,
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness: () => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness({
documentRef: mountDocument,
mountNode: releaseArtifactJsonWorkflowMountNode,
statusNode: releaseArtifactJsonWorkflowStatusNode,
rowsNode: releaseArtifactJsonWorkflowRowsNode,
})
),
renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState: () => releaseArtifactJsonWorkflowRenderResult,
mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState: () => releaseArtifactJsonWorkflowMountResult,
loadWorkflowOverviewReleaseReadinessArtifactUrl: loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl, loadWorkflowOverviewReleaseReadinessArtifactUrl: loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: () => releaseArtifactUrlWorkflowSummary, getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: () => releaseArtifactUrlWorkflowSummary,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan: () => releaseArtifactUrlWorkflow.actionPlan,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState: () => releaseArtifactUrlWorkflowRenderState,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness: () => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness({
documentRef: mountDocument,
mountNode: releaseArtifactUrlWorkflowMountNode,
statusNode: releaseArtifactUrlWorkflowStatusNode,
rowsNode: releaseArtifactUrlWorkflowRowsNode,
})
),
renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState: () => releaseArtifactUrlWorkflowRenderResult,
mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState: () => releaseArtifactUrlWorkflowMountResult,
getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel: () => releaseArtifactValidationSummary, getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel: () => releaseArtifactValidationSummary,
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan: () => releaseArtifactValidation.actionPlan,
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel: () => releaseArtifactGateExecutionSummary,
getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel: () => releaseArtifactGateExecutionSummary,
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState: () => (
releaseArtifactValidationActionPlanRenderState
),
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness: () => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness({
documentRef: mountDocument,
mountNode: releaseArtifactValidationActionPlanMountNode,
statusNode: releaseArtifactValidationActionPlanStatusNode,
rowsNode: releaseArtifactValidationActionPlanRowsNode,
})
),
renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState: () => (
releaseArtifactValidationActionPlanRenderResult
),
mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState: () => (
releaseArtifactValidationActionPlanMountResult
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState: () => (
releaseArtifactGateExecutionSummaryRenderState
),
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness: () => (
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness({
documentRef: mountDocument,
mountNode: releaseArtifactGateExecutionSummaryMountNode,
statusNode: releaseArtifactGateExecutionSummaryStatusNode,
rowsNode: releaseArtifactGateExecutionSummaryRowsNode,
})
),
renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState: () => (
releaseArtifactGateExecutionSummaryRenderResult
),
mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState: () => (
releaseArtifactGateExecutionSummaryMountResult
),
getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel: () => releaseArtifactDisplay, getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel: () => releaseArtifactDisplay,
getWorkflowOverviewReleaseReadinessArtifactRenderState: () => releaseArtifactRenderState, getWorkflowOverviewReleaseReadinessArtifactRenderState: () => releaseArtifactRenderState,
getWorkflowOverviewReleaseReadinessArtifactDomContract: createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract, getWorkflowOverviewReleaseReadinessArtifactDomContract: createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract,