Files
one-os-dev-wayland-html5-co…/12-appendix.md
T

340 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 12 — Appendix: Glossary, File Index, References
## Glossary
### Wayland concepts
Same as Greenfield — see `../greenfield-analysis/12-appendix.md` for
the full Wayland glossary. Key terms: `wl_display`, `wl_registry`,
`wl_compositor`, `wl_surface`, `wl_seat`, `wl_keyboard`, `wl_pointer`,
`wl_touch`, `wl_output`, `wl_shm`, `wl_buffer`, `wl_callback`,
`wl_data_device_manager`, `wl_data_device`, `wl_data_source`,
`wl_data_offer`, `wl_drm`, `wl_subcompositor`, `wl_subsurface`,
`wl_region`.
### xdg-shell concepts
Same as Greenfield — `xdg_wm_base`, `xdg_surface`, `xdg_toplevel`,
`xdg_popup`, `xdg_positioner`, `configure`, `ack_configure`.
### MIT-approach-specific terms
| Term | Meaning |
|---|---|
| **Clean-room implementation** | Software written by an engineer who has NOT read the source code of the original (AGPL) implementation. The engineer writes from a behavioral spec produced by a separate person who MAY have read the AGPL source. This protects against derivative-work claims. |
| **Person A (spec author)** | The engineer who writes the behavioral spec. MAY read AGPL source for reference. Does NOT write implementation code. |
| **Person B (implementer)** | The engineer who writes the implementation. MUST NOT read AGPL source. Implements from spec + MIT references only. |
| **SPEC.md** | The behavioral spec artifact (inputs/outputs/edge cases, NO code). Written by Person A. |
| **CLEAN_ROOM_LOG.md** | Legal-defensibility artifact documenting who read AGPL source, who didn't, when, what they referenced. |
| **AFC test** | Abstraction-Filtration-Comparison test, from *Computer Associates v. Altai* (1992). The legal test for derivative-work infringement in software. Even non-literal similarity (SSO: structure, sequence, organization) can be infringing. |
| **AGPL §13** | The network-use clause of AGPL-3.0. Requires offering source to all users interacting with the modified work over a network. The killer clause for proprietary web services. |
| **GPL dynamic-linking exception** | GPL applies to the entire combined work when statically linked. Dynamic linking is more permissive (LGPL allows it from proprietary code). FSF's strict interpretation says loading a GPL .so into a proprietary process contaminates it. |
| **ProxyFD** | JSON descriptor for a file descriptor sent over WebSocket: `{handle, type, host}`. Same as Greenfield — see `../greenfield-analysis/04-transport.md`. |
### Python-specific terms
| Term | Meaning |
|---|---|
| **pywayland** | Python bindings to libwayland-server, via cffi. Apache-2.0 licensed. |
| **pywlroots** | Python bindings to libwlroots. NCSA/UIUC license (BSD-like). NOT RECOMMENDED — operates above wire-dispatch layer, incompatible with Greenfield's architecture. |
| **python-xkbcommon** | The `xkbcommon` PyPI package. Python bindings to libxkbcommon. MIT licensed. |
| **PyGObject** | Python bindings to GLib/GObject. LGPL-2.1+. Provides `gi.repository.Gst` for GStreamer. |
| **cffi** | C Foreign Function Interface for Python. Used to call C functions from Python without writing a C extension. |
| **asyncio** | Python's async I/O framework, built into the standard library. |
| **aiohttp** | Async HTTP + WebSocket server framework for Python. Apache-2.0. |
| **multiprocessing.Process** | Python's process-spawning primitive. Used to fork one child per Odoo session. |
| **multiprocessing.reduction.send_handle** | Function to pass an open file descriptor from one Python process to another (uses SCM_RIGHTS on Linux). |
| **GLib MainLoop** | GLib's event loop, required by GStreamer. Runs in a separate Python thread. |
| **asyncio.run_coroutine_threadsafe** | Function to schedule a coroutine on an asyncio event loop from a different thread. Used to marshal GStreamer results back to asyncio. |
| **bubblewrap (bwrap)** | Unprivileged sandboxing tool. LGPL-2.0+. Used by Flatpak. |
| **seccomp BPF** | Linux kernel feature for filtering syscalls. Compiled to BPF bytecode, loaded via `bwrap --seccomp <memfd>`. |
| **systemd-run --scope** | systemd command to run a process in a transient cgroup. Used for memory/CPU/PID limits. |
| **memfd_create** | Linux syscall to create an anonymous in-memory file. Python 3.8+ has `os.memfd_create()`. Replaces Greenfield's `createMemoryMappedFile` native addon. |
### Browser-specific terms
| Term | Meaning |
|---|---|
| **WebGL2** | Next-gen WebGL API. Uniform buffer objects, transform feedback, simplified shaders. 97%+ browser support. |
| **WebCodecs** | W3C standard for native video decode/encode in the browser. `VideoDecoder`, `VideoEncoder`, `EncodedVideoChunk`, `VideoFrame`. Replaces FFmpeg Wasm. |
| **OffscreenCanvas** | W3C standard for canvas rendering in a Web Worker. Allows WebGL to run off the main thread. |
| **Web Workers** | W3C standard for running JavaScript in background threads. |
| **SharedArrayBuffer + Atomics** | W3C standard for zero-copy shared memory between workers. Needs COOP/COEP headers. |
| **ImageBitmap** | W3C standard for a GPU-backed bitmap. Transferable between workers. Used by the `web-bitmapbuf` fast path. |
| **WebTransport** | W3C standard (in progress) for UDP-over-QUIC transport. Future replacement for WebSocket+KCP. |
| **OpenH264** | BSD-2-Clause H.264 codec. Cisco's binary release. Used as fallback when WebCodecs is unavailable. |
## File-to-feature index
### Custom browser compositor (PROPRIETARY, clean-room TS)
| File | Role |
|---|---|
| `packages/compositor/src/index.ts` | Public API: `createCompositorSession()` |
| `packages/compositor/src/core/Session.ts` | Top-level session |
| `packages/compositor/src/core/Compositor.ts` | `wl_compositor` global |
| `packages/compositor/src/core/Globals.ts` | Wayland globals registry |
| `packages/compositor/src/surface/Surface.ts` | `wl_surface`, double-buffered state |
| `packages/compositor/src/surface/SurfaceRole.ts` | Role abstraction |
| `packages/compositor/src/surface/Subsurface.ts` | `wl_subsurface` |
| `packages/compositor/src/surface/Subcompositor.ts` | `wl_subcompositor` global |
| `packages/compositor/src/surface/Region.ts` | `wl_region` (pixman-WASM) |
| `packages/compositor/src/surface/FrameCallback.ts` | `wl_callback` |
| `packages/compositor/src/render/Renderer.ts` | 4-phase render pipeline (WebGL2 + OffscreenCanvas) |
| `packages/compositor/src/render/Scene.ts` | One per output |
| `packages/compositor/src/render/View.ts` | Positioned surface |
| `packages/compositor/src/render/Output.ts` | `wl_output`, OffscreenCanvas binding |
| `packages/compositor/src/render/RenderState.ts` | Per-view-per-scene texture + transform |
| `packages/compositor/src/render/Texture.ts` | WebGL2 texture wrapper |
| `packages/compositor/src/render/Loop.ts` | requestAnimationFrame integration |
| `packages/compositor/src/render/shaders/YUVA2RGBA.glsl` | BT.601 YUVA → RGBA |
| `packages/compositor/src/render/shaders/RGBandA2RGBA.glsl` | RGB+Alpha → RGBA |
| `packages/compositor/src/render/shaders/SceneShader.glsl` | Final pass: textured quads |
| `packages/compositor/src/buffer/Shm.ts` | `wl_shm`, BMP-header hack |
| `packages/compositor/src/buffer/BufferContents.ts` | Buffer abstraction (mimeType) |
| `packages/compositor/src/buffer/ImageBitmapBuffer.ts` | web-bitmapbuf fast path |
| `packages/compositor/src/buffer/EncodedFrameBuffer.ts` | H.264/PNG from proxy |
| `packages/compositor/src/transport/Channel.ts` | ARQChannel + SimpleChannel |
| `packages/compositor/src/transport/kcp.ts` | Ported fresh from MIT C ref (skywind3000/kcp) |
| `packages/compositor/src/transport/ReconnectingWebSocket.ts` | Vendored from pladaria (MIT) |
| `packages/compositor/src/transport/BufferStream.ts` | Serial → frame promise resolution |
| `packages/compositor/src/transport/StreamingBuffer.ts` | Per-surface encoded-frame buffer |
| `packages/compositor/src/transport/EncodedFrame.ts` | Wire format parser |
| `packages/compositor/src/transport/EncoderFeedback.ts` | 4-byte decode feedback, 1 Hz |
| `packages/compositor/src/transport/RemoteInputOutput.ts` | FD-over-WebSocket for native apps |
| `packages/compositor/src/transport/RemoteAppLauncher.ts` | Channel setup per app |
| `packages/compositor/src/transport/decoders/WebCodecsFrameDecoder.ts` | WebCodecs VideoDecoder (HW-accelerated) |
| `packages/compositor/src/transport/decoders/OpenH264FrameDecoder.ts` | OpenH264 BSD Wasm fallback |
| `packages/compositor/src/input/Seat.ts` | `wl_seat` global |
| `packages/compositor/src/input/Keyboard.ts` | `wl_keyboard` |
| `packages/compositor/src/input/Pointer.ts` | `wl_pointer` |
| `packages/compositor/src/input/Touch.ts` | `wl_touch` (REAL implementation, not stub) |
| `packages/compositor/src/input/Xkb.ts` | @gfld/compositor-wasm wrapper (REUSED MIT) |
| `packages/compositor/src/input/InputQueue.ts` | Event coalescing |
| `packages/compositor/src/input/InputOutput.ts` | FD abstraction |
| `packages/compositor/src/roles/XdgWmBase.ts` | `xdg_wm_base` global |
| `packages/compositor/src/roles/XdgSurface.ts` | `xdg_surface` role |
| `packages/compositor/src/roles/XdgToplevel.ts` | `xdg_toplevel` role |
| `packages/compositor/src/roles/XdgPopup.ts` | `xdg_popup` role |
| `packages/compositor/src/roles/XdgPositioner.ts` | `xdg_positioner` |
| `packages/compositor/src/roles/Shell.ts` | `wl_shell` (legacy, optional) |
| `packages/compositor/src/roles/ShellSurface.ts` | `wl_shell_surface` (legacy, optional) |
| `packages/compositor/src/data/DataDeviceManager.ts` | `wl_data_device_manager` |
| `packages/compositor/src/data/DataSource.ts` | `wl_data_source` |
| `packages/compositor/src/data/DataOffer.ts` | `wl_data_offer` |
| `packages/compositor/src/data/PrimarySelectionDeviceManager.ts` | **NEW: zwp_primary_selection_v1** |
| `packages/compositor/src/desktop/Desktop.ts` | Floating vs AlwaysFullScreen |
| `packages/compositor/src/desktop/FloatingDesktopSurface.ts` | Default floating mode |
| `packages/compositor/src/userapi/UserShellApi.ts` | OWL shell integration seam |
| `packages/compositor/src/browser/input.ts` | DOM keyboard events |
| `packages/compositor/src/browser/pointer.ts` | DOM pointer events |
| `packages/compositor/src/browser/touch.ts` | DOM touch events (NEW) |
| `packages/compositor/src/browser/dnd.ts` | DnD bridge (NEW: native→DOM DnD) |
| `packages/compositor/src/browser/selection.ts` | Clipboard bridge |
| `packages/compositor/src/math/Mat4.ts` | 4×4 matrix |
| `packages/compositor/src/math/Rect.ts` | Rectangle math |
### Custom Python proxy (PROPRIETARY, ~2880 LOC)
| File | Role |
|---|---|
| `compositor_proxy/main.py` | HTTP + WS hub, forks per session |
| `compositor_proxy/session.py` | Top-level proxy session |
| `compositor_proxy/session_controller.py` | aiohttp WS server with 9 endpoints |
| `compositor_proxy/jwt_auth.py` | JWT validation (pyjwt) |
| `compositor_proxy/native_app_context.py` | Per-app state, signaling WS, kill timers, bwrap spawn |
| `compositor_proxy/native_wayland_client_session.py` | Per-client message dispatcher |
| `compositor_proxy/native_wayland_compositor_session.py` | Display creation, initShm, initDrm |
| `compositor_proxy/channel.py` | ARQChannel + SimpleChannel (clean-room) |
| `compositor_proxy/kcp_adapter.py` | kcp PyPI package integration |
| `compositor_proxy/frame_feedback.py` | Receives 4-byte decode feedback |
| `compositor_proxy/proxy_buffer.py` | Proxy-side buffer representation |
| `compositor_proxy/surface_buffer_encoding.py` | Encoding pipeline orchestration |
| `compositor_proxy/xwayland_session.py` | XWayland spawn + bridge |
| `compositor_proxy/wayland_server.py` | pywayland wrapper + cffi shim |
| `compositor_proxy/io/` | WebSocket server glue |
| `compositor_proxy/encoding/gst_encoder.py` | GStreamer H.264/PNG encoder (~700 LOC) |
| `compositor_proxy/encoding/adaptive_bitrate.py` | Adaptive bitrate controller (NEW) |
| `compositor_proxy/encoding/glib_thread.py` | GLib MainLoop in separate thread |
| `compositor_proxy/sandbox.py` | bubblewrap + seccomp + systemd-run wrappers |
### Reused from Greenfield (MIT/Apache)
| Path | Role |
|---|---|
| `greenfield/protocol/wayland.xml` | Upstream Wayland core (MIT) |
| `greenfield/protocol/xdg-shell.xml` | Stable xdg-shell (MIT) |
| `greenfield/protocol/wayland-drm.xml` | Legacy wl_drm (MIT) |
| `greenfield/protocol/web-bitmapbuf-unstable-v1.xml` | Greenfield's custom extension (MIT) |
| `greenfield/libs/common/src/Connection.ts` | Wire format codec (REUSED) |
| `greenfield/libs/compositor-protocol/src/` | Server-side runtime + generated bindings (REUSED) |
| `greenfield/libs/client-protocol/src/` | Client-side runtime + generated bindings (REUSED) |
| `greenfield/libs/compositor-wasm/src/` | pixman + xkbcommon WASM (REUSED) |
| `greenfield/libs/xtsb/` | X11 TypeScript bindings (REUSED, only if XWayland) |
| `greenfield/libs/client-generator/` | Browser client bindings generator (REUSED) |
| `greenfield/libs/compositor-generator/` | Browser server bindings generator (REUSED) |
| `greenfield/packages/compositor-proxy/native/wayland/src/westfield-buffer.c` | Buffer helpers (REUSED, MIT) |
| `greenfield/packages/compositor-proxy/native/wayland/src/westfield-dmabuf.c` | DMA-BUF import (REUSED, MIT) |
| `greenfield/packages/compositor-proxy/native/wayland/src/westfield-egl.c` | EGL zero-copy setup (REUSED, MIT) |
| `greenfield/packages/compositor-proxy/native/wayland/src/westfield-xwayland.c` | XWayland bridge (REUSED as reference, ported to Python) |
| `greenfield/packages/compositor-proxy/native/wayland/src/wlr_drm.c` | `wl_drm` global impl (REUSED, MIT, vendored from wlroots) |
| `greenfield/packages/compositor-proxy/native/wayland/src/wlr_linux_dmabuf_v1.c` | `zwp_linux_dmabuf_v1` global impl (REUSED, MIT, vendored from wlroots) |
| `greenfield/packages/compositor-proxy/native/wayland/src/drm_format_set.c` | DRM format helpers (REUSED, MIT, vendored from wlroots) |
| `greenfield/packages/compositor-proxy/native/wayland/src/wayland-server/changes.diff` | Patches to libwayland-server (REUSED, MIT, optional for fast-sync) |
### Odoo 20 backend addon
| Path | Role |
|---|---|
| `compositor_shell/__manifest__.py` | Addon manifest |
| `compositor_shell/models/compositor_app.py` | App catalog model |
| `compositor_shell/models/compositor_session.py` | Session model (mail.thread) |
| `compositor_shell/models/compositor_audit_log.py` | Append-only audit log |
| `compositor_shell/controllers/main.py` | HTTP controllers (token, apps, launch, audit) |
| `compositor_shell/security/compositor_security.xml` | Groups + rules |
| `compositor_shell/security/ir.model.access.csv` | ACLs |
| `compositor_shell/views/compositor_app_views.xml` | App management views |
| `compositor_shell/views/compositor_session_views.xml` | Session views |
| `compositor_shell/views/ir_actions_client_views.xml` | OWL action registration |
| `compositor_shell/static/src/components/compositor_shell.js` | OWL shell component |
| `compositor_shell/static/src/components/compositor_shell.xml` | OWL template |
| `compositor_shell/static/src/components/compositor_shell.scss` | Styles |
| `compositor_shell/static/src/lib/compositor_lib/` | Custom browser compositor library (clean-room TS) |
## External references
### Wayland protocol
- **Wayland documentation**: https://wayland.freedesktop.org/docs/html/
- **Wayland protocol XML**: https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/protocol/wayland.xml
- **xdg-shell protocol**: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/stable/xdg-shell/xdg-shell.xml
- **wayland-drm protocol**: https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/protocol/wayland.xml
- **linux-dmabuf-unstable-v1**: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
### libwayland + pywayland
- **libwayland source**: https://gitlab.freedesktop.org/wayland/wayland
- **Wayland book**: https://wayland-book.com/
- **pywayland docs**: https://pywayland.readthedocs.io/
- **pywayland source**: https://github.com/flacjacket/pywayland
- **pywayland on PyPI**: https://pypi.org/project/pywayland/
### wlroots + pywlroots
- **wlroots source**: https://gitlab.freedesktop.org/wlroots/wlroots
- **wlroots mirror**: https://github.com/swaywm/wlroots
- **pywlroots source**: https://github.com/flacjacket/pywlroots
- **Smithay (Rust alternative)**: https://github.com/Smithay/smithay
### xkbcommon + python-xkbcommon
- **xkbcommon homepage**: https://xkbcommon.org/
- **xkbcommon source**: https://github.com/xkbcommon/libxkbcommon
- **xkbcommon on PyPI**: https://pypi.org/project/xkbcommon/
### GStreamer + PyGObject
- **GStreamer homepage**: https://gstreamer.freedesktop.org/
- **GStreamer Python bindings (gst-python)**: https://github.com/GStreamer/gst-python
- **PyGObject docs**: https://pygobject.readthedocs.io/
- **GStreamer tutorials**: https://gstreamer.freedesktop.org/documentation/tutorials/index.html
- **GStreamer GL plugins**: https://gstreamer.freedesktop.org/documentation/opengl/index.html
- **vaapih264enc docs**: https://gstreamer.freedesktop.org/documentation/vaapi/index.html
- **nvh264enc docs**: https://gstreamer.freedesktop.org/documentation/nvcodec/index.html
- **openh264enc docs**: https://gstreamer.freedesktop.org/documentation/openh264/index.html
### OpenH264 (BSD fallback decoder)
- **OpenH264 source**: https://github.com/cisco/openh264
- **Cisco binary releases**: https://github.com/cisco/openh264/releases
### WebCodecs + WebGL2 + OffscreenCanvas
- **WebCodecs API (MDN)**: https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API
- **VideoDecoder (MDN)**: https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder
- **WebGL2 (MDN)**: https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext
- **OffscreenCanvas (MDN)**: https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
- **Web Workers (MDN)**: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
- **SharedArrayBuffer (MDN)**: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer
- **WebTransport (MDN)**: https://developer.mozilla.org/en-US/docs/Web/API/WebTransport
- **WebCodecs samples**: https://w3c.github.io/webcodecs/samples/
### KCP
- **KCP protocol (skywind3000)**: https://github.com/skywind3000/kcp
- **KCP documentation**: https://skywind3000.github.io/kcp/
- **kcp on PyPI (RealistikDash)**: https://pypi.org/project/kcp/
### asyncio + aiohttp
- **asyncio docs**: https://docs.python.org/3/library/asyncio.html
- **aiohttp docs**: https://docs.aiohttp.org/
- **aiohttp WebSocket**: https://docs.aiohttp.org/en/stable/web_advanced.html#websockets
### JWT
- **PyJWT docs**: https://pyjwt.readthedocs.io/
- **JWT.io**: https://jwt.io/
- **RFC 7519 (JWT)**: https://datatracker.ietf.org/doc/html/rfc7519
### Sandboxing
- **bubblewrap docs**: https://github.com/containers/bubblewrap
- **libseccomp**: https://github.com/seccomp/libseccomp
- **Flatpak sandboxing**: https://docs.flatpak.org/en/latest/sandbox-permissions.html
- **cgroups v2**: https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
- **systemd-run**: https://www.freedesktop.org/software/systemd/man/systemd-run.html
### Odoo 20
- **Odoo 20 documentation**: https://www.odoo.com/documentation/20.0/
- **Odoo OWL framework**: https://github.com/odoo/owl
- **Odoo OWL migration guide (Odoo 19→20)**: https://www.odoo.com/documentation/20.0/developer/howtos/owl_migration.html
- **Odoo controller patterns**: https://www.odoo.com/documentation/20.0/developer/howtos/routing.html
- **Odoo security**: https://www.odoo.com/documentation/20.0/developer/howtos/security.html
### Greenfield (for reference, NOT for clean-room implementers)
- **Greenfield homepage**: https://www.greenfield.app
- **Greenfield source**: https://github.com/udevbe/greenfield
- **Greenfield design docs**: https://github.com/udevbe/greenfield/blob/master/docs/pages/design/index.md
- **Greenfield MIT libs (REUSABLE)**: https://github.com/udevbe/greenfield/tree/master/libs
- **Greenfield AGPL packages (DO NOT READ for clean-room)**: https://github.com/udevbe/greenfield/tree/master/packages
### Westfield (Greenfield's predecessor, MIT)
- **Westfield source**: https://github.com/udevbe/westfield
- **Note**: Contains ONLY the protocol infrastructure (same as Greenfield's MIT libs). NEVER had the in-browser compositor logic.
### Reference Wayland compositors (MIT, for clean-room spec authors)
- **wlroots (C, MIT)**: https://gitlab.freedesktop.org/wlroots/wlroots — reference for compositor patterns
- **Weston (C, MIT)**: https://gitlab.freedesktop.org/wayland/weston — reference Wayland compositor
- **Smithay (Rust, MIT)**: https://github.com/Smithay/smithay — Rust compositor library
- **wprs (Rust, MIT)**: https://github.com/Smithay/wprs — Rust wayland-xpra, mirrors Greenfield's architecture almost exactly
## Pointers to the user's next steps
1. **Read the comparison document**: `../Greenfield-vs-MIT-Comparison.md`
for the head-to-head analysis and final recommendation.
2. **If you choose the MIT approach** (recommended):
- Phase 0: Spike (1 week) — validate libwayland ↔ asyncio integration
- Phase 1: Browser compositor MVP (25 weeks, clean-room TS)
- Phase 2: Python proxy MVP (3.5 weeks, aiohttp + pywayland + GStreamer)
- Phase 3: Odoo integration (3.5 weeks, OWL shell + backend addon + JWT)
- Phase 4: Sandboxing v1 (1.5 weeks, bubblewrap + seccomp)
- Phase 5: Polish & testing (3 weeks)
3. **Critical first step**: Set up the clean-room process.
- Designate Person A (spec author) and Person B (implementer)
- Person A reads Greenfield AGPL source + writes `SPEC.md`
- Person B implements from `SPEC.md` + MIT references only
- Maintain `CLEAN_ROOM_LOG.md` as a legal-defensibility artifact
4. **CI/CD license hygiene gates**: Add the 4 license checks to your CI
pipeline from day one. See `11-pitfalls.md` for the commands.
5. **Engage legal counsel** before starting the clean-room process. This
bundle is engineering analysis, not legal advice.