diff --git a/PROJECT_COMPLETION_TRACKER.md b/PROJECT_COMPLETION_TRACKER.md index ca3341f..93a84db 100644 --- a/PROJECT_COMPLETION_TRACKER.md +++ b/PROJECT_COMPLETION_TRACKER.md @@ -9,7 +9,7 @@ turn-by-turn continuation notes and next-batch execution records. ## Current Status - Active continuation file: `text14.txt` -- Latest completed batch: workflow overview release readiness artifact URL workflow +- Latest completed batch: release artifact URL browser workflow gate - Latest relevant commit: use `git log -1 --oneline` after each committed batch - Working tree at tracker creation: clean - Required policy: LinuxCNC remains the only CNC semantic source @@ -48,7 +48,7 @@ The project is complete for the current scope when all of the following are true | Workflow overview embedding | Stable for current scope | Report/display/render, DOM contract/readiness/renderer, mount result/display/render, mount DOM contract/readiness/renderer/wrapper exist. | | Host/runtime boundary proof | Stable blocked state | Host smoke passes; runtime families remain blocked and `docs/host-runtime-boundary-handoff.md` records host readiness, promotion blockers, dispatch, and evidence gates. | | Documentation/release gate | Stable for current scope | `docs/project-release-handoff.md` links README, panel entry, SDK, OPFS/session, sim-config, host/runtime, source reuse, drift, 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, writes `build/project-release-readiness.json`, verifies it 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, writes `build/project-release-readiness.json`, verifies it through the SDK artifact validation workflow, and ends with `project_release_gate=ok`. | ## Blocked Runtime Families @@ -209,6 +209,7 @@ wasm-port/tools/verify_no_standalone_cnc_semantics.sh SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh 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 wasm-port/tests/ui/node/verify_ui_node_smokes.sh wasm-port/tests/host/verify_host_smokes.sh ``` diff --git a/text14.txt b/text14.txt index eba09f1..ed0e958 100644 --- a/text14.txt +++ b/text14.txt @@ -3001,7 +3001,77 @@ project_release_gate=ok 继续只做实质能力推进。优先选择真实 browser/UI workflow 或外部 shell 可消费能力; 如果继续 release 路径,必须继续产出可调用 API、可验证 workflow、可执行 gate 或可消费 artifact。 -三十九、2026-06-16 继续执行记录:workflow overview release readiness artifact URL workflow +四十一、2026-06-16 继续执行记录:release artifact URL browser workflow gate + +本轮继续按“每批必须产出可调用 API、可验证 workflow、可执行 gate、或真实 UI/browser 能力”推进, +把上一批 release readiness artifact URL workflow 提升为独立可执行 browser gate,并纳入 project +release readiness artifact 的 required gates。外部 CI 现在可以单独验证 workflow overview iframe +从 URL fetch artifact、validate、render 和 mount 的真实 browser 能力。 + +完成内容: + +- 新增真实 browser gate: + - `tests/browser/release_artifact_url_workflow_smoke.html`; + - `tests/browser/verify_release_artifact_url_workflow_browser.sh`; +- 新 gate 验证: + - missing URL 返回结构化 blocked; + - missing DOM 返回结构化 blocked 且 validation ready; + - ready DOM 下 fetch `tests/fixtures/project-release-readiness-ready.json`; + - validation gateCount 为 10; + - render-state 和 mount result 为 ready; + - 输出 `browser_release_artifact_url_workflow_smoke=ok`; +- `runtime/sdk/src/project-release-readiness.js` 的 required release gates 新增: + - `release-artifact-url-browser`; +- `verify_project_release_gate.sh` 在 browser INI smoke 后运行新 browser gate; +- `write_project_release_readiness_artifact.mjs` 写入新 gate result 和 observed output; +- `verify_project_release_readiness_artifact.mjs` 期望 `gateCount=10`; +- `tests/fixtures/project-release-readiness-ready.json` 新增第 10 个 gate; +- `verify_sdk_surface.mjs`、`verify_ini_panel_ui_shell.mjs`、workflow overview browser smoke、 + shell integration browser smoke 同步 `gateCount=10`; +- `docs/project-release-handoff.md` 和 `verify_project_release_handoff_docs.mjs` 记录新 gate; +- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch 和 release gate wrapper 状态; +- 清理 `text14.txt` 尾部重复中文编号,使续接记录标题保持唯一; +- 未新增控制按钮; +- 未执行 release gate/action-plan 以外的 CNC 行为; +- 未解析 G-code; +- 未解释 canonical events; +- 未新增 JS CNC 语义; +- 未运行 opt-in runtime probes; +- 未 promotion blocked runtime family; +- 未改变 LinuxCNC interpreter、tool、parameter、planner、kinematics、remap 或 LinuxCNC-owned + runtime semantics。 + +验证已通过(先行 targeted): + +```bash +wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh +wasm-port/tests/sdk/node/verify_sdk_surface.sh +wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh +wasm-port/tests/docs/node/verify_project_release_handoff_docs.sh +wasm-port/tests/host/verify_project_release_readiness_artifact.sh wasm-port/tests/fixtures/project-release-readiness-ready.json +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh +wasm-port/tests/ui/node/verify_ui_node_smokes.sh +git diff --check +``` + +关键输出: + +```text +browser_release_artifact_url_workflow_smoke=ok +sdk_surface_node_smoke=ok +ini_panel_ui_shell_node_smoke=ok +project_release_handoff_docs_node_smoke=ok +project_release_readiness_artifact_node_smoke=ok +browser_ini_shell_integration_workflow_smoke=ok +ui_node_smokes=ok +``` + +下一步工作计划: + +继续只做实质能力推进。优先选择可执行 gate、SDK/API surface、或真实 browser workflow; +不要做只整理断言或局部常量化的批次。 + +四十、2026-06-16 继续执行记录:workflow overview release readiness artifact URL workflow 本轮继续按“每批必须产出可调用 API、可验证 workflow、可执行 gate、或真实 UI/browser 能力”推进, 把 release readiness artifact validation 从 JSON 字符串调用推进到真实 browser URL 加载 workflow。外部 diff --git a/wasm-port/docs/project-release-handoff.md b/wasm-port/docs/project-release-handoff.md index d835404..8ef9dfe 100644 --- a/wasm-port/docs/project-release-handoff.md +++ b/wasm-port/docs/project-release-handoff.md @@ -85,6 +85,7 @@ wasm-port/tools/verify_no_standalone_cnc_semantics.sh SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh 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 wasm-port/tests/ui/node/verify_ui_node_smokes.sh wasm-port/tests/host/verify_host_smokes.sh ``` @@ -134,6 +135,7 @@ browser_ini_control_page_smoke=ok browser_ini_launch_smoke=ok browser_ini_workflow_overview_smoke=ok browser_ini_shell_integration_workflow_smoke=ok +browser_release_artifact_url_workflow_smoke=ok ``` ## Blocked runtime families @@ -157,6 +159,7 @@ must not be run on hosts that do not provide the required LinuxCNC runtime. - Sim-config inventory has `unexpected_fail=0`. - UI Node smoke passes. - Browser INI panel smoke passes. +- Release artifact URL browser workflow smoke passes. - Host aggregate smoke passes. - `verify_project_release_gate.sh` passes. - SDK exports match `runtime/sdk/README.md`. diff --git a/wasm-port/runtime/sdk/src/project-release-readiness.js b/wasm-port/runtime/sdk/src/project-release-readiness.js index 91ad417..87bf8f1 100644 --- a/wasm-port/runtime/sdk/src/project-release-readiness.js +++ b/wasm-port/runtime/sdk/src/project-release-readiness.js @@ -34,6 +34,12 @@ const REQUIRED_RELEASE_GATES = [ 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", }, + { + id: "release-artifact-url-browser", + label: "Release artifact URL browser workflow smoke", + 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", + }, { id: "ui-node-smokes", label: "UI Node smokes", diff --git a/wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html b/wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html index 22bda1d..f8bd2fb 100644 --- a/wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html +++ b/wasm-port/tests/browser/ini_panel_shell_integration_workflow_smoke.html @@ -338,7 +338,7 @@ TOOL_TABLE = browser-shell-tool.tbl "L4-PYTHON-REMAP", ], promotedBlockedFamilies: [], - gates: Array.from({ length: 9 }, (_, index) => ({ id: `gate-${index}`, passed: true })), + gates: Array.from({ length: 10 }, (_, index) => ({ id: `gate-${index}`, passed: true })), rows: [ { id: "project-release-gate", diff --git a/wasm-port/tests/browser/ini_panel_workflow_overview_smoke.html b/wasm-port/tests/browser/ini_panel_workflow_overview_smoke.html index e5f4356..354349e 100644 --- a/wasm-port/tests/browser/ini_panel_workflow_overview_smoke.html +++ b/wasm-port/tests/browser/ini_panel_workflow_overview_smoke.html @@ -93,7 +93,7 @@ "L4-PYTHON-REMAP", ], promotedBlockedFamilies: [], - gates: Array.from({ length: 9 }, (_, index) => ({ id: `gate-${index}`, passed: true })), + gates: Array.from({ length: 10 }, (_, index) => ({ id: `gate-${index}`, passed: true })), rows: [ { id: "project-release-gate", @@ -161,7 +161,7 @@ "workflow overview release artifact validation API name", ); assertEqual(releaseArtifactValidation.ready, true, "workflow overview release artifact validation readiness"); - assertEqual(releaseArtifactValidation.gateCount, 9, "workflow overview release artifact validation gates"); + assertEqual(releaseArtifactValidation.gateCount, 10, "workflow overview release artifact validation gates"); assertEqual(releaseArtifactDisplay.statusText, "Ready", "workflow overview release artifact display status"); assertEqual(releaseArtifactRenderState.statusLine, "Ready: No blocking reasons", "workflow overview release artifact render status"); assertEqual( diff --git a/wasm-port/tests/browser/release_artifact_url_workflow_smoke.html b/wasm-port/tests/browser/release_artifact_url_workflow_smoke.html new file mode 100644 index 0000000..3c3dfac --- /dev/null +++ b/wasm-port/tests/browser/release_artifact_url_workflow_smoke.html @@ -0,0 +1,86 @@ + + +
+ +running+ + + diff --git a/wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh b/wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh new file mode 100755 index 0000000..9987bf8 --- /dev/null +++ b/wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh @@ -0,0 +1,81 @@ +#!/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_INI_BUILD:-0}" != "1" ]]; then + "$ROOT_DIR/tools/build_ini_panel.sh" +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 "release artifact URL workflow 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/release_artifact_url_workflow_smoke.html" +OUT="$TMP_DIR/chromium.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_release_artifact_url_workflow_smoke=ok" "$OUT"; then + echo "release artifact URL workflow browser smoke failed" >&2 + sed -n '1,220p' "$OUT" >&2 + exit 1 +fi + +echo "browser_release_artifact_url_workflow_smoke=ok" diff --git a/wasm-port/tests/docs/node/verify_project_release_handoff_docs.mjs b/wasm-port/tests/docs/node/verify_project_release_handoff_docs.mjs index e6d4f85..a47ee85 100644 --- a/wasm-port/tests/docs/node/verify_project_release_handoff_docs.mjs +++ b/wasm-port/tests/docs/node/verify_project_release_handoff_docs.mjs @@ -51,6 +51,7 @@ for (const phrase of [ "project_release_gate=ok", "sim_configs_wasm_node_inventory_unexpected_fail=0", "browser_ini_shell_integration_workflow_smoke=ok", + "browser_release_artifact_url_workflow_smoke=ok", "project_release_handoff_docs_node_smoke=ok", "L4-USER-M-PROCESS", "L4-TOOL-DB", @@ -74,6 +75,7 @@ for (const phrase of [ "verify_interp_wasm.sh", "verify_sim_configs_inventory_wasm.sh", "verify_ini_panel_browser.sh", + "verify_release_artifact_url_workflow_browser.sh", "verify_ui_node_smokes.sh", "verify_host_smokes.sh", "write_project_release_readiness_artifact.mjs", diff --git a/wasm-port/tests/fixtures/project-release-readiness-ready.json b/wasm-port/tests/fixtures/project-release-readiness-ready.json index 4bfe00f..45c8629 100644 --- a/wasm-port/tests/fixtures/project-release-readiness-ready.json +++ b/wasm-port/tests/fixtures/project-release-readiness-ready.json @@ -71,6 +71,14 @@ "status": "passed", "passed": true }, + { + "id": "release-artifact-url-browser", + "label": "Release artifact URL browser workflow smoke", + "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", + "status": "passed", + "passed": true + }, { "id": "ui-node-smokes", "label": "UI Node smokes", diff --git a/wasm-port/tests/host/verify_project_release_gate.sh b/wasm-port/tests/host/verify_project_release_gate.sh index ef1a5ec..96b6dc9 100755 --- a/wasm-port/tests/host/verify_project_release_gate.sh +++ b/wasm-port/tests/host/verify_project_release_gate.sh @@ -12,6 +12,7 @@ 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_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_release_artifact_url_workflow_browser.sh" "$ROOT_DIR/tests/ui/node/verify_ui_node_smokes.sh" "$ROOT_DIR/tests/host/verify_host_smokes.sh" diff --git a/wasm-port/tests/host/verify_project_release_readiness_artifact.mjs b/wasm-port/tests/host/verify_project_release_readiness_artifact.mjs index b50b1f1..7a7cf13 100644 --- a/wasm-port/tests/host/verify_project_release_readiness_artifact.mjs +++ b/wasm-port/tests/host/verify_project_release_readiness_artifact.mjs @@ -20,6 +20,6 @@ assert.equal(validation.phase, "ready"); assert.deepEqual(validation.missing, []); assert.equal(validation.artifactApiName, "project-release-readiness-report"); assert.equal(validation.artifactVersion, 1); -assert.equal(validation.gateCount, 9); +assert.equal(validation.gateCount, 10); console.log("project_release_readiness_artifact_node_smoke=ok"); diff --git a/wasm-port/tests/host/write_project_release_readiness_artifact.mjs b/wasm-port/tests/host/write_project_release_readiness_artifact.mjs index f02130f..4dc791f 100644 --- a/wasm-port/tests/host/write_project_release_readiness_artifact.mjs +++ b/wasm-port/tests/host/write_project_release_readiness_artifact.mjs @@ -15,6 +15,7 @@ const passedGateResults = { "interp-wasm": true, "sim-config-inventory": true, "ini-panel-browser": true, + "release-artifact-url-browser": true, "ui-node-smokes": true, "host-smokes": true, "project-release-gate": true, @@ -28,6 +29,7 @@ const report = createProjectReleaseReadinessReport({ "interp_wasm_node_smoke=ok", "sim_configs_wasm_node_inventory_unexpected_fail=0", "browser_ini_shell_integration_workflow_smoke=ok", + "browser_release_artifact_url_workflow_smoke=ok", "ui_node_smokes=ok", "host_wasm_opfs_browser_smokes=ok", "project_release_gate=ok", diff --git a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs index 0d4396c..9b50c24 100644 --- a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs +++ b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs @@ -222,6 +222,7 @@ const releaseReadinessArtifact = parseProjectReleaseReadinessArtifactJson(JSON.s "interp-wasm": true, "sim-config-inventory": true, "ini-panel-browser": true, + "release-artifact-url-browser": true, "ui-node-smokes": true, "host-smokes": true, "project-release-gate": true, @@ -236,7 +237,7 @@ assert.deepEqual(createProjectReleaseReadinessArtifactValidation(releaseReadines missing: [], artifactApiName: "project-release-readiness-report", artifactVersion: 1, - gateCount: 9, + gateCount: 10, blockedRuntimeFamilies: [ "L4-USER-M-PROCESS", "L4-TOOL-DB", diff --git a/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs b/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs index 8b5b00b..891bf4d 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs @@ -1308,7 +1308,7 @@ const releaseReadinessArtifactJson = JSON.stringify({ "L4-PYTHON-REMAP", ], promotedBlockedFamilies: [], - gates: Array.from({ length: 9 }, (_, index) => ({ id: `gate-${index}`, passed: true })), + gates: Array.from({ length: 10 }, (_, index) => ({ id: `gate-${index}`, passed: true })), rows: [ { id: "project-release-gate", @@ -1326,7 +1326,7 @@ assert.equal( ); assert.equal(releaseArtifactValidation.ready, true); assert.equal(releaseArtifactValidation.validation.ready, true); -assert.equal(releaseArtifactValidation.gateCount, 9); +assert.equal(releaseArtifactValidation.gateCount, 10); const releaseArtifactDisplay = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel( releaseArtifactValidation, );