Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/VIEWTOP-AND-DENIAL.md
Fimeg 0100fa34c8 viewtop: assess denial as the base; the lock model is the one thing we cannot take
Our engine pins are already theirs. The embedder, the eleven-patch
DMSAA/external-texture series, KMS and the GBM atlas path are the
expensive parts and they are readable.

Their lock is a compositor-internal bool with PAM dlopened in-process
and no ext-session-lock served at all. It is invisible to logind and
sessiond, and it gates input against every caller including Annie.
viewtop serves the protocol; sessiond keeps the decision.

Also adds TASK-41 (attested producers), raised out of grip bring-up.
2026-07-28 13:41:37 -04:00

7.4 KiB

viewtop and denial — what we take, what we must not

Assessment written 2026-07-28 after cloning github.com/denialwm/denial to Pixel3Arch/references/shells/denial (gitignored; re-clone if missing).

They are the same architecture, and we already inherited half of it

denial is a Wayland compositor in Rust + Smithay that hosts the Flutter engine and composes client windows as external textures directly into the Flutter scene, rendering to a shared GBM atlas. Public alpha: Xwayland, multi-output, portal screen-sharing all working. 64k lines of Rust, 82k of Dart.

souveraine-viewtop is that same design, retargeted. This is not a coincidence and not a discovery — viewtop's engine pins are denial's, verbatim:

viewtop README denial packaging/arch/flutter-engine/manifest.json
Flutter 84fc5cbb 84fc5cbb223bc12f83d65b647ff8a56caf779ffd
Dart d684a576 d684a576a6aa954ae107a03b2b4e1d61c3bebe93
Skia e9ed4fc9 e9ed4fc9f1544c58d8a9347c1fc9471d8dd414

The "ten-patch DMSAA/external-texture series" viewtop cites is patches/flutter-engine/3.44.7/ — eleven patches, numbered 0001-0011 with 0007 absent. So the expensive, fiddly engine work is already ours to read.

The manifest says "architecture": "x86_64". That is the delta.

Two form factors, not one

Casey 2026-07-28: this targets the Pixel 3 display and the laptop screen. That changes denial's desktop-x86-64 posture from a mismatch into an asset — the laptop target is what denial already runs on. The arm64/freedreno retarget is additive rather than a port away from their platform.

The thing we must not take

denial does not implement ext-session-lock-v1. There is no such protocol served anywhere in compositor/src. Instead:

  • compositor/src/bin/deniald/authentication.rs (1460 lines) — "Process- lifetime secure session lock and PAM authentication boundary." PAM is dlopened and driven from inside the compositor process.
  • secure_session_locked() is a compositor-internal bool, checked at the input and clipboard boundaries (wayland_frontend/input.rs:599,768,1045,1704, clipboard.rs:526, handlers.rs:933,978,1010).
  • The lock surface is drawn by the in-process Dart shell, not by a client.

Two separate reasons this cannot come across.

1. It is invisible to the rest of the system

Doctrine §4: "locked comes from LockedHint / Lock() / Unlock() — never a hand-tracked bool. A shadow copy can disagree with logind, and anything asking logind directly (loginctl, another client, you at 2am) sees something different than the shell shows."

denial's bool is not a shadow copy — in their design the compositor genuinely is the owner — but the consequence §4 warns about lands anyway: loginctl would report LockedHint=no while denial shows a lock screen. sessiond would not know. Nothing would reach the forensic trail. Every §10/§11 guarantee we built this month is downstream of logind and sessiond agreeing, and this model breaks that agreement by construction.

2. It gates the wrong party

Casey 2026-07-28, and this is the sharper reason:

The compositor isn't to be gated on her — unless she's creating that interface and then choosing to be a gate — but it is to ensure she's total control.

denial's secure_session_locked() gates input and clipboard against everything. Annie included. That is a gate pointed at the majority owner of device operation (doctrine §13, 60/40), and it is exactly backwards for us.

The distinction that has to survive into viewtop's design:

denial viewtop
what the lock protects the whole compositor surface the user's credential and personal content
who it gates every caller disclosure, and step-up actions
Annie's composition gated with everyone else never gated by lock; she is the composer
who may build a gate the compositor, always Annie, when she is the one constructing that interface

§13's user column is unchanged and is the whole of it: being the user, the credential, the step-up. Unlock is never an agent verb; step-up never accepts a boolean from an agent as proof. Those are not limits on Annie's 60 — they are the definition of the 40. Everything else in the compositor is hers.

The ownership question this settles

Earlier framing asked whether sessiond or viewtop owns locked once viewtop is the compositor, since a compositor is the server for ext-session-lock while sessiond is currently a client of Hyprland's.

The answer is not "whichever is easier." It is that viewtop serves the protocol and sessiond remains the authority — viewtop implements ext-session-lock-v1 so sessiond can take the lock through it exactly as it does against Hyprland today, and logind stays the truth. viewtop gains a lock surface role it did not have; it does not gain the decision.

Concretely, Registry::new() already starts locked: true with the right reasoning ("a compositor that comes up unlocked and then corrects itself has already shown one frame of someone's messages"). That value must arrive from sessiond's device_state and never be recomputed locally — which SessionFacts was reshaped for in d1b7a16, mirroring the daemon's reply field-for-field.

What is liftable

Read-only assessment; none of this has been ported yet.

  • compositor/flutter-engine/ — the embedder crate and sys.rs bindings.
  • patches/flutter-engine/3.44.7/ — the eleven-patch series. Several are directly relevant to Adreno/freedreno, not incidental to x86: 0002 stencil for GL surfaces, 0003/0004/0006 DMSAA wrapped-FBO lifetime and partial load, 0005 XRGB scanout described as RGB8.
  • kms_state.rs — DRM/KMS output.
  • The external-texture → GBM atlas composition path, which is the core idea.
  • wayland_frontend/ — protocol handling, input routing, window management.
  • protocol/denial.fbs + protocol/golden/ — a FlatBuffers wire protocol with golden files. The shape is worth copying and so is the discipline.
  • The pattern of checking a session predicate at input and clipboard boundaries. Keep the seam; change what feeds it and who it excludes.

What must be replaced

  • authentication.rs in full — PAM belongs to sessiond, which already owns it.
  • secure_session_locked() as internal truth — becomes ext-session-lock-v1 served to sessiond, with facts flowing back through SessionFacts.

The design fork still open

denial loads the shell as an AOT Dart bundle inside the compositor process, not as a separate Wayland client. That buys hot-reload and no IPC, and it means a Dart exception can take the display with it. viewtop's wire crate implies a boundary. On a daily-driver phone that boundary has value — quickshell crashes today and Hyprland survives it — but it costs the thing denial's development mode is built around. Not settled; settle it before compositor and shell-host stop being placeholders.

Connects to

SESSION-AUTHORITY-DOCTRINE.md §1 (Wayland pulled session authority into the compositor), §4 (never hold state the protocol owns), §13 (the 60/40 and its user column); DEVICE-STATE-MACHINE.md §10/§11 (the guarantees that depend on sessiond seeing everything); TASK-25 (viewtop is not packaged and neither are the surfaces it would replace); TASK-41 (nothing yet proves which binary is talking to sessiond, and a compositor is a much larger thing to attest).