SouveraineOS umbrella: docs, dumps, handoffs, cross-repo STATE
This commit is contained in:
commit
dc4fd14bbd
13 changed files with 2360 additions and 0 deletions
182
docs/INTERFACE-ARCHITECTURE.md
Normal file
182
docs/INTERFACE-ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
# Phone shell — interface architecture
|
||||
|
||||
The phone has four primary interfaces the user actually touches: the **pill**,
|
||||
the **dock**, the **keyboard**, and **touch/gesture**. This doc names what each
|
||||
one is *meant to be*, what it is *today*, and the single seam where a hardcode
|
||||
should become a small framework so the surface can grow without rewrites.
|
||||
|
||||
Principle: **clean beats feature-rich.** Each surface has one job and one place
|
||||
its behaviour is tuned. A new feature should be a new entry in an existing
|
||||
table, not a new hardcoded branch. Where a value is tuned in more than one
|
||||
place today, that is the bug — not the value.
|
||||
|
||||
Truth hierarchy: this doc describes intent; `HOW-IT-WORKS.md` describes the
|
||||
current wiring; the code is the reality. When they disagree, fix the code or
|
||||
fix the doc in the same change — never leave a third story.
|
||||
|
||||
---
|
||||
|
||||
## 1. Pill — the always-on gesture bar
|
||||
|
||||
**Meant to be:** the one surface that is *always* reachable, on any app, in any
|
||||
state. A thin, dumb input strip at the bottom edge that recognises a small
|
||||
fixed vocabulary of gestures and forwards them — it owns no app state and makes
|
||||
no decisions beyond "which gesture was this."
|
||||
|
||||
**Today (`pill/shell.qml`):** `WlrLayer.Overlay`, `ExclusionMode.Ignore`,
|
||||
`margins.bottom:0`. Gesture arbitration is one MouseArea (double-tap, swipe up,
|
||||
swipe down) → `dock` IPC. This part is clean and well-reasoned.
|
||||
|
||||
**The seam / the bug:** the pill's z-order guarantee is *documented but not
|
||||
enforced*. `pill/shell.qml:23-27` sets namespace `quickshell:pill` and points
|
||||
at "the `order` layerrule in hyprland.lua" — **that layerrule does not exist**
|
||||
(hyprland.lua only has a commented-out generic `^my-overlay$` example). So
|
||||
after an `ii` restart the pill can be buried under the dock and stop taking
|
||||
touch — the exact failure the comment says is solved. Fix: add the real
|
||||
`order` layerrule for `quickshell:pill`, or drop the promise from the code and
|
||||
docs. Do not add more pill gestures until stacking is enforced — an always-on
|
||||
surface that silently dies is worse than a plain one.
|
||||
|
||||
**Growth rule:** new pill gestures are new cases in the one MouseArea, each
|
||||
forwarding to a *named* IPC target — never doing app logic inline.
|
||||
|
||||
---
|
||||
|
||||
## 2. Dock — the app switcher and stack surface
|
||||
|
||||
**Meant to be:** the surface that shows and switches running/pinned apps and
|
||||
lets the user group them into stacks. It owns app-presentation state; it does
|
||||
not own gesture recognition (the pill and hyprgrass feed it via IPC).
|
||||
|
||||
**Today:** interaction layer (`Dock.qml`, `DockAppButton.qml`, `DockStack.qml`)
|
||||
is strong — drag-to-combine, fan-out arc, visibility state machine
|
||||
(`computeDockState`). The weak layer is **state/config**:
|
||||
|
||||
- Stacks are a hand-parsed string `"stackId|appId,appId"` (`TaskbarApps.qml:25`).
|
||||
A `|` or `,` in a name corrupts it silently; parsed/encoded in ~6 places.
|
||||
→ move to **one JSON blob per entry** (array-of-strings the adapter tolerates,
|
||||
but each string is JSON): kills the delimiter-corruption class, keeps the
|
||||
adapter happy. This is the agreed direction.
|
||||
- Stack ids are count-based (`nextStackName` = `"Stack " + (count+1)`,
|
||||
`:87`) → collide after a delete, and `id` is the lookup key. Two stacks can
|
||||
share an id and cross-contaminate members. → stable uid, display name
|
||||
separate from id.
|
||||
- Combining into a new stack suppresses the target's standalone pin at *render*
|
||||
time (`apps` getter) but never removes it from `pinnedApps` in config
|
||||
(`:99-108`) → the pin lingers; unstack works by luck. → remove-on-combine so
|
||||
config matches what's shown.
|
||||
- Tap-cycle `lastFocused` index (`DockAppButton :196`) is never reconciled when
|
||||
windows open/close and is also written by hover (`:180`) → tapping can focus
|
||||
the wrong window. → clamp/reconcile against the live toplevel model.
|
||||
- Magic numbers live in the components: `pillStripHeight 32` (`Dock.qml:161`),
|
||||
dwell `500` (twice: `DockAppButton:133`, `DockStack:116`), double-tap `350`,
|
||||
arc geometry (`DockStack:33-36`). → lift into `Config.options.dock` next to
|
||||
the `height`/`monochromeIcons`/`hoverRegionHeight` that already live there.
|
||||
- `reorderStackMember` (`TaskbarApps:113`) is dead — superseded by
|
||||
`setStackOrder`. → remove, or wire the menu reorder it was meant for.
|
||||
|
||||
**The seam:** `Config.options.dock` already exists — the framework anchor is
|
||||
already there. "More structure" here means *finishing* that namespace (all
|
||||
tuning knobs + a real stack schema under it), not inventing a new one.
|
||||
|
||||
**Growth rule:** dock feel/config knobs go under `Config.options.dock`; stack
|
||||
members are structured entries, not delimited strings. Rename + ungroup are
|
||||
table-stakes and should exist before any fancier stack feature.
|
||||
|
||||
---
|
||||
|
||||
## 3. Keyboard (OSK) — squeekboard
|
||||
|
||||
**Meant to be:** an on-screen keyboard that appears on text focus and can be
|
||||
summoned by one deliberate gesture, driven through **one** IPC target so its
|
||||
visibility and any focus-grab shield always move together.
|
||||
|
||||
**Today:** squeekboard, launched from `hyprland.lua`, auto-shows via
|
||||
input-method-v2, toggled by 3-finger swipe-up routed through ii's `osk` IPC.
|
||||
The *routing* is right (single `osk` target).
|
||||
|
||||
**The seam / the drift:** the comments and the retained
|
||||
`quickshell-ii-patches/OnScreenKeyboard.qml` still describe **wvkbd**
|
||||
(retired 2026-07-10) and its focus-grab shield — the `osk` IPC now drives
|
||||
squeekboard, but the code comments and the history-only patch file still tell
|
||||
the wvkbd story. Same doc-vs-reality drift as the pill layerrule. → update the
|
||||
comments to squeekboard reality; confirm whether `OnScreenKeyboard.qml`'s
|
||||
GlobalStates.oskOpen plumbing is still the thing `osk toggle` hits, or vestigial.
|
||||
|
||||
**Growth rule:** one `osk` IPC target owns show/hide; layout/theme is
|
||||
squeekboard config, addressable later from souveraine-settings. No second path
|
||||
to toggle the keyboard.
|
||||
|
||||
---
|
||||
|
||||
## 4. Touch / gesture — the input spine
|
||||
|
||||
**Meant to be:** one routing layer that maps a physical touch gesture to a
|
||||
named interface action. Today this is the messiest surface because it is spread
|
||||
across four dispatch styles.
|
||||
|
||||
**Today (`hyprland.lua`):**
|
||||
- `hl.gesture{fingers=3,horizontal}` → workspace (Hyprland-native)
|
||||
- `hl.plugin.hyprgrass.bind{...}` → close / terminal / edge-swipes →
|
||||
`qs -c ii ipc call <target>`
|
||||
- the pill's own MouseArea → `dock` IPC
|
||||
- `touchdevice.output = "DSI-1"` binds touch to the panel for rotation
|
||||
|
||||
Two input sources (pill swipe-up, hyprgrass edge-swipe-up) both drive the dock;
|
||||
no single arbiter. Gesture → action bindings are inline `exec_cmd` strings
|
||||
scattered through the file.
|
||||
|
||||
**The seam:** this is the memory note "don't hardcode bindings blindly; need a
|
||||
routing system to avoid overlap." The clean form is **one gesture table** —
|
||||
edge/finger/direction → named IPC target — read top-to-bottom so overlaps are
|
||||
visible in one place. Every binding already ends in a `qs ... ipc call <target>`;
|
||||
the framework is just making that table explicit and single-sourced instead of
|
||||
sprinkled through `hyprland.lua`.
|
||||
|
||||
**Growth rule:** a new gesture is a new row in the gesture table pointing at a
|
||||
named IPC target. Two rows may not target the same action from different edges
|
||||
without being adjacent in the table (so overlap is obvious).
|
||||
|
||||
---
|
||||
|
||||
## Cross-cutting: the one recurring defect
|
||||
|
||||
Three of four surfaces have the **same** flaw — *a documented guarantee the
|
||||
code doesn't enforce*: the pill layerrule (doc says pinned, code doesn't pin),
|
||||
the keyboard (comments say wvkbd, code runs squeekboard), the dock stack pin
|
||||
(render says suppressed, config says still pinned). Cleaning these up is mostly
|
||||
making the code match its own stated contract, then giving each surface exactly
|
||||
one place it's tuned.
|
||||
|
||||
## Status (2026-07-13)
|
||||
|
||||
1. ~~Pill layerrule~~ DONE — `pill-above-dock` rule added to hyprland.lua
|
||||
(`order = 1` on `^quickshell:pill$`). VERIFY ON GLASS: `order`
|
||||
passthrough in the Lua layer_rule wrapper is untested on this build.
|
||||
2. ~~Gesture table~~ DONE — hyprgrass binds are one `touch_gestures` table
|
||||
in hyprland.lua; the two other gesture sources (hl.gesture workspace
|
||||
swipe, the pill's MouseArea) are listed in its header so overlap stays
|
||||
visible in one read.
|
||||
3. ~~Dock state layer~~ DONE — JSON-per-entry stacks (legacy pipe entries
|
||||
still parse, rewritten on next write), minted `stack-N` ids that never
|
||||
reuse after delete, name separate from id (+ `renameStack()`, no UI
|
||||
yet), pin actually removed from config on combine, tap-cycle starts
|
||||
from the truly focused window, dead `reorderStackMember` removed,
|
||||
`dragDwellMs`/`pillStripHeight` lifted into `Config.options.dock`.
|
||||
4. ~~Keyboard~~ DONE — hyprland.lua comments tell the squeekboard story;
|
||||
`OnScreenKeyboard.qml` (the "osk" IPC owner) moved into this surface +
|
||||
deploy manifest. Remaining hand-deployed patches (BarContent, Network,
|
||||
QuickSliders, switchwall.sh) noted in overlays/QUICKSHELL-MOVED.md.
|
||||
|
||||
## Open decision — two-stage swipe-up was removed, not lost by accident?
|
||||
|
||||
Souveraine commit `6e21c50` ("resume agent conversations from server")
|
||||
reworked the dock state machine: the Peek state, `dockRevealPulse`, and the
|
||||
two-stage swipeUp (reveal → escalate to overview) all went away in favor of
|
||||
a flat reveal/hide contract — under a commit title that says nothing about
|
||||
the dock. Pixel3Arch CLAUDE.md still records two-stage as SHIPPED
|
||||
(2026-07-11). The replacement comment is articulate, so this reads as a
|
||||
deliberate redesign, but it needs Casey's confirmation: keep the flat
|
||||
contract (overview = the dock's apps button), or restore the escalation.
|
||||
Comments in hyprland.lua/HOW-IT-WORKS now describe the flat behavior that
|
||||
actually runs.
|
||||
Loading…
Reference in a new issue