mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
docs(b2-7): plugin boundary — off twice, compiled out of releases, no API promise
docs/architecture/plugins.md records the experimental WASM boundary (BPR-080/ 081, BG-17): disabled by build tag and by config, absent from release.yml and Dockerfile builds, the HP-2 configuration audit (fresh, upgraded, Docker, standalone), the beta release-notes wording, what exists today with its limits and tests, the post-beta plugin candidates that stay in core during beta, and the core concerns that never move. Linked from architecture/README.md, architecture/server.md and docs/README.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rg9QQWVN3E5UUgBD2dydtu
This commit is contained in:
@@ -60,6 +60,7 @@ and a PR touching those updates the blueprint in the same change.
|
||||
- [data-model.md](architecture/data-model.md), [websocket.md](architecture/websocket.md), [voice-e2ee.md](architecture/voice-e2ee.md)
|
||||
- [ux/](architecture/ux/README.md) — target-state UX spec, per-view states and event→reaction maps
|
||||
- [platform-contracts.md](architecture/platform-contracts.md) — target-state desktop/browser seam: what has to move behind a contract before the client can run in a browser (B7)
|
||||
- [plugins.md](architecture/plugins.md) — the experimental WASM plugin boundary: off by default, compiled out of releases, no API promise, what may become a plugin after beta and what never moves
|
||||
|
||||
[client-architecture.md](client-architecture.md) is a redirect stub; the live
|
||||
document is [architecture/client.md](architecture/client.md).
|
||||
|
||||
+11
-10
@@ -11,16 +11,17 @@ natively) followed by a prose explanation and a **Source of truth** file list.
|
||||
|
||||
## Index
|
||||
|
||||
| Doc | Diagrams | Covers |
|
||||
| ---------------------------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [system-overview.md](system-overview.md) | D1 System context, D8 Deployment topology | All processes, trust boundaries, ports, single-instance constraints |
|
||||
| [server.md](server.md) | D2 Server package map, D3 REST request lifecycle | Go package structure, DB-access styles, middleware chain |
|
||||
| [websocket.md](websocket.md) | D4 WS connect / replay / dispatch | Real-time engine: auth handshake, 3-tier reconnect replay, backpressure, typed dispatch |
|
||||
| [data-model.md](data-model.md) | D5 Entity-relationship overview | All 26 tables from migrations 001–028, grouped by domain |
|
||||
| [voice-e2ee.md](voice-e2ee.md) | D6 Voice + E2EE flow | LiveKit token flow, loopback TLS tunnel, ECDH key-holder relay |
|
||||
| [client.md](client.md) | D7 Client module map | Tauri client: bootstrap, dispatcher, stores, Rust sidecars (structure, as-built) |
|
||||
| [ux/](ux/README.md) | UX flow + state diagrams | Client **behavior** spec (target state): what every view does and how it reacts to events, permissions, and failure |
|
||||
| [platform-contracts.md](platform-contracts.md) | — | Desktop/browser **seam** (target state): where native dependencies will be isolated, and the three that have no browser equivalent |
|
||||
| Doc | Diagrams | Covers |
|
||||
| ---------------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [system-overview.md](system-overview.md) | D1 System context, D8 Deployment topology | All processes, trust boundaries, ports, single-instance constraints |
|
||||
| [server.md](server.md) | D2 Server package map, D3 REST request lifecycle | Go package structure, DB-access styles, middleware chain |
|
||||
| [websocket.md](websocket.md) | D4 WS connect / replay / dispatch | Real-time engine: auth handshake, 3-tier reconnect replay, backpressure, typed dispatch |
|
||||
| [data-model.md](data-model.md) | D5 Entity-relationship overview | All 26 tables from migrations 001–028, grouped by domain |
|
||||
| [voice-e2ee.md](voice-e2ee.md) | D6 Voice + E2EE flow | LiveKit token flow, loopback TLS tunnel, ECDH key-holder relay |
|
||||
| [client.md](client.md) | D7 Client module map | Tauri client: bootstrap, dispatcher, stores, Rust sidecars (structure, as-built) |
|
||||
| [ux/](ux/README.md) | UX flow + state diagrams | Client **behavior** spec (target state): what every view does and how it reacts to events, permissions, and failure |
|
||||
| [platform-contracts.md](platform-contracts.md) | — | Desktop/browser **seam** (target state): where native dependencies will be isolated, and the three that have no browser equivalent |
|
||||
| [plugins.md](plugins.md) | — | Experimental WASM plugin boundary: off twice and compiled out of releases, no API promise, post-beta candidates, core that never moves |
|
||||
|
||||
### Structure vs. behavior
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# Plugins — the experimental boundary
|
||||
|
||||
**Kind:** reference + boundary record. **Verified against:** `dev` @
|
||||
`2b2d58ab`, 2026-08-29. **Satisfies:** BPR-080, BPR-081, BG-17; feeds HP-2
|
||||
question 6.
|
||||
|
||||
OwnCord has a WASM plugin runtime. It is **experimental, off by default, and
|
||||
absent from every shipped artifact**. This document says exactly what exists,
|
||||
what it may not be relied on for, what could become a plugin after beta, and
|
||||
what never will.
|
||||
|
||||
## Status: off, twice — and not in the release at all
|
||||
|
||||
| Layer | Fact | Anchor |
|
||||
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| Build tag | WASM execution compiles only under `-tags wazero`. The default build discovers and lists manifests but **never executes a module** | `Server/plugin/sandbox_default.go:1-5` (`//go:build !wazero`); `sandbox_wazero.go` is the tagged twin |
|
||||
| Config | `plugins.enabled` defaults to `false`; the example config block is commented out and says "Disabled by default so existing operators are unaffected" | `Server/config/config.go:352`; `:449-457` |
|
||||
| Startup | The registry is only built when the flag is on; otherwise the plugin admin handler gets `nil`, lifecycle calls answer 503 and the list is empty | `Server/main.go:394`; `Server/api/router.go:35-37`, `:184` |
|
||||
| Release builds | `release.yml` builds `chatserver.exe` / `chatserver` with a plain `go build` — no `wazero` tag. The Docker image does the same. **No shipped binary can run a plugin.** | `.github/workflows/release.yml:261`, `:268`; `Server/Dockerfile:13` |
|
||||
| CI | The `wazero` variants are compiled on every PR so they cannot rot, but their tests run only under the tag | `.github/workflows/ci.yml:52-55`, `:79` |
|
||||
|
||||
Configuration audit for HP-2 question 6 — is WASM off in every shape a server
|
||||
can take?
|
||||
|
||||
| Shape | Verdict | Why |
|
||||
| -------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Fresh install | off | default `false` (`config.go:352`); the generated `config.yaml` has the block commented out (`:452-457`) |
|
||||
| Upgraded install | off | an older `config.yaml` has no `plugins` key; koanf loads defaults first, so the absent key reads as `false`. Unknown keys are rejected, not silently ignored (`Server/config/unknown_keys_test.go`) |
|
||||
| Docker | off | image built without the tag (`Dockerfile:13`); `OWNCORD_PLUGINS_ENABLED=true` (`config.go:525-526` env provider) would flip the flag but the binary still cannot execute a module |
|
||||
| Standalone release binary | off | same — no tag (`release.yml:261`, `:268`) |
|
||||
| Source build with the flag | **on** | only `go build -tags wazero` **and** `plugins.enabled: true` together run WASM. This is the developer path and the only one |
|
||||
|
||||
## No API promise
|
||||
|
||||
The plugin ABI — the five guest exports (`command_dispatch`, `allocate`,
|
||||
`deallocate`, `list_commands`, and the manifest contract) — **may change or be
|
||||
removed in any release without a deprecation period**
|
||||
(`Server/plugin/examples/hello/README.md:6-10`). There are no supported
|
||||
plugins, so there is nothing to keep compatible with. The example under
|
||||
`Server/plugin/examples/hello/` is a reference for the ABI as it stands, not a
|
||||
promise about the ABI to come; its prebuilt `.wasm` is not tracked
|
||||
(`.gitignore:59`) and is not byte-reproducible (TinyGo embeds host paths —
|
||||
`hello/README.md:70-74`).
|
||||
|
||||
**Release-notes wording for beta.** Use this text, unchanged, in the beta
|
||||
release notes and anywhere plugins are mentioned to operators:
|
||||
|
||||
> Plugins are experimental. The WASM runtime is compiled out of release
|
||||
> binaries and disabled by default in source builds. The plugin API carries no
|
||||
> compatibility promise and may change or be removed without notice. Do not
|
||||
> build on it for production use.
|
||||
|
||||
## What exists today (for the record)
|
||||
|
||||
Enough to know what "experimental" is guarding. All paths under `Server/plugin/`.
|
||||
|
||||
| Aspect | State | Anchor |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Runtime | wazero, one module instance per plugin, closed on context done | `sandbox_wazero.go:102-103` |
|
||||
| Manifest | JSON `plugin.json`; TOML `plugin.toml` only under the tag and preferred when both exist. Entrypoint must be a relative `.wasm` path. A zip with both is rejected as ambiguous (OC-0318) | `manifest.go:52-61`, `:115`, `:144-148`; `manifest_toml.go:1-5`; `loader.go:39`; test `registry_test.go:696-700` |
|
||||
| Capabilities | closed set `commands`, `events`, `storage`, `http`, `ui`; anything else fails load | `manifest.go:97-112`, `:151` |
|
||||
| Memory | per-plugin linear-memory cap from manifest or `plugins.max_memory_mb` (default 64 MiB), clamped to the wazero page limit | `sandbox_wazero.go:84-97`, `:102`; `config.go:126`, `:354` |
|
||||
| CPU | a wall-clock deadline per invocation — manifest, then `plugins.cpu_budget_ms`, then a hard 100 ms floor. Not fuel-based: a runaway loop is killed by closing the module | `sandbox_wazero.go:300-325`; `config.go:128`, `:355`; TOML resource keys decode (OC-0338) — test `manifest_test.go:149-155` |
|
||||
| HTTP | only hosts on `plugins.http_allowlist` (empty by default), 10 s timeout, body cap, at most 5 redirects re-validated, through the guarded dialer that refuses private, loopback, link-local and CGN answers | `host_http.go:39`, `:66`, `:87-102`, `:112`, `:136-155`, `:182-249`; tests `TestGuardedDial_*` |
|
||||
| Storage | a per-plugin key/value namespace, scan size clamped; no other table is reachable | `pluginstore.go:12-24`; `host_storage.go:27-66` |
|
||||
| Filesystem | none — no WASI preview-1 filesystem is mounted | `sandbox_wazero.go:77-78` |
|
||||
| Host imports | **none are wired into the runtime yet.** The `http`, `storage`, `events` and `ui` APIs exist on the Go side of the registry; a guest module today can only receive `command_dispatch` | `sandbox_wazero.go:311-316` |
|
||||
| Admin surface | `GET /`, `POST /install` (zip), `POST /{id}/enable`, `POST /{id}/disable`, `DELETE /{id}` under `/api/v1/admin/plugins`, behind the admin IP allowlist **and** an admin session — a LAN peer on the allowed CIDR cannot install without one. Install and uninstall are audited | `Server/api/plugins_handler.go:43-47`; `Server/api/router.go:171-186`; test `TestAuditCoverage_PluginLifecycle` |
|
||||
| Client | no plugin UI exists in the desktop client | `grep -rn plugin Client/src` hits only `@tauri-apps/plugin-*` imports |
|
||||
|
||||
## Could become a plugin after beta (BPR-081)
|
||||
|
||||
Cohesive features and provider integrations that are natural plugin shapes.
|
||||
**During beta they stay where they are**, in core, behind the same tests — the
|
||||
audit names them so the boundary is a decision, not drift. Nothing on this list
|
||||
moves behind the experimental runtime before a supported plugin API exists.
|
||||
|
||||
| Candidate | Lives today | Why it is a candidate |
|
||||
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
||||
| GIF provider (Klipy) | `Server/api/gif_handler.go` (server proxy, `gif.api_key`) | one vendor behind one endpoint; swapping vendors should not touch core |
|
||||
| Link-preview and embed providers (YouTube oEmbed, OG) | `Client/src/components/message-list/media.ts`, `embeds.ts` (moves behind the B7 native broker first — C-09) | provider-shaped; the destination policy stays core |
|
||||
| Slash commands and automation | the `plugin_command` protocol family already exists (`protocol/schema.json`) | the one thing the runtime can dispatch today |
|
||||
| Webhooks (inbound and outbound) | not implemented | classic integration seam |
|
||||
| Optional moderation automation | not implemented; human moderation in `Server/service/moderation.go` | may _suggest_; **human authority and the moderation audit trail stay core** |
|
||||
| UI tabs / panels | `ui` capability reserved (`host_ui.go`), no client side | display-only extension point |
|
||||
| Import/export bridges (other chat platforms) | not implemented | one-shot data movers with no security surface of their own |
|
||||
| Observability exporters | `Server/telemetry/` (OTel, `-tags otel`, exporter `none` by default) | already a build-tagged optional edge |
|
||||
|
||||
## Core that never moves
|
||||
|
||||
These stay in the server and client proper, permanently, whatever the plugin
|
||||
system becomes. A plugin may _call_ some of them; none may _replace_ or
|
||||
_bypass_ them.
|
||||
|
||||
| Concern | Owner |
|
||||
| ----------------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| Authentication, sessions, 2FA | `Server/auth/`, `Server/api/auth_handler.go` |
|
||||
| Authorization | `Server/permissions/` (one predicate per property — B2-5) |
|
||||
| TLS and certificate pinning | `Server/auth/tls.go`; `Client/src-tauri/src/tofu.rs` |
|
||||
| Safe outbound fetch | `Server/plugin/host_http.go` guarded dialer; the B7 native broker (C-09) |
|
||||
| Quotas and rate limits | `Server/auth/ratelimit*.go`, per-action limits in `Server/service/` |
|
||||
| Voice/video E2EE | `Client/src/lib/e2eeCrypto.ts`, `livekitE2EE.ts`, `identity.ts`; `Server/ws/voice_e2ee.go` |
|
||||
| Updates and signatures | `Server/updater/`, `Server/api/client_update.go` |
|
||||
| Deletion and account removal | `Server/db/account.go` |
|
||||
| Backup and recovery | `Server/admin/handlers_backup.go`, `Server/db/admin_queries.go` |
|
||||
| Moderation audit | `Server/db/audit*.go`, `Server/db/audittest/`, `TestAuditCoverage_*` |
|
||||
|
||||
The trust statements these back are in [../trust-model.md](../trust-model.md).
|
||||
|
||||
## Maintenance
|
||||
|
||||
**Source of truth:** `Server/plugin/`, `Server/config/config.go` (`PluginsConfig`
|
||||
and its defaults), `Server/main.go` (registry construction),
|
||||
`.github/workflows/release.yml` and `Server/Dockerfile` (build flags),
|
||||
`Server/plugin/examples/hello/README.md` (ABI and toolchain). A change to any of
|
||||
those that alters a row above updates this document in the same PR. The
|
||||
release-notes paragraph is quoted verbatim by the beta release; change it here
|
||||
first.
|
||||
@@ -85,6 +85,10 @@ spawns background goroutines; and mounts all routes. `main.go` performs only
|
||||
process-level wiring (config, TLS, DB, event persistence, HTTP server,
|
||||
shutdown).
|
||||
|
||||
The `plugin` package is experimental and compiled out of release binaries;
|
||||
[plugins.md](plugins.md) records that boundary — what exists, what carries no
|
||||
promise, and which core concerns will never move behind it.
|
||||
|
||||
**Source of truth:** `Server/main.go`, `Server/api/router.go`, package import
|
||||
graph (`go list -deps`), `Server/service/datastore.go`, `sqlc.yaml`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user