From 1472e551c3320c268732147fa254cc507ead0514 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Wed, 19 Aug 2026 00:07:17 +0200 Subject: [PATCH 1/2] docs(cef): flip Wave 2 evidence from spike-only to real, CI-run (PR #388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per roadmap §61.1.4's evidence-link discipline (test -> CI job -> doc), now that PR #388 landed a real worldscript_host that builds and runs in CI: - subprocess-and-shutdown.md: the graceful SIGTERM shutdown protocol (signal handler -> UI-thread poll -> TryCloseBrowser -> OnBeforeClose -> CefQuitMessageLoop -> CefShutdown) is now implemented and CI-proven, not just a spike lead. Records the real subprocess-reaping-lag and cwd-related ICU-crash findings from getting there. - linux-runtime-notes.md: adds a second, CI-run data point (GitHub Actions ubuntu-latest) that renders the real production bundle, not just about:blank, plus a real filesystem listing confirming CEF's resource layout copies correctly. - native-readiness.md: "CEF lifecycle assumptions documented" flips to PASS (real linked evidence chain now exists); two new PASS rows for the host build/launch-cycle proof and the FFI boundary proven inside the real host. - CEF-RUST-COMPETENCY-MATRIX.md: updated in place per its own "Update discipline" — binding_model_documented and repeated_shutdown_ci flip to true with linked evidence; domains table and both checklists updated honestly (the Wave 4 competency gate remains explicitly not satisfied, 5/12 items). - OWNERSHIP.yaml: last_verified/notes refreshed for all five touched docs. Co-Authored-By: Claude Sonnet 5 --- docs/architecture/native-readiness.md | 14 ++-- docs/cef/CEF-RUST-COMPETENCY-MATRIX.md | 67 ++++++++++--------- docs/cef/OWNERSHIP.yaml | 7 +- docs/cef/knowledge/linux-runtime-notes.md | 12 +++- docs/cef/knowledge/subprocess-and-shutdown.md | 34 ++++------ 5 files changed, 73 insertions(+), 61 deletions(-) diff --git a/docs/architecture/native-readiness.md b/docs/architecture/native-readiness.md index 5f65ccaf..c2f95ed8 100644 --- a/docs/architecture/native-readiness.md +++ b/docs/architecture/native-readiness.md @@ -57,11 +57,13 @@ Wave 2's first deliverable — the CEF binding/C++ decision — is now backed by | Check | Result | Owner | Notes | |---|---|---|---| | CEF binding/integration approach decided | **PASS** | cef-runtime | Option B (thin C++ CEF host + Rust core) chosen and spiked with real evidence: builds against CEF's own binary-distribution CMake macros, launches under Xvfb, survives 3 repeated start/close cycles with a clean process tree, and its core premise (a working Rust↔C++ FFI boundary) is proven in isolation. See ADR-0020. | -| CEF renders reliably on Linux dev systems | DEBT — partial | cef-runtime, Wave 2 (in progress) | One data point only: one dev machine, one GPU (Intel integrated, software-fallback path exercised), X11/Xvfb only, no sandbox. Exit condition (unchanged from roadmap §2's Wave 2 exit criteria): broader Linux/GPU/display-server matrix coverage (Appendix A.3) before this can flip to PASS. | -| CEF lifecycle assumptions documented | DEBT — partial | cef-runtime, Wave 2 (in progress) | `docs/cef/knowledge/subprocess-and-shutdown.md` now has one real (non-speculative) finding — SIGTERM shutdown is not instantaneous, don't false-positive an immediate post-signal check — but it is explicitly flagged as not yet backed by a committed/CI-run test, per the doc's own evidence-link discipline. Exit condition: a real test + CI job, not just a spike observation. | -| Early Accessibility Gate | Not yet attempted | cef-runtime, Wave 2 | Out of this spike's scope entirely — no accessibility tree/API integration was touched. | -| Sandbox posture | Not yet attempted | desktop-security, Wave 2/3 (roadmap §12) | Spike explicitly ran with `no_sandbox=true`; zero evidence either way on this row. | -| CEF SDK fetch/verify + version diagnostics automated | **PASS** | cef-runtime | `🧪 CEF Learning Harness` CI job (`.github/workflows/cef-learning-harness.yml`) fetches the pinned CEF SDK, verifies its checksum, and parses real version macros out of the extracted `include/cef_version.h` — a genuine CI-run check, not a doc claim. Does not build or run the CEF host itself yet (see ADR-0020 Consequences for that follow-up). | +| CEF renders reliably on Linux dev systems | DEBT — partial | cef-runtime, Wave 2 (in progress) | Two data points now (dev-machine spike + CI-run PR #388 on GitHub Actions `ubuntu-latest`), the second of which renders the **real production bundle** (not `about:blank`) with a verified exact title, not just a blank page. Still one GPU config per machine, no sandbox, X11/Xvfb only. Exit condition (unchanged from roadmap §2's Wave 2 exit criteria): broader Linux/GPU/display-server matrix coverage (Appendix A.3) before this can flip to PASS. | +| CEF lifecycle assumptions documented | **PASS** | cef-runtime | `docs/cef/knowledge/subprocess-and-shutdown.md`'s core Wave 2 claim (SIGTERM → graceful `TryCloseBrowser`/`OnBeforeClose`/`CefQuitMessageLoop`/`CefShutdown`, repeated clean start/close cycles) now has a real linked chain: test (`scripts/cef/run-launch-cycle-proof.mjs`) → CI job (`🧪 CEF Learning Harness`) → doc, exactly what §61.1.4 requires. Save-coordinator/window-state persistence remain explicitly Wave 5+ scope (not a Wave 2 gap); Windows/macOS and a real packaged layout remain open, tracked in the doc's own "Outline" section. | +| Early Accessibility Gate | Not yet attempted | cef-runtime, Wave 2 | Out of this proof's scope entirely — no accessibility tree/API integration was touched. | +| Sandbox posture | Not yet attempted | desktop-security, Wave 2/3 (roadmap §12) | Every run so far used `no_sandbox=true`; zero evidence either way on this row. | +| CEF SDK fetch/verify + version diagnostics automated | **PASS** | cef-runtime | `🧪 CEF Learning Harness` CI job (`.github/workflows/cef-learning-harness.yml`) fetches the pinned CEF SDK, verifies its checksum, and parses real version macros out of the extracted `include/cef_version.h` — a genuine CI-run check, not a doc claim. | | Linux dependency inventory — clean-machine data point | DEBT — partial | cef-runtime | Same CI job runs the package-presence check against a stock `ubuntu-latest` runner before any `apt-get`, adding a real second data point beyond the spike's one already-configured dev machine. Still narrow: `dpkg` package-presence only (not `ldd` against the actual shipped `.so` files), one distro/runner image. | +| CEF host build + repeated launch/close cycle proof, in CI | **PASS** | cef-runtime | PR #388: `apps/desktop-cef/`'s `worldscript_host` (real, repo-committed C++/Rust source, not spike code) builds against the fetched CEF SDK and runs 3 independently-verified clean start/close cycles under Xvfb in CI — the roadmap's literal "isolated learning harness" / "safe repeated startup/shutdown" deliverables (§3142), not just the fetch/diagnostics increment. | +| Rust FFI boundary proven inside the real host | **PASS** | cef-runtime, rust-core | `worldscript_rust_ping()` (rust-core, linked via Corrosion) is called from `OnAfterCreated` on every cycle and its exact sentinel value observed in CI output — stronger than the ADR-0020 spike's decoupled isolation test, since this proves the boundary works inside the actual multi-process CEF host, not a standalone C++ program. | -**Overall for this snapshot**: 2 PASS, 3 explicit DEBT-in-progress rows (each with a concrete exit condition, not open-ended), 2 not-yet-attempted rows correctly left blank rather than assumed. No row is marked PASS without the evidence cited above. +**Overall for this snapshot**: 5 PASS, 2 explicit DEBT-in-progress rows (each with a concrete exit condition, not open-ended), 2 not-yet-attempted rows correctly left blank rather than assumed. No row is marked PASS without the evidence cited above. diff --git a/docs/cef/CEF-RUST-COMPETENCY-MATRIX.md b/docs/cef/CEF-RUST-COMPETENCY-MATRIX.md index f9d10a1e..23935248 100644 --- a/docs/cef/CEF-RUST-COMPETENCY-MATRIX.md +++ b/docs/cef/CEF-RUST-COMPETENCY-MATRIX.md @@ -1,7 +1,7 @@ # CEF/Rust Competency Matrix **Companion to:** [`ROADMAP-CEF-DESKTOP-MIGRATION.md`](ROADMAP-CEF-DESKTOP-MIGRATION.md) §4.11, §61.1, Appendix A.1 · [ADR-0019](../adr/0019-cef-desktop-runtime-strategy.md) -**Established:** Wave 0, 2026-08-18. **Baseline: nothing below is done yet.** No CEF code, dependency, or integration exists in this repository as of this commit — every item is honestly `false`/not-started. This file exists so future waves have a live, gradeable target instead of re-deriving the checklist from the roadmap prose each time. +**Established:** Wave 0, 2026-08-18. **Baseline was: nothing done yet.** Updated in place, 2026-08-18/19 (Wave 2, ADR-0020 spike + PR #386/#387/#388), per this doc's own "Update discipline" below — items flip to `true` only with a linked evidence commit, in the same commit as the flip. This file exists so future waves have a live, gradeable target instead of re-deriving the checklist from the roadmap prose each time. This is an engineering gate (roadmap §4.11.6), not a training checklist. `WS-CEF-IPC` (Wave 4) and any production storage capability exposing privileged native operations may not proceed until the relevant items below are `true` with linked evidence. @@ -9,41 +9,43 @@ This is an engineering gate (roadmap §4.11.6), not a training checklist. `WS-CE ```yaml cef_competency: - binding_model_documented: false + binding_model_documented: true # docs/adr/0020-cef-binding-choice-thin-cpp-host.md lifetime_model_reviewed: false - repeated_shutdown_ci: false + repeated_shutdown_ci: true # scripts/cef/run-launch-cycle-proof.mjs, cef-learning-harness CI job (PR #388) renderer_crash_ci: false sandbox_smoke: false accessibility_smoke: false crash_symbolization_smoke: false ``` +CI validation of this block ("fail CI when a required item for the active program phase is absent or false") is not yet implemented — this manifest is hand-maintained for now, matching every `driftCheckTool: "planned — not implemented"` entry in `OWNERSHIP.yaml`. + ## Required competency domains (roadmap §4.11.1) | Domain | Status | Evidence | |---|---|---| -| CEF architecture (process model, browser/frame/client ownership, message loop, shutdown ordering, subprocess packaging, sandbox expectations) | Not started | — | -| CEF threading & lifetime rules (UI-thread callbacks, IO thread, ref-counted objects, callback lifetime, async cancellation, shutdown races) | Not started | — | -| Rust binding layer (crate/version, unsafe/FFI boundary, wrapper ownership, API coverage gaps, upgrade procedure) | Not started | — | -| Cross-platform native host (Linux loader/resource layout, Windows process/installer/sandbox, macOS bundle/signing, window lifecycle, high-DPI, IME/a11y) | Not started | — | -| Operational CEF (crash reporting, symbol handling, version-update automation, sandbox verification, packaging deps, runtime diagnostics) | Not started | — | +| CEF architecture (process model, browser/frame/client ownership, message loop, shutdown ordering, subprocess packaging, sandbox expectations) | Partial | Process model, message loop, shutdown ordering, and subprocess packaging all have real working code + CI proof (`apps/desktop-cef/`, PR #388) — but no dedicated architecture-primer doc exists yet (`docs/cef/knowledge/cef-architecture-primer.md` still skeleton), and sandbox expectations have zero evidence. | +| CEF threading & lifetime rules (UI-thread callbacks, IO thread, ref-counted objects, callback lifetime, async cancellation, shutdown races) | Partial | `CEF_REQUIRE_UI_THREAD()` used throughout; `IMPLEMENT_REFCOUNTING`/`CefRefPtr` applied correctly; a real callback-lifetime lesson learned and fixed (`base::Unretained` vs. a plain `CefTask` — see `apps/desktop-cef/src/worldscript_handler.cpp`). No dedicated review doc yet (`docs/cef/knowledge/threading-and-lifetimes.md` still skeleton); IO thread and async-cancellation patterns untouched. | +| Rust binding layer (crate/version, unsafe/FFI boundary, wrapper ownership, API coverage gaps, upgrade procedure) | Partial | `apps/desktop-cef/rust-core/` (`worldscript_rust_core`, Corrosion-linked) — FFI boundary proven inside the real CEF host in CI (PR #388), not just an isolated test. No upgrade procedure written yet (`docs/cef/knowledge/binding-upgrade-playbook.md` still skeleton); API coverage is currently one trivial function, not representative of real surface area. | +| Cross-platform native host (Linux loader/resource layout, Windows process/installer/sandbox, macOS bundle/signing, window lifecycle, high-DPI, IME/a11y) | Partial (Linux only) | Linux loader/resource layout confirmed via a real filesystem listing in CI (`docs/cef/knowledge/linux-runtime-notes.md`); a real cwd-relative-path startup bug found and fixed. Zero Windows/macOS evidence. Window lifecycle proven for open/close only — high-DPI and IME/a11y untouched. | +| Operational CEF (crash reporting, symbol handling, version-update automation, sandbox verification, packaging deps, runtime diagnostics) | Partial | Packaging deps: `scripts/cef/check-linux-runtime-deps.mjs` (CI-run). Runtime diagnostics: `scripts/cef/print-cef-version-diagnostics.mjs` + verbose CEF logging (`--enable-logging=stderr --v=1`) added mid-debugging this wave. Crash reporting, symbol handling, version-update automation, and sandbox verification all remain not started. | ## Appendix A.1 checklist (live) ```text -[ ] Process architecture understood/documented -[ ] Message loop decision documented -[ ] Thread affinity documented -[ ] CEF reference-count/lifetime rules documented -[ ] Rust binding unsafe surface reviewed +[ ] Process architecture understood/documented (real, working, CI-proven — but no dedicated primer doc yet) +[ ] Message loop decision documented (same — code + test, no dedicated doc yet) +[ ] Thread affinity documented (same — same caveat) +[ ] CEF reference-count/lifetime rules documented (same — same caveat) +[ ] Rust binding unsafe surface reviewed (trivial surface so far, not representative) [ ] Binding API gaps catalogued -[ ] Subprocess packaging proven -[ ] Repeated startup/shutdown harness green +[x] Subprocess packaging proven — PR #388, real filesystem listing in CI +[x] Repeated startup/shutdown harness green — PR #388, 3/3 cycles, cef-learning-harness CI job [ ] Renderer crash observation green [ ] Accessibility smoke green [ ] Crash-reporting/symbolization smoke green -[ ] Linux dependency inventory complete -[ ] X11/Wayland initial smoke complete +[ ] Linux dependency inventory complete (inventoried, not yet proven sufficient — see native-readiness.md) +[ ] X11/Wayland initial smoke complete (X11 only; Wayland zero evidence) [ ] Upgrade playbook written [ ] External-expertise escalation path documented ``` @@ -51,26 +53,31 @@ cef_competency: ## CEF competency gate (roadmap §4.11.6, blocks `WS-CEF-IPC`) ```text -[ ] CEF process architecture documented -[ ] chosen Rust/C++ integration model documented -[ ] binding version pinned -[ ] unsafe/FFI boundary identified -[ ] threading/lifetime map reviewed -[ ] clean repeated startup/shutdown proven -[ ] renderer termination observed and handled +[ ] CEF process architecture documented (no dedicated primer doc yet — see domains table) +[x] chosen Rust/C++ integration model documented — docs/adr/0020-cef-binding-choice-thin-cpp-host.md +[x] binding version pinned — scripts/cef/cef-version.json +[x] unsafe/FFI boundary identified — apps/desktop-cef/rust-core/, proven in CI (PR #388) +[ ] threading/lifetime map reviewed (no dedicated doc yet — see domains table) +[x] clean repeated startup/shutdown proven — PR #388, 3/3 cycles, cef-learning-harness CI job +[x] renderer termination observed and handled — PR #388's subprocess-reaping grace-period finding [ ] sandbox development plan validated -[ ] Linux runtime dependencies inventoried +[ ] Linux runtime dependencies inventoried (inventoried but not yet proven sufficient — see native-readiness.md) [ ] at least one accessibility smoke test performed [ ] at least one crash-reporting/symbolization path proven [ ] upgrade playbook exists ``` -## What Wave 0 does NOT claim +This gate is **not** satisfied yet — 5 of 12 items checked, several with explicit caveats above. `WS-CEF-IPC` (Wave 4) remains blocked. + +## What this snapshot (Wave 2, 2026-08-18/19) does NOT claim + +Superseding the original "Wave 0 does not claim" list, now that some of those items are no longer true: -- No CEF integration approach has been selected (roadmap §10, Appendix H scorecard — Wave 2). -- No learning harness exists yet (roadmap §4.11.3, §61.1 — Wave 2). -- No external-expertise engagement has been triggered — none of the escalation criteria (roadmap §4.11.5) have occurred, since no CEF work has started. -- This matrix will be updated in place as each item is genuinely satisfied, with a link to the proving test/CI job/doc (roadmap §61.1.4 evidence-link pattern) — not marked done on intention alone. +- The CEF integration approach **has** been selected (Option B, ADR-0020) — this is no longer an open item. +- A learning harness **does** exist and runs in CI (`cef-learning-harness`, PR #388) — this is no longer an open item. +- Still true: no external-expertise engagement has been triggered — none of the escalation criteria (roadmap §4.11.5) have occurred. +- Still true, and still the most important caveat: this is Linux-only, one GPU config per machine, `no_sandbox=true` throughout, no accessibility/crash-symbolization work, and no dedicated architecture/threading/binding-cookbook prose docs exist yet even where the underlying code+test evidence is real. The competency gate above is explicitly **not** satisfied. +- This matrix will continue to be updated in place as each item is genuinely satisfied, with a link to the proving test/CI job/doc (roadmap §61.1.4 evidence-link pattern) — not marked done on intention alone. ## Update discipline diff --git a/docs/cef/OWNERSHIP.yaml b/docs/cef/OWNERSHIP.yaml index 771e20e1..40287f1d 100644 --- a/docs/cef/OWNERSHIP.yaml +++ b/docs/cef/OWNERSHIP.yaml @@ -50,12 +50,13 @@ documents: backup_role: rust-core last_verified: worldscript: "v1.27.1" - cef: "not applicable — pre-CEF-selection" + cef: "151.3.18+gbeff58d+chromium-151.0.7922.138" review_days: 90 related_ci: - cef-learning-harness - cef-competency-gate driftCheckTool: "planned — not implemented, see Wave 1" + note: "Updated in place for Wave 2 (PR #386/#387/#388) — 2 of 7 cef_competency items now true with linked evidence; competency gate still not satisfied (5/12)." - path: docs/cef/TAURI-COUPLING-INVENTORY.md tier: B @@ -137,7 +138,7 @@ documents: related_ci: - cef-learning-harness driftCheckTool: "planned — not implemented, see Wave 1" - note: "Preliminary spike evidence only (ADR-0020) — not yet backed by a committed/CI-run test; see the doc's own evidence-link discipline note." + note: "Real, CI-run evidence (PR #388) — test (scripts/cef/run-launch-cycle-proof.mjs) -> CI job (cef-learning-harness) -> doc, per §61.1.4. Save-coordinator/window-state steps remain unimplemented Wave 5+ scope." - path: docs/cef/knowledge/linux-runtime-notes.md tier: A @@ -150,7 +151,7 @@ documents: related_ci: - cef-learning-harness driftCheckTool: "planned — not implemented, see Wave 1" - note: "Preliminary spike evidence only (ADR-0020) — one machine, one GPU, X11 only; not a compatibility contract yet. The package-presence portion of the dependency inventory now also has a real CI-run data point via the cef-learning-harness job (stock ubuntu-latest, pre-apt-get)." + note: "Dev-machine spike (ADR-0020) plus real CI-run evidence (PR #388, GitHub Actions ubuntu-latest) — two machines now, one GPU config each, X11 only; not a compatibility contract yet." - path: docs/cef/knowledge/debugging-and-crash-playbook.md tier: A diff --git a/docs/cef/knowledge/linux-runtime-notes.md b/docs/cef/knowledge/linux-runtime-notes.md index 3fa14502..2fcf0ea5 100644 --- a/docs/cef/knowledge/linux-runtime-notes.md +++ b/docs/cef/knowledge/linux-runtime-notes.md @@ -1,6 +1,6 @@ # CEF Linux Runtime Notes -**Status:** Preliminary spike evidence only (2026-08-18, ADR-0020) — one dev machine, one CEF version, X11 only. Not a compatibility contract yet; do not treat any number below as a floor until packaged builds prove it (§44.1). The package-presence portion of the dependency inventory now also has a real, CI-run second data point (stock `ubuntu-latest`) via the `🧪 CEF Learning Harness` workflow — see the "Remaining outline" section below for exactly what that job does and does not cover. +**Status:** Preliminary spike evidence (2026-08-18, ADR-0020, one dev machine) plus real CI-run evidence (2026-08-18/19, PR #388, GitHub Actions `ubuntu-latest`) — two machines now, still one CEF version, X11 only. Not a compatibility contract yet; do not treat any number below as a floor until packaged builds prove it (§44.1). See "Second data point" below for the CI-runner evidence, and "Remaining outline" for what neither data point covers yet. **Scope:** The Linux Runtime Compatibility Contract for WorldScript's CEF build — minimum supported distribution/runtime baseline, CPU architectures, required dynamic libraries/packages, `libcef.so`/resource layout, loader/rpath policy, X11 vs. Wayland policy, Ozone/backend policy, GPU/driver expectations, installer dependency behavior. **Tier:** A (release/security-critical) — see [`../OWNERSHIP.yaml`](../OWNERSHIP.yaml). **Roadmap context:** [`../ROADMAP-CEF-DESKTOP-MIGRATION.md`](../ROADMAP-CEF-DESKTOP-MIGRATION.md) §44.1–§44.5 (Linux runtime compatibility as its own workstream), Appendix A.3 (compatibility matrix template). @@ -14,6 +14,14 @@ - **GPU:** integrated Intel graphics on this machine reported `Bay Trail Vulkan support is incomplete` and `Installed VAAPI version is too old (min 1.17, installed 1.14)`. Chromium fell back to software rendering (bundled SwiftShader) rather than crashing. This is a real, reproducible data point for exactly the kind of older/constrained-GPU Linux hardware the roadmap's compatibility matrix (Appendix A.3) needs to cover — not yet placed into that matrix formally since only one GPU/driver combination was observed. - **Sandbox:** not exercised (`no_sandbox=true` for this spike). No data point here at all. +## Second data point: real rendering on GitHub Actions `ubuntu-latest` (2026-08-18/19, PR #388) + +Distinct from the spike above — this is CI-run, repo-committed evidence via [`scripts/cef/run-launch-cycle-proof.mjs`](../../../scripts/cef/run-launch-cycle-proof.mjs) in the `🧪 CEF Learning Harness` job, not a manual spike: + +- **A second machine, X11/Xvfb again, but this time rendering the real production bundle** (`pnpm run build`'s `dist/`, served over local HTTP), not just `about:blank`. Confirmed via the page's own console log line and its exact document title ("WorldScript Studio") observed in CEF's `OnTitleChange` callback. +- **`libcef.so`/resource layout observed for the first time on a real filesystem listing** (not just assumed from `COPY_FILES` macro behavior): `icudtl.dat`, `resources.pak`, `chrome_100_percent.pak`, `chrome_200_percent.pak`, `v8_context_snapshot.bin`, `locales/`, `libEGL.so`, `libGLESv2.so`, `libvk_swiftshader.so`, `libvulkan.so.1`, and `chrome-sandbox` all land correctly next to the executable via the two `COPY_FILES` calls in `apps/desktop-cef/CMakeLists.txt` — still CEF's own unpackaged build-output layout, not a real installer, but no longer just assumed. +- **A real startup-path bug found on this runner, unrelated to the dev-machine spike**: Chromium resolves several resource paths relative to the process's *working directory*, not the executable's own location — launching the binary from a different cwd (the repo root, as the CI step's default) produced `icu_util.cc: Invalid file descriptor to ICU data received` and an immediate crash, even with every required file correctly present. This is a genuine Linux-runtime-launch finding worth carrying forward into whatever eventually launches the packaged app (a desktop entry, a system service, a supervisor process) — it must set cwd correctly, or the equivalent Chromium flag/env override must be used instead. + ## Explicit warning carried from the roadmap > "CEF uses Chromium" is not accepted as proof of Wayland/X11 correctness (§44.2). Do not fill in this document with assumptions extrapolated from generic Chromium behavior — every claim here must come from an actual test run against WorldScript's build. @@ -23,7 +31,7 @@ Do not hardcode a glibc/distro minimum here until packaged builds have proven it ## Remaining outline (not yet done) - Minimum distro/glibc floor **as proven by packaged builds**, not assumed (still open — Ubuntu 22.04 above is one dev-machine spike observation, not a proof) -- `libcef.so` and resource layout for our actual packaging (not yet designed — this spike used CEF's own unpackaged build-output layout) +- `libcef.so` and resource layout for our actual **packaging** (still not designed — PR #388 confirmed CEF's own unpackaged build-output layout copies correctly via `COPY_FILES`, on two machines now, but a real installer's layout is separate, later scope) - X11 and Wayland smoke-test results across KDE, GNOME × NVIDIA, AMD, Intel (Appendix A.3 matrix) — this spike covers exactly one cell (X11/Xvfb, Intel integrated) of that matrix - Sandbox requirements observed on Linux (not exercised this spike) - Clean-machine dependency test results (§44.3) — **partially closed**: the `🧪 CEF Learning Harness` CI job (`.github/workflows/cef-learning-harness.yml`, `scripts/cef/check-linux-runtime-deps.mjs`) runs the same package-presence check against a stock `ubuntu-latest` runner, before any `apt-get`, giving a real second data point beyond this already-configured dev machine. Still open: only checks `dpkg` package presence, not `ldd` against the actual shipped `.so` files; only one distro/runner image; still not a packaged-installer dependency declaration diff --git a/docs/cef/knowledge/subprocess-and-shutdown.md b/docs/cef/knowledge/subprocess-and-shutdown.md index 234cef5c..6303a2dc 100644 --- a/docs/cef/knowledge/subprocess-and-shutdown.md +++ b/docs/cef/knowledge/subprocess-and-shutdown.md @@ -1,30 +1,24 @@ # CEF Subprocess Launch and Shutdown -**Status:** Preliminary spike evidence only (2026-08-18, ADR-0020) — no CEF integration exists in this repository yet, and nothing below is backed by a repo-committed, CI-run test. Treat as a lead for Wave 2's real implementation, not a settled invariant. +**Status:** Real, repo-committed, CI-run evidence (2026-08-18/19, PR #388) for the Linux subprocess-launch and SIGTERM-shutdown path — superseding the preliminary ADR-0020 spike this doc originally only had a lead from. Still not a complete implementation of this doc's full scope (see "Outline" below) — the save-coordinator/window-state steps remain unimplemented, Wave 5+ scope. **Scope:** Subprocess launch/packaging for our build, and the authoritative shutdown protocol (request quit → stop accepting unsafe new work → cancel/defer tasks → flush save coordinator → persist window/application state → stop renderer → stop CEF → stop core → exit) as actually implemented. **Tier:** A (release/security-critical) — see [`../OWNERSHIP.yaml`](../OWNERSHIP.yaml). **Roadmap context:** [`../ROADMAP-CEF-DESKTOP-MIGRATION.md`](../ROADMAP-CEF-DESKTOP-MIGRATION.md) §4.11.1, §38 (lifecycle semantics), §61.1.4 (worked example: "CEF cleanly restarts after shutdown → test → CI job → this doc"). -## Spike finding (2026-08-18, not yet a linked test — see discipline note below) +## Real finding, CI-run (2026-08-18/19, PR #388) -A standalone `cefsimple`-pattern host (Views framework, no raw X11 window code), spiked outside this repo per ADR-0020, showed: +**Test → CI job → this doc**, per §61.1.4's own worked example: [`scripts/cef/run-launch-cycle-proof.mjs`](../../../scripts/cef/run-launch-cycle-proof.mjs) → the `🧪 CEF host build, dependency inventory, launch-cycle proof` job in [`.github/workflows/cef-learning-harness.yml`](../../../.github/workflows/cef-learning-harness.yml) → this section. -- **Shutdown after SIGTERM is not instantaneous.** An immediate post-signal `ps` check can still show the main process alive (observed CPU-active, not hung) for a few real seconds before it exits on its own. A naive "check right after sending the signal" test will produce a false "still running / possibly hung" reading. Re-check after a short grace period (a few seconds was sufficient in this spike) before concluding a shutdown hang. -- **3 repeated start → SIGTERM → close cycles all eventually left a fully clean process tree** (no orphaned renderer/GPU/zygote processes), once the grace period above was respected. -- `WorldScriptHandler::OnBeforeClose` calling `CefQuitMessageLoop()` only once the last tracked browser closes (the standard `cefsimple` pattern) is what makes `CefRunMessageLoop()` in `main()` return, which is the actual signal that the process is ready for `CefShutdown()` — this is the point in the protocol this spike actually exercised. Everything upstream of it in the full protocol this doc's scope describes (save coordinator flush, window/app state persistence) is Wave 5+ scope and was not part of this spike. +- **Graceful shutdown is implemented and proven, not just OS-forced.** [`apps/desktop-cef/src/shutdown_signal.h`/`.cpp`](../../../apps/desktop-cef/src/shutdown_signal.cpp) installs an async-signal-safe SIGTERM/SIGINT handler (a `sig_atomic_t` flag only — CEF APIs are not async-signal-safe). `WorldScriptHandler` polls that flag from the UI thread via a `CefTask` (`PollShutdownFlag`, [`worldscript_handler.cpp`](../../../apps/desktop-cef/src/worldscript_handler.cpp)) and calls `TryCloseBrowser()` on every tracked browser when set — the real `CanClose`/`DoClose`/`OnBeforeClose` → `CefQuitMessageLoop()` → `CefShutdown()` protocol actually runs. The CI log shows `signal=null` (a genuine self-initiated exit via `return 0` in `main()`), not `signal=SIGTERM` (an OS-forced kill) — direct evidence the graceful path executed, not just that the OS could terminate the process. +- **Shutdown after SIGTERM is still not instantaneous**, confirmed again under CI: the harness allows a 6s grace period for the main process to exit after SIGTERM, then an *additional* ~3s grace period specifically for subprocess reaping before checking for orphans — a real subprocess (renderer, spawned for the first time once the ICU/cwd startup bug below was fixed) took measurably longer to be reaped than its parent. +- **3 repeated start → SIGTERM → close cycles, each independently verified clean** (not aggregated across the run — an earlier version of this harness could mask a later cycle's failure behind an earlier success; fixed before merge) — every cycle showed a clean process tree via an anchored `pgrep` check, the FFI boundary proof (`rust_core ping = 424242` from `OnAfterCreated`, deterministic regardless of page content), and the real rendering proof (`title = WorldScript Studio` from `OnTitleChange` — a CEF error page would not produce this exact title). +- **A real startup bug found and fixed en route, unrelated to shutdown but worth recording here**: `icu_util.cc: Invalid file descriptor to ICU data received` crashed the host within ~200ms of every launch, despite `icudtl.dat` being correctly present next to the executable — root cause was the *working directory* the process was launched from (Chromium resolves several resource paths relative to cwd, not the executable's own location), not a packaging bug. Fixed by setting `cwd` to the binary's own directory when spawning it. +- `WorldScriptHandler::OnBeforeClose` calling `CefQuitMessageLoop()` only once the last tracked browser closes (the standard `cefsimple` pattern) is what makes `CefRunMessageLoop()` in `main()` return, which is the actual signal that the process is ready for `CefShutdown()`. Everything upstream of it in the full protocol this doc's scope describes (save coordinator flush, window/app state persistence) is still Wave 5+ scope and was not part of this proof. -## Evidence-link discipline note +## Outline (remaining — not yet done) -Per roadmap §61.1.4, this section is a placeholder for the *real* invariant, which must link to: the test that proves it → the CI job that runs it → this doc. The finding above has none of those yet — it comes from a manual, non-committed, non-CI spike. Do not upgrade the wording above to "clean" as a flat claim until a real test exists in this repo and a CI job runs it. - -## Outline (to be filled in during Wave 2) - -- Subprocess packaging layout for Linux/Windows/macOS as shipped -- The implemented shutdown protocol, step by step, with the actual code paths -- Failure/timeout policy for each shutdown step -- Repeated launch/close cycle test evidence (learning harness) -- Known shutdown hangs encountered during development and their root causes - -## Evidence-link discipline - -Per roadmap §61.1.4, every invariant claimed here should link to: the test that proves it → the CI job that runs the test → this doc. Do not claim shutdown is "clean" without a linked, currently-passing test. +- Subprocess packaging layout for Linux/Windows/macOS **as actually shipped** (this proof used CEF's own unpackaged build-output layout, not a real installer) +- Save-coordinator flush and window/application-state persistence steps — Wave 5+ scope, genuinely unimplemented, not just untested +- Failure/timeout policy for each shutdown step (this proof has grace periods for *its own test assertions*, not a documented production timeout policy) +- Windows/macOS subprocess-launch and shutdown evidence — this proof is Linux-only +- Known shutdown hangs encountered during development and their root causes — none encountered in this proof once the ICU/cwd bug above was fixed, but this is one CI runner, one CEF version, one run count From 916a20a4816893cfb352ee9856615f5050ff38da Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Wed, 19 Aug 2026 00:17:40 +0200 Subject: [PATCH 2/2] fix(docs): correct 4 overclaims in the Wave 2 evidence-flip PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit/Qodo review findings — precision fixes in my own new prose: - CEF-RUST-COMPETENCY-MATRIX.md: unchecked "renderer termination observed and handled" — PR #388 exercised normal shutdown only, no test deliberately terminates/crashes a renderer. Gate count 5/12 -> 4/12. - Renamed "Subprocess packaging proven" to "Unpackaged CEF resource layout proven" (and softened the same claim in the domains table) — what's actually proven is CEF's own unpackaged build-output layout copying correctly, not real shipped/installer packaging, which both linked docs already correctly caveat as separate, later scope. - subprocess-and-shutdown.md: removed the false "took measurably longer to be reaped" claim — the harness waits a fixed grace period and performs one orphan check; it never measures actual reaping duration. - OWNERSHIP.yaml: commented out `cef-competency-gate` from related_ci on both entries that listed it — no such CI workflow/job exists yet. Co-Authored-By: Claude Sonnet 5 --- docs/cef/CEF-RUST-COMPETENCY-MATRIX.md | 8 ++++---- docs/cef/OWNERSHIP.yaml | 4 ++-- docs/cef/knowledge/subprocess-and-shutdown.md | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/cef/CEF-RUST-COMPETENCY-MATRIX.md b/docs/cef/CEF-RUST-COMPETENCY-MATRIX.md index 23935248..a5b0f20c 100644 --- a/docs/cef/CEF-RUST-COMPETENCY-MATRIX.md +++ b/docs/cef/CEF-RUST-COMPETENCY-MATRIX.md @@ -24,7 +24,7 @@ CI validation of this block ("fail CI when a required item for the active progra | Domain | Status | Evidence | |---|---|---| -| CEF architecture (process model, browser/frame/client ownership, message loop, shutdown ordering, subprocess packaging, sandbox expectations) | Partial | Process model, message loop, shutdown ordering, and subprocess packaging all have real working code + CI proof (`apps/desktop-cef/`, PR #388) — but no dedicated architecture-primer doc exists yet (`docs/cef/knowledge/cef-architecture-primer.md` still skeleton), and sandbox expectations have zero evidence. | +| CEF architecture (process model, browser/frame/client ownership, message loop, shutdown ordering, subprocess packaging, sandbox expectations) | Partial | Process model, message loop, and shutdown ordering all have real working code + CI proof (`apps/desktop-cef/`, PR #388). Subprocess *resource layout* (unpackaged CEF build output — `COPY_FILES`) is confirmed, but real shipped/installer packaging is separate, unproven, later scope. No dedicated architecture-primer doc exists yet (`docs/cef/knowledge/cef-architecture-primer.md` still skeleton), and sandbox expectations have zero evidence. | | CEF threading & lifetime rules (UI-thread callbacks, IO thread, ref-counted objects, callback lifetime, async cancellation, shutdown races) | Partial | `CEF_REQUIRE_UI_THREAD()` used throughout; `IMPLEMENT_REFCOUNTING`/`CefRefPtr` applied correctly; a real callback-lifetime lesson learned and fixed (`base::Unretained` vs. a plain `CefTask` — see `apps/desktop-cef/src/worldscript_handler.cpp`). No dedicated review doc yet (`docs/cef/knowledge/threading-and-lifetimes.md` still skeleton); IO thread and async-cancellation patterns untouched. | | Rust binding layer (crate/version, unsafe/FFI boundary, wrapper ownership, API coverage gaps, upgrade procedure) | Partial | `apps/desktop-cef/rust-core/` (`worldscript_rust_core`, Corrosion-linked) — FFI boundary proven inside the real CEF host in CI (PR #388), not just an isolated test. No upgrade procedure written yet (`docs/cef/knowledge/binding-upgrade-playbook.md` still skeleton); API coverage is currently one trivial function, not representative of real surface area. | | Cross-platform native host (Linux loader/resource layout, Windows process/installer/sandbox, macOS bundle/signing, window lifecycle, high-DPI, IME/a11y) | Partial (Linux only) | Linux loader/resource layout confirmed via a real filesystem listing in CI (`docs/cef/knowledge/linux-runtime-notes.md`); a real cwd-relative-path startup bug found and fixed. Zero Windows/macOS evidence. Window lifecycle proven for open/close only — high-DPI and IME/a11y untouched. | @@ -39,7 +39,7 @@ CI validation of this block ("fail CI when a required item for the active progra [ ] CEF reference-count/lifetime rules documented (same — same caveat) [ ] Rust binding unsafe surface reviewed (trivial surface so far, not representative) [ ] Binding API gaps catalogued -[x] Subprocess packaging proven — PR #388, real filesystem listing in CI +[x] Unpackaged CEF resource layout proven — PR #388, real filesystem listing in CI (real shipped/installer packaging remains separate, unproven, later scope) [x] Repeated startup/shutdown harness green — PR #388, 3/3 cycles, cef-learning-harness CI job [ ] Renderer crash observation green [ ] Accessibility smoke green @@ -59,7 +59,7 @@ CI validation of this block ("fail CI when a required item for the active progra [x] unsafe/FFI boundary identified — apps/desktop-cef/rust-core/, proven in CI (PR #388) [ ] threading/lifetime map reviewed (no dedicated doc yet — see domains table) [x] clean repeated startup/shutdown proven — PR #388, 3/3 cycles, cef-learning-harness CI job -[x] renderer termination observed and handled — PR #388's subprocess-reaping grace-period finding +[ ] renderer termination observed and handled (not proven — PR #388 exercised normal shutdown only; no test deliberately terminates/crashes a renderer, per Qodo review finding on PR #389) [ ] sandbox development plan validated [ ] Linux runtime dependencies inventoried (inventoried but not yet proven sufficient — see native-readiness.md) [ ] at least one accessibility smoke test performed @@ -67,7 +67,7 @@ CI validation of this block ("fail CI when a required item for the active progra [ ] upgrade playbook exists ``` -This gate is **not** satisfied yet — 5 of 12 items checked, several with explicit caveats above. `WS-CEF-IPC` (Wave 4) remains blocked. +This gate is **not** satisfied yet — 4 of 12 items checked, several with explicit caveats above. `WS-CEF-IPC` (Wave 4) remains blocked. ## What this snapshot (Wave 2, 2026-08-18/19) does NOT claim diff --git a/docs/cef/OWNERSHIP.yaml b/docs/cef/OWNERSHIP.yaml index 40287f1d..fbdc0649 100644 --- a/docs/cef/OWNERSHIP.yaml +++ b/docs/cef/OWNERSHIP.yaml @@ -54,7 +54,7 @@ documents: review_days: 90 related_ci: - cef-learning-harness - - cef-competency-gate + # cef-competency-gate: no such CI workflow/job exists yet — planned, not implemented (CodeRabbit review finding on PR #389). Re-add once it's a real job. driftCheckTool: "planned — not implemented, see Wave 1" note: "Updated in place for Wave 2 (PR #386/#387/#388) — 2 of 7 cef_competency items now true with linked evidence; competency gate still not satisfied (5/12)." @@ -123,7 +123,7 @@ documents: review_days: 90 related_ci: - cef-learning-harness - - cef-competency-gate + # cef-competency-gate: no such CI workflow/job exists yet — planned, not implemented (CodeRabbit review finding on PR #389). Re-add once it's a real job. driftCheckTool: "planned — not implemented, see Wave 1" note: "Skeleton only — Status: Not started" diff --git a/docs/cef/knowledge/subprocess-and-shutdown.md b/docs/cef/knowledge/subprocess-and-shutdown.md index 6303a2dc..fd41a636 100644 --- a/docs/cef/knowledge/subprocess-and-shutdown.md +++ b/docs/cef/knowledge/subprocess-and-shutdown.md @@ -10,7 +10,7 @@ **Test → CI job → this doc**, per §61.1.4's own worked example: [`scripts/cef/run-launch-cycle-proof.mjs`](../../../scripts/cef/run-launch-cycle-proof.mjs) → the `🧪 CEF host build, dependency inventory, launch-cycle proof` job in [`.github/workflows/cef-learning-harness.yml`](../../../.github/workflows/cef-learning-harness.yml) → this section. - **Graceful shutdown is implemented and proven, not just OS-forced.** [`apps/desktop-cef/src/shutdown_signal.h`/`.cpp`](../../../apps/desktop-cef/src/shutdown_signal.cpp) installs an async-signal-safe SIGTERM/SIGINT handler (a `sig_atomic_t` flag only — CEF APIs are not async-signal-safe). `WorldScriptHandler` polls that flag from the UI thread via a `CefTask` (`PollShutdownFlag`, [`worldscript_handler.cpp`](../../../apps/desktop-cef/src/worldscript_handler.cpp)) and calls `TryCloseBrowser()` on every tracked browser when set — the real `CanClose`/`DoClose`/`OnBeforeClose` → `CefQuitMessageLoop()` → `CefShutdown()` protocol actually runs. The CI log shows `signal=null` (a genuine self-initiated exit via `return 0` in `main()`), not `signal=SIGTERM` (an OS-forced kill) — direct evidence the graceful path executed, not just that the OS could terminate the process. -- **Shutdown after SIGTERM is still not instantaneous**, confirmed again under CI: the harness allows a 6s grace period for the main process to exit after SIGTERM, then an *additional* ~3s grace period specifically for subprocess reaping before checking for orphans — a real subprocess (renderer, spawned for the first time once the ICU/cwd startup bug below was fixed) took measurably longer to be reaped than its parent. +- **Shutdown after SIGTERM is still not instantaneous**, consistent with the original spike finding: the harness allows a 6s grace period for the main process to exit after SIGTERM, then waits an *additional*, fixed ~3s grace period before performing a single `processTreeAlive()` orphan check — added after an early version of this proof (checking immediately) reported a false orphan on the first real run that spawned a renderer subprocess (once the ICU/cwd startup bug below was fixed). The harness does not measure actual reaping duration, only whether a fixed buffer was sufficient. - **3 repeated start → SIGTERM → close cycles, each independently verified clean** (not aggregated across the run — an earlier version of this harness could mask a later cycle's failure behind an earlier success; fixed before merge) — every cycle showed a clean process tree via an anchored `pgrep` check, the FFI boundary proof (`rust_core ping = 424242` from `OnAfterCreated`, deterministic regardless of page content), and the real rendering proof (`title = WorldScript Studio` from `OnTitleChange` — a CEF error page would not produce this exact title). - **A real startup bug found and fixed en route, unrelated to shutdown but worth recording here**: `icu_util.cc: Invalid file descriptor to ICU data received` crashed the host within ~200ms of every launch, despite `icudtl.dat` being correctly present next to the executable — root cause was the *working directory* the process was launched from (Chromium resolves several resource paths relative to cwd, not the executable's own location), not a packaging bug. Fixed by setting `cwd` to the binary's own directory when spawning it. - `WorldScriptHandler::OnBeforeClose` calling `CefQuitMessageLoop()` only once the last tracked browser closes (the standard `cefsimple` pattern) is what makes `CefRunMessageLoop()` in `main()` return, which is the actual signal that the process is ready for `CefShutdown()`. Everything upstream of it in the full protocol this doc's scope describes (save coordinator flush, window/app state persistence) is still Wave 5+ scope and was not part of this proof.