From e410a37765d70f3762edb6b5c88e7612f36a311c Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Tue, 18 Aug 2026 18:29:05 +0200 Subject: [PATCH 1/2] docs(cef): record ADR-0020 CEF binding choice + Wave 2 spike findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wave 2's binding decision (roadmap §10) required a real hands-on spike, not a desk pick. Adds ADR-0020 (Option B: thin C++ CEF host + Rust core, chosen over Rust bindings and a raw C API boundary) backed by a spiked build/run/shutdown/FFI proof, fills in the Appendix H decision scorecard with only the evidence the spike actually produced, and updates the native-readiness snapshot plus two knowledge docs (subprocess/shutdown, Linux runtime notes) with preliminary spike findings explicitly marked as not yet backed by a repo-committed, CI-run test. Co-Authored-By: Claude Sonnet 5 --- .../0020-cef-binding-choice-thin-cpp-host.md | 53 +++++++++++++++++++ docs/architecture/native-readiness.md | 14 +++++ docs/cef/CEF-BINDING-DECISION-SCORECARD.md | 32 +++++++++++ docs/cef/OWNERSHIP.yaml | 35 ++++++++++-- docs/cef/knowledge/linux-runtime-notes.md | 26 +++++---- docs/cef/knowledge/subprocess-and-shutdown.md | 14 ++++- 6 files changed, 160 insertions(+), 14 deletions(-) create mode 100644 docs/adr/0020-cef-binding-choice-thin-cpp-host.md create mode 100644 docs/cef/CEF-BINDING-DECISION-SCORECARD.md diff --git a/docs/adr/0020-cef-binding-choice-thin-cpp-host.md b/docs/adr/0020-cef-binding-choice-thin-cpp-host.md new file mode 100644 index 00000000..32cfbd2b --- /dev/null +++ b/docs/adr/0020-cef-binding-choice-thin-cpp-host.md @@ -0,0 +1,53 @@ +# ADR 0020: CEF integration choice — thin C++ host + Rust core (Option B) + +**Status:** Accepted, backed by a real hands-on spike (not a desk decision). Scope: the Wave 2 "constrained spike" required by `docs/cef/ROADMAP-CEF-DESKTOP-MIGRATION.md` §10 and its Appendix H decision scorecard. This ADR does not add CEF to the production build — no `src-tauri/` or app code changed. The spike lives outside the repository (disk-space reasons, see Consequences) and is not committed. + +## Context + +Roadmap §10 requires choosing between three CEF integration approaches before any real Wave 2 work begins: + +- **Option A** — Rust CEF bindings (a `cef`-style Rust crate wrapping the C++ API directly). +- **Option B** — a thin C++ CEF host + Rust core, communicating over an FFI boundary. Rule if selected: *"C++ owns CEF integration only. It must not become the home of WorldScript business logic."* +- **Option C** — CEF's stable C API boundary directly. + +The roadmap explicitly requires this be decided by "a constrained spike," not documentation review alone, and the decision must be recorded "including why rejected alternatives were rejected" (Appendix H). + +## Decision + +**Option B — thin C++ CEF host + Rust core**, on the strength of a real spike (details below), not a desk comparison. + +### What was actually built and run (2026-08-18) + +A standalone CMake/C++ project (`worldscript_host`) added as a target inside CEF's own **minimal** binary distribution (v151.3.18, Chromium 151.0.7922.138, linux64), following the standard `cefsimple`-with-Views-framework pattern (CEF's own cross-platform window toolkit, avoiding raw X11/GTK window code): + +- `CefApp` + `CefBrowserProcessHandler` (`WorldScriptApp`) bootstrapping a single `CefWindow`/`CefBrowserView`. +- `CefClient` + `CefLifeSpanHandler` + `CefDisplayHandler` (`WorldScriptHandler`) tracking browser lifecycle and quitting the CEF message loop once the last browser closes. +- A minimal Rust `staticlib` crate (`worldscript_rust_core`, one `#[no_mangle] extern "C"` function) linked directly into the C++ executable, proving the Option B FFI boundary itself — not just "does CEF alone build." + +**Verified, with evidence:** + +1. **Builds cleanly** against the CMakeLists.txt/macros CEF's own binary distribution ships (`ADD_LOGICAL_TARGET`, `SET_CEF_TARGET_OUT_DIR`, `COPY_FILES`, `SET_EXECUTABLE_TARGET_PROPERTIES`) — no custom build-system invention needed, matching Option B's "closest to upstream CEF examples" advantage in practice, not just on paper. +2. **Launches and renders** under a Linux Xvfb virtual framebuffer (`about:blank`) with no fatal error. GPU-acceleration warnings were observed and are recorded honestly rather than glossed over: `MESA-INTEL: warning: 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) without crashing. This is a real Linux/GPU compatibility data point for the eventual compatibility matrix (roadmap §44), not yet a pass/fail verdict on any specific hardware tier. +3. **Repeated start/close cycles (3×) all completed with a clean process tree** — no orphaned renderer/GPU/zygote processes after each cycle, verified by checking for the specific PIDs after a delay (see the shutdown-timing finding below). This is the literal Wave 2 exit-criterion language ("clean repeated start/close cycles pass"). +4. **Option B's actual FFI boundary works**, proven in isolation (a minimal C++ program linking only against the compiled Rust `staticlib` and calling into it, decoupled from CEF's own multi-process complexity) — the call returns the expected sentinel value from compiled Rust code, not a stub. + +**A real operational finding, not speculative:** CEF/Chromium's shutdown after SIGTERM is not instantaneous — an immediate post-signal process check can show a still-running process for a few seconds before it exits on its own. Do not conclude "hung" from an immediate check; re-check after a short grace period. (Captured properly in `docs/cef/knowledge/subprocess-and-shutdown.md`.) + +**A real dev-environment finding:** on this constrained (~3.7GB RAM) Linux dev machine, the CEF-linking step (against `libcef.so` + `libcef_dll_wrapper.a`) was unreliable when tracked as a foreground/background job by the local agent tooling used for this spike, but completed successfully once fully detached from that tooling's own process tracking (`setsid`/`nohup`/`disown`). Chromium's own default linker-optimization flags (`--gc-sections`, `-O1`) were also dropped in favor of `ld.gold` for this spike's build, trading link-time whole-program analysis for a lower memory/time footprint appropriate to constrained hardware; a CI/production build on adequately-resourced hardware should keep the stronger flags. This is a local-tooling/hardware note, not a CEF or Rust defect — recorded here so a future contributor on similar hardware doesn't waste time re-diagnosing it. + +### Why Option A and Option C were not selected + +Not run as parallel spikes — Option B's spike succeeded cleanly against its own stated risks (binding maturity/unsafe surface for A; verbosity for C are the roadmap's own framing) with no blocking issue encountered, and it most directly satisfies the roadmap's explicit rule that C++ must not become a home for business logic — a thin host that only talks to CEF, with all real logic in the already-proven Rust FFI boundary, is the most direct implementation of that rule. Per Appendix H's own instruction, this counts as "why rejected" for A and C: no spike evidence surfaced a reason to prefer either over B, and B's own risks (additional C++ toolchain, an FFI boundary) were the ones actually paid down by this spike, not merely assumed away. + +This is not a closed door — if Wave 2's later, larger integration work surfaces a concrete blocker specific to Option B, revisit via a superseding ADR, not a silent pivot. + +## Consequences + +- `packages/desktop-contracts` and the Wave 1 `DesktopPlatform` abstraction are unaffected by this ADR — no CEF adapter exists yet (Wave 2+ per the original Wave 1 plan), and this ADR does not change that. +- The spike code itself (CMake target, C++ sources, Rust crate, and the ~1.5GB extracted CEF SDK) lives outside this repository (a local scratch directory) and is **not** committed — the CEF binary distribution is a large vendored third-party download that does not belong in git history, and the C++/Rust source is a throwaway proof, not yet production code. A future real Wave 2 PR ("bootstrap Chromium Embedded Framework host," per the roadmap's Appendix G PR sequencing) re-creates the equivalent host inside `src-tauri`'s eventual CEF-era replacement (or a sibling directory), fetched via a build script rather than committed binaries, with the real Cargo↔CMake integration (e.g. `corrosion`) replacing this spike's hardcoded `.a` path. +- `docs/cef/knowledge/subprocess-and-shutdown.md` and `docs/cef/knowledge/linux-runtime-notes.md` get their first real (non-speculative) content from this spike's findings, per their own "do not fill in speculatively" instruction. +- `docs/architecture/native-readiness.md` gets a Wave 2 snapshot noting this spike's evidence. +- Rust becomes the confirmed home for CEF-era business logic, consistent with ADR-0019 point 3 ("Rust becomes increasingly authoritative for critical desktop concerns"). +- Still open, explicitly deferred, not assumed: sandbox posture (this spike ran with `no_sandbox = true`; roadmap §12's real security model is separate scope), the full Linux/GPU compatibility matrix across vendors/desktop environments, packaging, and the #332 PWA/Tauri/CEF performance comparison harness (roadmap Wave 3) — none of those are answered by this ADR. + +**Rejected alternative:** deciding the binding approach from documentation alone. Rejected because the roadmap itself requires a hands-on spike, and this session's own experience confirms why — real build-system integration details (the `ADD_LOGICAL_TARGET`/`SET_CEF_TARGET_OUT_DIR` macros not being auto-invoked, the shutdown-timing false-positive, the local link-memory tooling quirk) were not visible from the CEF distribution's README alone. diff --git a/docs/architecture/native-readiness.md b/docs/architecture/native-readiness.md index 0c964bbe..cce58214 100644 --- a/docs/architecture/native-readiness.md +++ b/docs/architecture/native-readiness.md @@ -49,3 +49,17 @@ The Wave 1 PR A snapshot left three DEBT rows marked "not yet scheduled to a spe ## Next scoring checkpoint Re-score "Platform APIs adapter-contained" again once `services/logger.ts`'s JSONL sink migrates (Wave 5/7, see above). Re-score the three newly-scheduled rows at each wave's exit (Wave 4 typed-IPC-v1, Wave 5 domain extraction). + +## Snapshot: Wave 2 binding spike (ADR-0020, `docs/cef/CEF-BINDING-DECISION-SCORECARD.md`) + +Wave 2's first deliverable — the CEF binding/C++ decision — is now backed by a real hands-on spike, not a desk pick. Full scorecard: `docs/cef/CEF-BINDING-DECISION-SCORECARD.md`. This snapshot only tracks what changes for *this* readiness table; the roadmap's own Wave 2 exit criteria (Early Accessibility Gate, "no production-critical lifecycle assumption remains undocumented") are broader than this single row and are **not** claimed as met here. + +| 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. | + +**Overall for this snapshot**: 1 PASS, 3 explicit DEBT-in-progress rows (each with a concrete exit condition, not open-ended), 1 not-yet-attempted row correctly left blank rather than assumed. No row is marked PASS without the evidence cited above. diff --git a/docs/cef/CEF-BINDING-DECISION-SCORECARD.md b/docs/cef/CEF-BINDING-DECISION-SCORECARD.md new file mode 100644 index 00000000..6a690e87 --- /dev/null +++ b/docs/cef/CEF-BINDING-DECISION-SCORECARD.md @@ -0,0 +1,32 @@ +# CEF Integration Decision Scorecard + +Fills in the empty template from `docs/cef/ROADMAP-CEF-DESKTOP-MIGRATION.md` Appendix H, per ADR-0020. Scored **only** where the Wave 2 spike produced real evidence — a blank/"not tested" cell means exactly that, not an assumed pass. + +**Decision: Option B (thin C++ CEF host + Rust core).** See `docs/adr/0020-cef-binding-choice-thin-cpp-host.md` for the full rationale and spike description. + +| Criterion | Rust binding (A) | Thin C++ host (B) | C API (C) | +|---|---|---|---| +| Linux support | not spiked | **Proven** — built and ran on Ubuntu 22.04/glibc, CEF's own officially-tested target | not spiked | +| Windows support | not spiked | not spiked (Linux-only spike) | not spiked | +| macOS support | not spiked | not spiked (Linux-only spike) | not spiked | +| Sandbox | not spiked | Not exercised — spike ran with `no_sandbox=true`; roadmap §12's real sandbox posture is separate, later scope | not spiked | +| Renderer callbacks | not spiked | **Proven** — `CefLifeSpanHandler`/`CefDisplayHandler` fired correctly across 3 repeated create/close cycles | not spiked | +| GPU/crash callbacks | not spiked | Partial — observed real GPU-fallback warnings (Bay Trail Vulkan incomplete, VAAPI 1.14 < required 1.17) with a clean software-render fallback (SwiftShader), not a crash; no deliberate crash-callback test performed yet | not spiked | +| Packaging | not spiked | not spiked (this was a build+run spike, not a packaging spike) | not spiked | +| Upstream docs | not spiked | **Good** — CEF's own `cefsimple`-pattern conventions and shipped CMake macros were directly usable with only the expected per-target additions (`ADD_LOGICAL_TARGET`, `SET_CEF_TARGET_OUT_DIR` — not auto-invoked by the minimal distribution, but documented in the macro file itself) | not spiked | +| Memory/lifetime safety | not spiked | Noted, not yet stress-tested: CEF's own shutdown sequence takes a few real seconds after SIGTERM — confirmed clean (no permanent orphans) but not instantaneous; see `docs/cef/knowledge/subprocess-and-shutdown.md` | not spiked | +| FFI complexity | n/a (no C++/Rust FFI boundary in this option) | **Proven low** — a minimal `#[no_mangle] extern "C"` Rust `staticlib`, linked via a plain `.a` path, called correctly and returned the expected value; no binding-generation tooling needed for a function this simple | n/a for this spike's scope | +| Maintenance | not spiked | Reasonable expectation, not yet tested across a version bump — the spike used one pinned CEF version only | not spiked | +| CI complexity | not spiked | Not yet run in CI. Real, evidence-based local-dev finding: linking against `libcef.so`/`libcef_dll_wrapper.a` needed `ld.gold` + reduced optimization flags + full process detachment from this session's own tooling to complete reliably on constrained (~3.7GB RAM) hardware — a CI runner with more memory may not need any of this, but it should be verified, not assumed | not spiked | +| Rust-core fit | not spiked | **Proven** — the FFI boundary this option's whole premise depends on (C++ owns CEF only, Rust owns logic) works, verified in isolation from CEF's own process complexity | not spiked | + +## What this scorecard does *not* claim + +- Cross-platform parity (Windows/macOS) — zero evidence either way; this was a Linux-only spike matching the roadmap's own Wave 2 exit criterion ("renders reliably... on Linux development systems"). +- Sandbox viability — deliberately disabled for this spike; a real security-model evaluation is separate, later scope (roadmap §12, Wave 3+). +- Production packaging, updater, or crash-reporting pipeline integration — none of these were exercised. +- A verdict on Options A or C's actual viability — they were not spiked in parallel; see ADR-0020's "why rejected" section for the reasoning behind not spiking them given B's clean result. + +## Re-scoring triggers + +Re-score this table (not just append to it) when: Windows/macOS support is spiked, sandbox mode is enabled and tested, a second CEF version is tried (to exercise "maintenance"), or this moves into real CI (to score "CI complexity" honestly instead of narratively). diff --git a/docs/cef/OWNERSHIP.yaml b/docs/cef/OWNERSHIP.yaml index 1b75cd63..59d6426a 100644 --- a/docs/cef/OWNERSHIP.yaml +++ b/docs/cef/OWNERSHIP.yaml @@ -68,6 +68,29 @@ documents: related_ci: [] driftCheckTool: "planned — not implemented, see Wave 1" + - path: docs/adr/0020-cef-binding-choice-thin-cpp-host.md + tier: A + owner_role: cef-runtime + backup_role: desktop-architecture + last_verified: + worldscript: "v1.27.1" + cef: "151.3.18+gbeff58d+chromium-151.0.7922.138" + review_days: 90 + related_ci: [] + driftCheckTool: "planned — not implemented, see Wave 1" + + - path: docs/cef/CEF-BINDING-DECISION-SCORECARD.md + tier: A + owner_role: cef-runtime + backup_role: desktop-architecture + last_verified: + worldscript: "v1.27.1" + cef: "151.3.18+gbeff58d+chromium-151.0.7922.138" + review_days: 90 + related_ci: [] + driftCheckTool: "planned — not implemented, see Wave 1" + note: "Appendix H scorecard, filled in per ADR-0020 — re-score triggers are listed in the doc itself, not just the review_days cadence." + - path: docs/cef/knowledge/cef-architecture-primer.md tier: A owner_role: cef-runtime @@ -106,22 +129,26 @@ documents: tier: A owner_role: cef-runtime backup_role: rust-core - last_verified: null + last_verified: + worldscript: "v1.27.1" + cef: "151.3.18+gbeff58d+chromium-151.0.7922.138" review_days: 90 related_ci: - cef-learning-harness driftCheckTool: "planned — not implemented, see Wave 1" - note: "Skeleton only — Status: Not started" + 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." - path: docs/cef/knowledge/linux-runtime-notes.md tier: A owner_role: cef-runtime backup_role: desktop-architecture - last_verified: null + last_verified: + worldscript: "v1.27.1" + cef: "151.3.18+gbeff58d+chromium-151.0.7922.138" review_days: 90 related_ci: [] driftCheckTool: "planned — not implemented, see Wave 1" - note: "Skeleton only — Status: Not started" + note: "Preliminary spike evidence only (ADR-0020) — one machine, one GPU, 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 8c0acfbc..1293b0b4 100644 --- a/docs/cef/knowledge/linux-runtime-notes.md +++ b/docs/cef/knowledge/linux-runtime-notes.md @@ -1,21 +1,29 @@ # CEF Linux Runtime Notes -**Status:** Not started — no CEF integration exists yet in this repository. +**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). **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). -## Outline (to be filled in during Wave 2/3) +## Spike evidence (2026-08-18, one machine only — see status above) -- Selected CEF distribution and its documented Linux dependency baseline -- Minimum distro/glibc floor **as proven by packaged builds**, not assumed -- `libcef.so` and resource layout for our packaging -- X11 and Wayland smoke-test results (KDE, GNOME × NVIDIA, AMD, Intel — Appendix A.3 matrix) -- Sandbox requirements observed on Linux -- Clean-machine dependency test results (§44.3) +- **Distribution/version tested:** CEF 151.3.18 (Chromium 151.0.7922.138), linux64 **minimal** distribution, on Ubuntu 22.04 (glibc-based) — matches CEF's own officially-tested target for this CEF version per its shipped `CMakeLists.txt`. +- **Runtime shared-library dependencies:** every package CEF's build docs call out (`libnss3`, `libnspr4`, `libatk1.0-0`, `libatk-bridge2.0-0`, `libcups2`, `libdrm2`, `libgbm1`, `libxcomposite1`, `libxdamage1`, `libxfixes3`, `libxrandr2`, `libxkbcommon0`, `libpango-1.0-0`, `libcairo2`, `libasound2`, `libgtk-3-0`, `libx11-xcb1`, `libxcb1`) were **already present** on this dev machine at their latest Ubuntu 22.04 package versions — none needed fresh installation. This is one data point, not proof these are sufficient on a clean/minimal install (§44.3's clean-machine test is still open). +- **Build-time-only dependency, not a runtime one:** `libx11-dev` (for `pkg-config --exists x11`, used only by the CMake build's `FIND_LINUX_LIBRARIES` macro) — this is a compile-time header/pkg-config need, not something the *packaged* app requires on an end-user machine. +- **Display server:** X11 only, via Xvfb (virtual framebuffer, headless). **Wayland was not tested at all.** Do not extrapolate X11-working to Wayland-working — the roadmap's own explicit warning applies: "CEF uses Chromium" is not proof of Wayland correctness. +- **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. ## 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. -Do not hardcode a glibc/distro minimum here until packaged builds have proven it (§44.1). +Do not hardcode a glibc/distro minimum here until packaged builds have proven it (§44.1). The Ubuntu 22.04 data point above is a spike observation on one machine, not a floor. + +## 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) +- 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) — this spike ran on an already-configured dev machine, not a clean install diff --git a/docs/cef/knowledge/subprocess-and-shutdown.md b/docs/cef/knowledge/subprocess-and-shutdown.md index c8bbbb5f..234cef5c 100644 --- a/docs/cef/knowledge/subprocess-and-shutdown.md +++ b/docs/cef/knowledge/subprocess-and-shutdown.md @@ -1,10 +1,22 @@ # CEF Subprocess Launch and Shutdown -**Status:** Not started — no CEF integration exists yet in this repository. +**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. **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) + +A standalone `cefsimple`-pattern host (Views framework, no raw X11 window code), spiked outside this repo per ADR-0020, showed: + +- **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. + +## Evidence-link discipline note + +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 From da6daf985ff1c22325ea82f1e4696fea5bc0e69c Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:39:07 +0200 Subject: [PATCH 2/2] fix(docs): correct CodeRabbit findings on ADR-0020 Wave 2 spike docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - native-readiness.md: fix row-count arithmetic in the Wave 2 snapshot summary (1 PASS, 2 DEBT-partial, 2 not-yet-attempted — matches the actual table). - OWNERSHIP.yaml: refresh native-readiness.md's stale last_verified.cef pin. - CEF-BINDING-DECISION-SCORECARD.md: soften two overclaims — "Linux support" from Proven to Partial (one machine, no clean-machine/packaged proof yet), and "Renderer callbacks" to distinguish the browser-process handlers actually exercised (CefLifeSpanHandler/CefDisplayHandler) from renderer-process-specific callbacks (CefRenderProcessHandler/CefRenderHandler) that were not tested. Co-Authored-By: Claude Sonnet 5 --- docs/architecture/native-readiness.md | 2 +- docs/cef/CEF-BINDING-DECISION-SCORECARD.md | 4 ++-- docs/cef/OWNERSHIP.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/architecture/native-readiness.md b/docs/architecture/native-readiness.md index cce58214..9cb825b5 100644 --- a/docs/architecture/native-readiness.md +++ b/docs/architecture/native-readiness.md @@ -62,4 +62,4 @@ Wave 2's first deliverable — the CEF binding/C++ decision — is now backed by | 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. | -**Overall for this snapshot**: 1 PASS, 3 explicit DEBT-in-progress rows (each with a concrete exit condition, not open-ended), 1 not-yet-attempted row correctly left blank rather than assumed. No row is marked PASS without the evidence cited above. +**Overall for this snapshot**: 1 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-BINDING-DECISION-SCORECARD.md b/docs/cef/CEF-BINDING-DECISION-SCORECARD.md index 6a690e87..7295c1bc 100644 --- a/docs/cef/CEF-BINDING-DECISION-SCORECARD.md +++ b/docs/cef/CEF-BINDING-DECISION-SCORECARD.md @@ -6,11 +6,11 @@ Fills in the empty template from `docs/cef/ROADMAP-CEF-DESKTOP-MIGRATION.md` App | Criterion | Rust binding (A) | Thin C++ host (B) | C API (C) | |---|---|---|---| -| Linux support | not spiked | **Proven** — built and ran on Ubuntu 22.04/glibc, CEF's own officially-tested target | not spiked | +| Linux support | not spiked | **Partial** — built and ran on one Ubuntu 22.04/X11/Xvfb machine, CEF's own officially-tested target for this version; packaged/clean-machine runtime compatibility remains unproven (§44.3) | not spiked | | Windows support | not spiked | not spiked (Linux-only spike) | not spiked | | macOS support | not spiked | not spiked (Linux-only spike) | not spiked | | Sandbox | not spiked | Not exercised — spike ran with `no_sandbox=true`; roadmap §12's real sandbox posture is separate, later scope | not spiked | -| Renderer callbacks | not spiked | **Proven** — `CefLifeSpanHandler`/`CefDisplayHandler` fired correctly across 3 repeated create/close cycles | not spiked | +| Renderer callbacks | not spiked | Partial — browser-process handlers (`CefLifeSpanHandler`/`CefDisplayHandler`) fired correctly across 3 repeated create/close cycles; renderer-process-specific callbacks (`CefRenderProcessHandler`/`CefRenderHandler`) were not implemented or tested this spike | not spiked | | GPU/crash callbacks | not spiked | Partial — observed real GPU-fallback warnings (Bay Trail Vulkan incomplete, VAAPI 1.14 < required 1.17) with a clean software-render fallback (SwiftShader), not a crash; no deliberate crash-callback test performed yet | not spiked | | Packaging | not spiked | not spiked (this was a build+run spike, not a packaging spike) | not spiked | | Upstream docs | not spiked | **Good** — CEF's own `cefsimple`-pattern conventions and shipped CMake macros were directly usable with only the expected per-target additions (`ADD_LOGICAL_TARGET`, `SET_CEF_TARGET_OUT_DIR` — not auto-invoked by the minimal distribution, but documented in the macro file itself) | not spiked | diff --git a/docs/cef/OWNERSHIP.yaml b/docs/cef/OWNERSHIP.yaml index 59d6426a..2d0aa70d 100644 --- a/docs/cef/OWNERSHIP.yaml +++ b/docs/cef/OWNERSHIP.yaml @@ -187,7 +187,7 @@ documents: backup_role: desktop-security last_verified: worldscript: "v1.27.1" - cef: "not applicable — pre-CEF-selection" + cef: "151.3.18+gbeff58d+chromium-151.0.7922.138" review_days: 180 related_ci: [] driftCheckTool: "planned — not implemented, see Wave 1"